সঞ্চালনকারী নির্বাচিত হওয়ার কারণে একটি ফাঁস হতে পারে কারণ এর নির্বাচকটি অজানা


1258

আমি এআরসি সংকলক দ্বারা নিম্নলিখিত সতর্কতা পাচ্ছি:

"performSelector may cause a leak because its selector is unknown".

আমি যা করছি তা এখানে:

[_controller performSelector:NSSelectorFromString(@"someMethod")];

কেন আমি এই সতর্কতা পেতে পারি? আমি বুঝতে পারি যে সংকলক নির্বাচক উপস্থিত আছে কিনা তা পরীক্ষা করতে পারবেন না, তবে কেন এটি ফাঁস হওয়ার কারণ হবে? এবং আমি কীভাবে আমার কোডটি পরিবর্তন করতে পারি যাতে আমি এই সতর্কতাটি আর না পাই?


3
পরিবর্তনশীলটির নাম গতিশীল, এটি অন্যান্য অনেক কিছুর উপর নির্ভর করে। ঝুঁকি আছে যে আমি এমন কিছু কল করছি যা বিদ্যমান নেই, তবে সমস্যাটি নয়।
এডুয়ার্ডো স্কোজ

6
@ ম্যাট কেন কোনও বস্তুকে ডায়নামিকভাবে কোনও পদ্ধতি কল করা খারাপ অভ্যাস হবে? এই অনুশীলনকে সমর্থন করা কি এনএসএসইলেক্টরফ্রস্ট্রিং () এর পুরো উদ্দেশ্য নয়?
এডুয়ার্ডো স্কোজ

7
আপনার পারফরম্যান্স সিলেক্টরের মাধ্যমে সেট করার আগে আপনি [_ নিয়ন্ত্রক প্রতিক্রিয়াশীলতা: মাই সিলেক্টর] পরীক্ষা করে দেখতে পারেন:
ম্যাটাকুলার

50
@ ম্যাটাক্যাকুলার ইশ আমি ভোট দিতে পারলাম: "এটি ... খারাপ অভ্যাস।"
সিটিপেনরোজ

6
যদি আপনি জানেন যে স্ট্রিংটি আক্ষরিক, কেবল @ সিলেক্টর () ব্যবহার করুন যাতে সংকলক নির্বাচকের নাম কী তা বলতে পারে। যদি আপনার আসল কোডটি রান-টাইমে নির্মিত বা সরবরাহ করা একটি স্ট্রিং সহ এনএসএসইলেক্টর ফ্রমস্ট্রিং () কে কল করছে, তবে আপনাকে অবশ্যই এনএসএসইলেক্টর ফ্রমস্ট্রিং () ব্যবহার করতে হবে।
ক্রিস পৃষ্ঠা

উত্তর:


1211

সমাধান

সংকলক একটি কারণ সম্পর্কে এটি সম্পর্কে সতর্ক করে দিচ্ছে। এটি খুব বিরল যে এই সতর্কতাটি কেবল উপেক্ষা করা উচিত এবং এটির চারপাশে কাজ করা সহজ। এখানে কীভাবে:

if (!_controller) { return; }
SEL selector = NSSelectorFromString(@"someMethod");
IMP imp = [_controller methodForSelector:selector];
void (*func)(id, SEL) = (void *)imp;
func(_controller, selector);

বা আরও পরিশ্রুত (যদিও পড়তে এবং প্রহরী ব্যতীত কঠিন):

SEL selector = NSSelectorFromString(@"someMethod");
((void (*)(id, SEL))[_controller methodForSelector:selector])(_controller, selector);

ব্যাখ্যা

এখানে যা চলছে আপনি নিয়ন্ত্রকের সাথে অনুরোধ পদ্ধতিটির জন্য সি ফাংশন পয়েন্টারটির জন্য জিজ্ঞাসা করছেন। সমস্ত NSObjectসাড়া দেয় methodForSelector:, তবে আপনি class_getMethodImplementationঅবজেক্টিভ-সি রানটাইম ব্যবহার করতে পারেন (যদি আপনার কাছে কেবল প্রোটোকল রেফারেন্স থাকে তবে দরকারী id<SomeProto>)। এই ফাংশন পয়েন্টারগুলিকে IMPs বলা হয় এবং এগুলি সাধারণ typedefএড ফাংশন পয়েন্টার ( id (*IMP)(id, SEL, ...)) 1 । এটি পদ্ধতির আসল পদ্ধতিটির স্বাক্ষরের খুব কাছাকাছি হতে পারে তবে সর্বদা ঠিক মিলবে না।

একবার আপনার হয়ে গেলে IMP, আপনাকে এটি কোনও ফাংশন পয়েন্টারে কাস্ট করতে হবে যাতে এআরসি প্রয়োজনীয় সমস্ত বিবরণ (দুটি অন্তর্নিহিত গোপন তর্ক selfএবং _cmdপ্রতিটি উদ্দেশ্য-সি পদ্ধতি কল সহ) অন্তর্ভুক্ত করে। এটি তৃতীয় লাইনে হ্যান্ডেল করা হয়েছে ( (void *)ডানদিকে থাকাটি কম্পাইলারকে বলে দেয় যে আপনি কী করছেন এবং পয়েন্টারের ধরণগুলি মেলে না বলে একটি সতর্কতা উত্পন্ন না করার বিষয়টি আপনি জানেন)।

অবশেষে, আপনি ফাংশন পয়েন্টার 2 কল ।

জটিল উদাহরণ

যখন নির্বাচক আর্গুমেন্ট নেয় বা কোনও মান ফেরত দেয়, আপনাকে কিছুটা পরিবর্তন করতে হবে:

SEL selector = NSSelectorFromString(@"processRegion:ofView:");
IMP imp = [_controller methodForSelector:selector];
CGRect (*func)(id, SEL, CGRect, UIView *) = (void *)imp;
CGRect result = _controller ?
  func(_controller, selector, someRect, someView) : CGRectZero;

সতর্কতা জন্য যুক্তি

এই সতর্কতার কারণটি হ'ল এআরসি-র সাথে রানটাইমটি জানতে হবে যে আপনি যে পদ্ধতিতে কল করছেন তার ফলাফলটি কী করা উচিত। ফলাফলের কিছু হতে পারে: void, int, char, NSString *, id, ইত্যাদি এআরসি স্বাভাবিকভাবে অবজেক্ট প্রকারটি আপনার সাথে কাজ করছি হেডার থেকে এই তথ্য পায়। 3

সত্যিই কেবল 4 টি জিনিস রয়েছে যা প্রত্যাবর্তন মূল্যের জন্য এআরসি বিবেচনা করবে: 4

  1. Ignore অ বস্তুর প্রকার ( void, intইত্যাদি)
  2. অবজেক্টের মান ধরে রাখুন, তারপরে এটি আর ব্যবহার না করা হলে ছেড়ে দিন (স্ট্যান্ডার্ড অনুমান)
  3. আর ব্যবহার না করা হলে নতুন অবজেক্টের মানগুলি প্রকাশ করুন ( init/ copyপরিবারে পদ্ধতিগুলি বা এর সাথে যুক্ত ns_returns_retained)
  4. কিছুই করবেন না এবং ধরে নিন যে প্রত্যাবর্তিত অবজেক্টের মান স্থানীয় স্কোপে বৈধ হবে (যতক্ষণ না অভ্যন্তরীণ সর্বাধিক রিলিজ পুলটি শুকানো হয়, এর সাথে চিহ্নিত করা হয় ns_returns_autoreleased)

methodForSelector:ধরে নেওয়া কলটি যে পদ্ধতিটি কল করছে তার রিটার্ন মান একটি বস্তু, তবে এটি ধরে রাখে না / ছেড়ে দেয় না। সুতরাং আপনার অবজেক্ট উপরের # 3 হিসাবে মুক্তি পাওয়ার কথা মনে করা হলে আপনি একটি ফুটো তৈরি শেষ করতে পারেন (অর্থাৎ, আপনি যে পদ্ধতিটি কল করছেন সেটি কোনও নতুন অবজেক্ট ফিরিয়ে দেয়)।

আপনি যে রিটার্ন voidবা অন্যান্য অ-অবজেক্টগুলিকে কল করার চেষ্টা করছেন তাদের নির্বাচিতদের জন্য , আপনি সংকলক বৈশিষ্ট্যগুলি সতর্কতাটিকে উপেক্ষা করতে সক্ষম করতে পারেন তবে এটি বিপজ্জনক হতে পারে। আমি ক্ল্যাংকে স্থানীয় পুনরায় ভেরিয়েবলগুলিতে নির্ধারিত নয় এমন রিটার্ন মানগুলি কীভাবে পরিচালনা করে তার কয়েকটি পুনরাবৃত্তির মধ্য দিয়ে যেতে দেখেছি। এআরসি সক্ষম করে এমন কোনও কারণ নেই যে এটি ব্যবহার করতে না চাইলেও এটি থেকে ফিরে আসা অবজেক্টের মানটি ধরে রাখতে এবং ছেড়ে methodForSelector:দিতে পারে না। সংকলকের দৃষ্টিকোণ থেকে, এটি সর্বোপরি একটি অবজেক্ট। এর অর্থ এই যে আপনি যে পদ্ধতিটি কল করছেন someMethod, যদি কোনও নন অবজেক্ট (সহ void) ফিরিয়ে দেয় তবে আপনি কোনও আবর্জনা পয়েন্টার মান ধরে রাখতে / ছেড়ে দিতে এবং ক্র্যাশ করে শেষ করতে পারেন।

অতিরিক্ত যুক্তি

একটি বিবেচনা হ'ল এটি হ'ল একই সতর্কতাটি ঘটবে performSelector:withObject:এবং আপনি কীভাবে সেই পদ্ধতিটি পরামিতিগুলি ব্যয় করে তা ঘোষণা না করে একই ধরণের সমস্যার মধ্যে পড়তে পারেন। এআরসি গ্রাসকৃত প্যারামিটারগুলি ঘোষণা করার অনুমতি দেয় এবং যদি পদ্ধতিটি প্যারামিটার গ্রহণ করে তবে আপনি সম্ভবত শেষ পর্যন্ত একটি জম্বি এবং ক্র্যাশে একটি বার্তা প্রেরণ করবেন। ব্রিজযুক্ত ingালাই দিয়ে এটিকে ঘিরে কাজ করার উপায় রয়েছে তবে IMPউপরের ও ফাংশন পয়েন্টার পদ্ধতিটি কেবল উপরে ব্যবহার করা ভাল । যেহেতু গ্রাসকৃত প্যারামিটারগুলি খুব কমই একটি সমস্যা, এটি সম্ভবত আসার সম্ভাবনা নেই।

স্থির নির্বাচক

মজার বিষয় হল, সংকলক স্থিতিযুক্ত ঘোষিত নির্বাচকদের সম্পর্কে অভিযোগ করবে না:

[_controller performSelector:@selector(someMethod)];

এর কারণ হ'ল সংকলক আসলে সংকলনের সময় নির্বাচক এবং অবজেক্ট সম্পর্কে সমস্ত তথ্য রেকর্ড করতে সক্ষম। এটি কোনও কিছুর বিষয়ে কোনও অনুমান করার দরকার নেই। (উত্সটি দেখে আমি বছর খানেক আগে এটি পরীক্ষা করে দেখেছি, তবে এখনই কোনও উল্লেখ নেই))

চাপাচাপি

এই সতর্কতাটি দমন করা প্রয়োজনীয় এবং ভাল কোড ডিজাইনের হয়ে উঠতে পারে এমন পরিস্থিতিটি ভাবতে চেষ্টা করার পরে, আমি খালি আসছি। কেউ দয়া করে ভাগ করুন যদি তাদের যদি এমন কোনও অভিজ্ঞতা থাকে যেখানে এই সতর্কতাটি স্থির করা প্রয়োজন (এবং উপরের জিনিসগুলি সঠিকভাবে পরিচালনা করে না)।

অধিক

এটি NSMethodInvocationপরিচালনা করার জন্য এটিও তৈরি করা সম্ভব , তবে এটি করার জন্য আরও অনেক বেশি টাইপ করা দরকার এবং এটি ধীর গতির হয়, তাই এটি করার খুব কম কারণ আছে।

ইতিহাস

যখন performSelector:পদ্ধতির পরিবারটি প্রথম উদ্দেশ্য-সিতে যুক্ত হয়েছিল, তখন আরসিটির অস্তিত্ব ছিল না। এআরসি তৈরির সময়, অ্যাপল সিদ্ধান্ত নিয়েছে যে এই পদ্ধতিগুলির জন্য বিকাশকারীদের অন্য উপায় ব্যবহারের দিকে পরিচালিত করার উপায় হিসাবে একটি মনোনীত নির্বাচকের মাধ্যমে স্বেচ্ছাসেবক বার্তা প্রেরণ করার সময় স্মৃতি কীভাবে পরিচালনা করা উচিত তা স্পষ্টভাবে সংজ্ঞায়িত করার জন্য একটি সতর্কতা উত্পন্ন করা উচিত। উদ্দেশ্য-সি-তে, বিকাশকারীরা কাঁচা ফাংশন পয়েন্টারে সি স্টাইলের ক্যাসেট ব্যবহার করে এটি করতে সক্ষম হন।

সুইফ্ট প্রবর্তনের সাথে সাথে অ্যাপল পরিবারের অভ্যন্তরীণ পদ্ধতিগুলিকে "সহজাতভাবে অনিরাপদ" হিসাবে নথিভুক্ত করেছে performSelector:এবং সেগুলি সুইফটে উপলব্ধ নয়।

সময়ের সাথে সাথে আমরা এই অগ্রগতি দেখেছি:

  1. অবজেক্টিভ-সি এর প্রাথমিক সংস্করণগুলি অনুমতি দেয় performSelector:(ম্যানুয়াল মেমরি পরিচালনা)
  2. এআরসি সহ উদ্দেশ্য-সি ব্যবহারের জন্য সতর্ক করে performSelector:
  3. performSelector:"অভ্যন্তরীণভাবে অনিরাপদ" হিসাবে সুইফ্টের এই পদ্ধতিগুলিতে অ্যাক্সেস এবং নথির অ্যাক্সেস নেই documents

নামী নির্বাচিতের উপর ভিত্তি করে বার্তা প্রেরণের ধারণাটি অবশ্য "অন্তর্নিহিত অনিরাপদ" বৈশিষ্ট্য নয়। এই ধারণাটি দীর্ঘদিন ধরে অবজেক্টিভ-সি পাশাপাশি আরও অনেক প্রোগ্রামিং ভাষায় ব্যবহৃত হয়েছে।


1 সমস্ত অবজেক্টিভ-সি পদ্ধতিতে দুটি লুকানো আর্গুমেন্ট থাকে selfএবং _cmdএটি আপনি যখন কোনও পদ্ধতিতে কল করেন তখন তা স্পষ্টভাবে যুক্ত হয়।

2 একটি NULLফাংশন কল করা সি তে নিরাপদ নয় কন্ট্রোলারের উপস্থিতি যাচাই করতে ব্যবহৃত প্রহরীটি নিশ্চিত করে যে আমাদের কোনও বস্তু আছে। সুতরাং আমরা জানি যে আমরা একটি কিনবো IMPথেকে methodForSelector:(এটা হতে পারে যদিও _objc_msgForward, বার্তা ফরওয়ার্ডিং সিস্টেমের মধ্যে এন্ট্রি)। মূলত, জায়গায় পাহারাদারের সাথে, আমরা জানি আমাদের কল করার একটি ফাংশন রয়েছে।

3 প্রকৃতপক্ষে, আপনাকে যদি অবজেক্ট হিসাবে ঘোষণা করে idএবং আপনি সমস্ত শিরোনাম আমদানি না করে থাকেন তবে ভুল তথ্য পাওয়া সম্ভব । আপনি কোডটিতে ক্র্যাশগুলি শেষ করতে পারেন যা সংকলকটি ঠিক মনে করে। এটি খুব বিরল, তবে ঘটতে পারে। সাধারণত আপনি কেবল একটি সতর্কতা পাবেন যে দুটি পদ্ধতির স্বাক্ষরগুলির মধ্যে কোনটি বেছে নেবে তা এটি জানে না।

4 আরও তথ্যের জন্য ধরে রাখা পুনরুদ্ধার মান এবং অপ্রত্যাশিত রিটার্ন মানগুলির বিষয়ে এআরসি রেফারেন্স দেখুন ।


@Wbyoung যদি আপনার কোড ধরে রাখার সমস্যাটি সমাধান করে তবে আমি ভাবছি কেন performSelector:পদ্ধতিগুলি এইভাবে প্রয়োগ করা হয় না। তাদের কঠোর পদ্ধতির স্বাক্ষর রয়েছে (ফিরে আসা id, এক বা দুটি idগুলি নেওয়া), তাই কোনও আদিম ধরণের হ্যান্ডেল করার প্রয়োজন নেই।
ট্রাইসারটপস

1
@ এবং তর্কটি পদ্ধতির প্রোটোটাইপের সংজ্ঞার ভিত্তিতে পরিচালনা করা হয় (এটি ধরে রাখা / প্রকাশ করা হবে না)। উদ্বেগটি মূলত রিটার্নের ধরণের উপর ভিত্তি করে।
wbyoung

2
"কমপ্লেক্স উদাহরণ" Cannot initialize a variable of type 'CGRect (*)(__strong id, SEL, CGRect, UIView *__strong)' with an rvalue of type 'void *'সর্বশেষ এক্সকোড ব্যবহার করার সময় একটি ত্রুটি দেয় । (5.1.1) তবুও, আমি অনেক কিছু শিখেছি!
স্টান জেমস

2
void (*func)(id, SEL) = (void *)imp;সংকলন করে না, আমি এটি প্রতিস্থাপন করেছিvoid (*func)(id, SEL) = (void (*)(id, SEL))imp;
ডেভিড জিল

1
পরিবর্তন void (*func)(id, SEL) = (void *)imp;করার জন্য <…> = (void (*))imp;বা<…> = (void (*) (id, SEL))imp;
Isaak Osipovich Dunayevsky

1182

এক্সকোড ৪.২-তে এলএলভিএম comp.০ সংকলকটিতে আপনি সতর্কতাটি নিম্নরূপে দমন করতে পারেন:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    [self.ticketTarget performSelector: self.ticketAction withObject: self];
#pragma clang diagnostic pop

যদি আপনি বেশ কয়েকটি জায়গায় ত্রুটি পেয়ে থাকেন এবং প্রাগমাসগুলি গোপন করতে সি ম্যাক্রো সিস্টেমটি ব্যবহার করতে চান তবে সতর্কতা দমন করা সহজ করার জন্য আপনি একটি ম্যাক্রো সংজ্ঞায়িত করতে পারেন:

#define SuppressPerformSelectorLeakWarning(Stuff) \
    do { \
        _Pragma("clang diagnostic push") \
        _Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \
        Stuff; \
        _Pragma("clang diagnostic pop") \
    } while (0)

আপনি এই জাতীয় ম্যাক্রো ব্যবহার করতে পারেন:

SuppressPerformSelectorLeakWarning(
    [_target performSelector:_action withObject:self]
);

আপনার যদি সম্পাদিত বার্তার ফলাফলের প্রয়োজন হয় তবে আপনি এটি করতে পারেন:

id result;
SuppressPerformSelectorLeakWarning(
    result = [_target performSelector:_action withObject:self]
);

যখন অপটিমাইজেশন কিছুই বাদে অন্য কোনও কিছুতে সেট করা থাকে তখন এই পদ্ধতিটি মেমরি ফাঁসের কারণ হতে পারে।
এরিক

4
@ এরিক এটি না, যদি না আপনি "ইনসোমিংথিং" বা "নিউসোমিংথিং" বা "কিছুরকমি" এর মতো মজার পদ্ধতি ব্যবহার করেন।
আন্দ্রে তারানসভ

3
@ জুলিয়ান এটি কাজ করে তবে এটি পুরো ফাইলটির জন্য সতর্কবার্তাটি বন্ধ করে দেয় - আপনার সম্ভবত এটি প্রয়োজন বা চাইবে না। popএবং push-প্র্যাগমাস দিয়ে এটি মোড়ানো অনেক ক্লিনার এবং আরও সুরক্ষিত।
এমিল

2
এই সমস্ত কি এটি সংকলক চুপ করে। এটি সমস্যার সমাধান করে না। যদি নির্বাচক উপস্থিত না থাকে তবে আপনি বেশ খারাপ হয়ে গেছেন।
আন্দ্রা টডোরস্কু

2
এটি কেবল তখনই ব্যবহার করা উচিত যখন কোনও if ([_target respondsToSelector:_selector]) {অনুরূপ যুক্তি দ্বারা আবৃত থাকে ।

208

এটি সম্পর্কে আমার অনুমানটি হ'ল: নির্বাচক যেহেতু সংকলকের কাছে অজানা, তাই আরসি সঠিক মেমরি পরিচালনা প্রয়োগ করতে পারে না।

প্রকৃতপক্ষে, এমন সময়গুলি রয়েছে যখন কোনও নির্দিষ্ট সম্মেলনের মাধ্যমে মেমরি পরিচালনা পদ্ধতিটির নামের সাথে যুক্ত থাকে। বিশেষত, আমি সুবিধার কনস্ট্রাক্টরগুলি বনাম তৈরির পদ্ধতিগুলি নিয়ে ভাবছি ; কনভেনশন দ্বারা প্রাক্তন রিটার্ন একটি স্বতঃপ্রযুক্ত বস্তু; দ্বিতীয়টি একটি বজায় রাখা বস্তু। কনভেনশনটি নির্বাচকদের নামের উপর ভিত্তি করে তৈরি করা হয়, সুতরাং সংকলক যদি নির্বাচককে না জানায় তবে এটি যথাযথ মেমরি পরিচালনার নিয়মটি প্রয়োগ করতে পারে না।

যদি এটি সঠিক হয় তবে আমি মনে করি আপনি সুরক্ষিতভাবে আপনার কোডটি ব্যবহার করতে পারবেন, তবে আপনি মেমরির ব্যবস্থাপনার ক্ষেত্রে সমস্ত কিছু ঠিক আছে কিনা তা নিশ্চিত করে (যেমন, আপনার পদ্ধতিগুলি যেগুলি বরাদ্দ করে সেগুলি ফেরত দেয় না)।


5
উত্তরের জন্য ধন্যবাদ, আমি কী চলছে তা দেখার জন্য এটি আরও খতিয়ে দেখব। আমি কীভাবে সতর্কতাটিকে বাইপাস করে এটিকে অদৃশ্য করতে পারি তার কোনও ধারণা? নিরাপদ কল কী তা জন্য আমি আমার কোডটিতে চিরকালের জন্য সতর্কতা বজায় রাখা ঘৃণা করব।
এডুয়ার্ডো স্কোজ

84
সুতরাং আমি তাদের ফোরামে অ্যাপলের কারও কাছ থেকে নিশ্চয়তা পেয়েছি যে এটি প্রকৃতপক্ষে। লোকেরা ভবিষ্যতে প্রকাশে এই সতর্কতাটি অক্ষম করতে দেওয়ার জন্য তারা একটি ভুলে যাওয়া ওভাররাইড যুক্ত করবে। ধন্যবাদ।
এডুয়ার্ডো স্কোজ

5
এই উত্তরটি কিছু প্রশ্ন উত্থাপন করে, যেমন যদি আর্ক কনভেনশন এবং পদ্ধতির নামের উপর ভিত্তি করে কোনও কিছু প্রকাশ করতে হয় সে বিষয়ে সিদ্ধান্ত গ্রহণের চেষ্টা করে, তবে এটি "রেফারেন্স গণনা" কীভাবে হয়? আপনি যে আচরণটি বর্ণনা করেছেন তা পুরোপুরি স্বেচ্ছাসেবকের চেয়ে কেবল সামান্যই ভাল শোনায়, যদি এআরসি কোড ধরে নিচ্ছে তবে কোনও কনভেনশন অনুসরণ করা হোক না কেন প্রকৃতপক্ষে রেফারেন্সগুলি ট্র্যাক করার বিপরীতে এটি একটি নির্দিষ্ট সম্মেলন অনুসরণ করে।
আরথ

8
এআরসি সংকলনটিতে ধরে রাখার এবং প্রকাশ করার প্রক্রিয়াটি স্বয়ংক্রিয় করে তোলে। এটি আবর্জনা সংগ্রহ নয় (যে কারণে এটি এত অবিশ্বাস্যরূপে দ্রুত এবং নিম্ন ওভারহেড)। এটি মোটেও স্বেচ্ছাচারিতা নয়। ডিফল্ট নিয়মগুলি সু-প্রতিষ্ঠিত ওবজেসি সম্মেলনের উপর ভিত্তি করে নিয়মিতভাবে কয়েক দশক ধরে প্রয়োগ করা হয়েছে। এটি __attributeএর স্মৃতি ম্যানেজমেন্ট পরিচালনার ব্যাখ্যা করে প্রতিটি পদ্ধতিতে স্পষ্টভাবে একটি যুক্ত করার প্রয়োজনীয়তা এড়ায় । তবে এটি কম্পাইলারের পক্ষে এই প্যাটার্নটি সঠিকভাবে পরিচালনা করাও অসম্ভব করে তোলে (এমন একটি প্যাটার্ন যা খুব সাধারণ ব্যবহৃত হত, তবে সাম্প্রতিক বছরগুলিতে আরও দৃust় নিদর্শনগুলির সাথে প্রতিস্থাপন করা হয়েছে)।
রব নেপিয়ার

8
সুতরাং আমরা আর একটি আইভার টাইপ করতে পারি না SELএবং পরিস্থিতির উপর নির্ভর করে বিভিন্ন নির্বাচককে নিয়োগ করতে পারি? যাওয়ার উপায়, গতিশীল ভাষা ...
নিকোলাস মিয়ারি

121

আপনার প্রকল্পে অন্যান্য সতর্কতা পতাকা ( ) এর অধীনে সেটিংস তৈরি করুনWARNING_CFLAGS
-Wno-arc-performSelector-leaks

এখনই নিশ্চিত হয়ে নিন যে আপনি যে নির্বাচককে কল করছেন তার ফলে আপনার অবজেক্টটি ধরে রাখা বা অনুলিপি করা হচ্ছে না।


12
দ্রষ্টব্য আপনি পুরো প্রকল্পের চেয়ে নির্দিষ্ট ফাইলগুলির জন্য একই পতাকা যুক্ত করতে পারেন। আপনি যদি বিল্ড পর্যায়সমূহ-> সংকলন উত্সগুলির অধীনে সন্ধান করেন তবে আপনি প্রতি ফাইল সংকলক পতাকা সেট করতে পারেন (ঠিক যেমন আপনি এআরসি থেকে ফাইলগুলি বাদ দেওয়ার জন্য করতে চান)। আমার প্রকল্পে কেবল একটি ফাইলের এভাবে নির্বাচকদের ব্যবহার করা উচিত, তাই আমি কেবল এটিকে বাদ দিয়ে অন্যকে রেখে দিয়েছি।
মাইকেল

111

সংকলক সতর্কতাটিকে ওভাররাইড করার অনুমতি না দেওয়া পর্যন্ত আপনি রানটাইমটি ব্যবহার করতে পারেন

objc_msgSend(_controller, NSSelectorFromString(@"someMethod"));

পরিবর্তে

[_controller performSelector:NSSelectorFromString(@"someMethod")];

তোমাকে করতে হবে

#import <objc/message.h>


8
এআরসি কোকো সম্মেলনগুলিকে স্বীকৃতি দেয় এবং তারপরে এই সম্মেলনগুলির উপর ভিত্তি করে ধরে রাখে এবং প্রকাশ করে। সি এই কনভেনশনগুলি অনুসরণ করে না বলে, এআরসি আপনাকে ম্যানুয়াল মেমরি পরিচালনার কৌশলগুলি ব্যবহার করতে বাধ্য করে। আপনি যদি কোনও সিএফ অবজেক্ট তৈরি করেন তবে আপনাকে অবশ্যই এটি সিএফআলিলিজ করুন ()। যদি আপনি dispatch_queue_create () করেন তবে আপনাকে অবশ্যই প্রেরণ_আগ্রহ করে ()। নীচের লাইন, আপনি যদি এআরসি সতর্কতাগুলি এড়াতে চান, আপনি সি অবজেক্টস এবং ম্যানুয়াল মেমরি পরিচালনা ব্যবহার করে এগুলি এড়াতে পারেন। এছাড়াও, আপনি সেই ফাইলটিতে -fno-objc-arc সংকলক পতাকা ব্যবহার করে প্রতি ফাইলের ভিত্তিতে ARC অক্ষম করতে পারবেন।
jluckyiv

8
Castালাই ছাড়া না, আপনি পারবেন না। Varargs সুস্পষ্টভাবে টাইপ করা যুক্তি তালিকার মতো নয়। এটি সাধারণত কাকতালীয়ভাবে কাজ করবে তবে আমি "কাকতালীয়ভাবে" সঠিক বলে বিবেচনা করি না।
বুবুম

21
এটি করবেন না, [_controller performSelector:NSSelectorFromString(@"someMethod")];এবং objc_msgSend(_controller, NSSelectorFromString(@"someMethod"));সমতুল্য নয়! কটাক্ষপাত আছে পদ্ধতি স্বাক্ষর অমিল এবং উদ্দেশ্য সি এর দুর্বল টাইপিং একটি বড় দুর্বলতা তারা গভীরতা সমস্যা ব্যাখ্যা করা হয়।
0xced

5
@ 0xced এই ক্ষেত্রে, এটি ঠিক আছে। objc_msgSend কোনও নির্বাচনকারীর জন্য পারফরম্যাসলেক্টরে সঠিকভাবে কাজ করতে পারে এমন কোনও পদ্ধতিতে স্বাক্ষরের অমিল তৈরি করবে না: বা এর রূপগুলি যেহেতু তারা কেবলমাত্র পরামিতি হিসাবে বস্তু গ্রহণ করে। যতক্ষণ না আপনার সমস্ত প্যারামিটারগুলি পয়েন্টার (Incl। অবজেক্টস), ডাবলস এবং NSInteger / দীর্ঘ এবং আপনার ফেরতের প্রকারটি অকার্যকর, পয়েন্টার বা লম্বা হয়, ততক্ষণ obc_msgSend সঠিকভাবে কাজ করবে।
ম্যাট গালাগের

88

পারফর্ম সিলেক্টর দিয়ে কেবল ফাইলটিতে ত্রুটি উপেক্ষা করতে, নিম্নলিখিত হিসাবে একটি # চিত্র যুক্ত করুন:

#pragma clang diagnostic ignored "-Warc-performSelector-leaks"

এটি এই লাইনের সতর্কতাটিকে উপেক্ষা করবে, তবে এটি আপনার প্রকল্পের বাকি অংশে অনুমতি দিন।


6
আমি একত্রিত হয়েছি যে আপনি যে পদ্ধতিতে প্রশ্নযুক্ত তা পরে অবিলম্বে সতর্কতাটি আবার চালু করতে পারেন #pragma clang diagnostic warning "-Warc-performSelector-leaks"। আমি জানি যদি আমি কোনও সতর্কতা বন্ধ করি তবে আমি তাড়াতাড়ি সম্ভব এটিকে আবার চালু করতে চাই, তাই আমি ঘটনাক্রমে অন্য অপ্রত্যাশিত সতর্কবার্তাটি পিছলে যেতে দেই না। এটি সমস্যা বলে সম্ভাবনা নেই, তবে আমি যখনই কোনও সতর্কতা বন্ধ করি তবে এটি কেবল আমার অনুশীলন।
রব

2
আপনি #pragma clang diagnostic warning pushকোনও পরিবর্তন #pragma clang diagnostic warning popকরার আগে এবং পূর্বের অবস্থাটি পুনরুদ্ধার করে আপনার আগের সংকলক কনফিগারেশন স্থিতি পুনরুদ্ধার করতে পারেন । আপনি যদি লোডগুলি বন্ধ করে দিচ্ছেন এবং আপনার কোডগুলিতে প্রচুর পুনরায় সক্ষম করতে চান না তা দরকারী।
ডিনবম্বর্ন

এটি কেবল নিম্নলিখিত লাইনটি উপেক্ষা করবে?
hfossli

70

অদ্ভুত তবে সত্য: যদি গ্রহণযোগ্য হয় (উদাহরণস্বরূপ ফলাফলটি শূন্য হয় এবং আপনি একবার রানলুপ চক্রটি দিতে দিতে আপত্তি করেন না), যদিও এটি শূন্য হলেও একটি বিলম্ব যুক্ত করুন:

[_controller performSelector:NSSelectorFromString(@"someMethod")
    withObject:nil
    afterDelay:0];

এটি সতর্কতাটিকে সরিয়ে দেয়, সম্ভবতঃ কারণ এটি সংকলকটিকে আশ্বাস দেয় যে কোনও বস্তু ফেরত দেওয়া যাবে না এবং কোনওভাবে অব্যবস্থাপনা করা যাবে না।


2
আপনি কি জানেন যে এটি যদি আসলে সম্পর্কিত মেমরি পরিচালনা সংক্রান্ত সমস্যাগুলি সমাধান করে তবে এর কি একই সমস্যা রয়েছে তবে এক্সকোড এই কোডটি দিয়ে আপনাকে সতর্ক করার মতো যথেষ্ট স্মার্ট নয়?
অ্যারন ব্র্যাজার

এটি শব্দার্থগতভাবে একই জিনিস নয়! সঞ্চালনকারী নির্বাচন করে: উইজ অবজেক্ট: আফটারডেলি: রানলুপের পরবর্তী রানটিতে নির্বাচকটি সম্পাদন করবে। অতএব, এই পদ্ধতিটি অবিলম্বে ফিরে আসে।
ফ্লোরিয়ান

10
@ ফ্লোরিয়ান অবশ্যই এটি এক নয়! আমার উত্তর পড়ুন: আমি গ্রহণযোগ্য হলে বলি , কারণ ফলাফলটি অকার্যকর এবং রানলুপ চক্র। এটি আমার উত্তরের প্রথম বাক্য
ম্যাট 14

34

উপরে বর্ণিত উত্তরের উপর ভিত্তি করে এখানে একটি আপডেট ম্যাক্রো দেওয়া হয়েছে। এই একটি আপনাকে একটি রিটার্ন বিবৃতি দিয়ে এমনকি আপনার কোডটি মোড়ানোর অনুমতি দেবে should

#define SUPPRESS_PERFORM_SELECTOR_LEAK_WARNING(code)                        \
    _Pragma("clang diagnostic push")                                        \
    _Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"")     \
    code;                                                                   \
    _Pragma("clang diagnostic pop")                                         \


SUPPRESS_PERFORM_SELECTOR_LEAK_WARNING(
    return [_target performSelector:_action withObject:self]
);

6
returnম্যাক্রোর ভিতরে থাকতে হবে না; return SUPPRESS_PERFORM_SELECTOR_LEAK_WARNING([_target performSelector:_action withObject:self]);এছাড়াও কাজ করে এবং স্যানার দেখায়।
uasi

31

এই কোডটি সংকলক পতাকা বা সরাসরি রানটাইম কল জড়িত না:

SEL selector = @selector(zeroArgumentMethod);
NSMethodSignature *methodSig = [[self class] instanceMethodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
[invocation setSelector:selector];
[invocation setTarget:self];
[invocation invoke];

NSInvocationএকাধিক যুক্তি সেট করার অনুমতি দেয় যাতে performSelectorএটি কোনও পদ্ধতিতে কাজ করবে unlike


3
আপনি কি জানেন যে এটি যদি আসলে সম্পর্কিত মেমরি পরিচালনা সংক্রান্ত সমস্যাগুলি সমাধান করে তবে এর কি একই সমস্যা রয়েছে তবে এক্সকোড এই কোডটি দিয়ে আপনাকে সতর্ক করার মতো যথেষ্ট স্মার্ট নয়?
অ্যারন ব্র্যাজার

1
আপনি বলতে পারেন এটি মেমরি পরিচালনার সমস্যাগুলি সমাধান করে; তবে এটি কারণ এটি মূলত আপনাকে আচরণটি নির্দিষ্ট করতে দেয়। উদাহরণস্বরূপ, আপনি অনুরোধটি আর্গুমেন্টগুলি ধরে রাখতে বা না চয়ন করতে পারেন। আমার বর্তমান জ্ঞান অনুসারে, এটি স্বাক্ষরটি মেলে না এমন সমস্যাগুলি সমাধান করার চেষ্টা করে যা আপনি বিশ্বাস করছেন যে আপনি কী করছেন এবং ভুল ডেটা সরবরাহ করবেন না এই বিশ্বাস করে তা প্রদর্শিত হতে পারে। আমি নিশ্চিত নই যে রানটাইমের সময় সমস্ত চেক করা যায় কিনা। অন্য মন্তব্যে উল্লিখিত হিসাবে, মাইক্যাশ.com / pyblog /… অমিলগুলি কী করতে পারে তা সুন্দরভাবে ব্যাখ্যা করে।
মিহাই তিমার

20

ভাল, এখানে অনেক উত্তর, তবে যেহেতু এটি কিছুটা পৃথক, কয়েকটি উত্তর মিলিয়ে আমি ভেবেছিলাম যে আমি এটি রেখে দিয়েছি I'm আমি একটি এনএসবজেক্ট বিভাগ ব্যবহার করছি যা নির্বাচকটি শূন্য ফিরে আসে তা নিশ্চিত করার জন্য যাচাই করে এবং সংকলকটিও দমন করে সাবধানবাণী।

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "Debug.h" // not given; just an assert

@interface NSObject (Extras)

// Enforce the rule that the selector used must return void.
- (void) performVoidReturnSelector:(SEL)aSelector withObject:(id)object;
- (void) performVoidReturnSelector:(SEL)aSelector;

@end

@implementation NSObject (Extras)

// Apparently the reason the regular performSelect gives a compile time warning is that the system doesn't know the return type. I'm going to (a) make sure that the return type is void, and (b) disable this warning
// See http://stackoverflow.com/questions/7017281/performselector-may-cause-a-leak-because-its-selector-is-unknown

- (void) checkSelector:(SEL)aSelector {
    // See http://stackoverflow.com/questions/14602854/objective-c-is-there-a-way-to-check-a-selector-return-value
    Method m = class_getInstanceMethod([self class], aSelector);
    char type[128];
    method_getReturnType(m, type, sizeof(type));

    NSString *message = [[NSString alloc] initWithFormat:@"NSObject+Extras.performVoidReturnSelector: %@.%@ selector (type: %s)", [self class], NSStringFromSelector(aSelector), type];
    NSLog(@"%@", message);

    if (type[0] != 'v') {
        message = [[NSString alloc] initWithFormat:@"%@ was not void", message];
        [Debug assertTrue:FALSE withMessage:message];
    }
}

- (void) performVoidReturnSelector:(SEL)aSelector withObject:(id)object {
    [self checkSelector:aSelector];

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    // Since the selector (aSelector) is returning void, it doesn't make sense to try to obtain the return result of performSelector. In fact, if we do, it crashes the app.
    [self performSelector: aSelector withObject: object];
#pragma clang diagnostic pop    
}

- (void) performVoidReturnSelector:(SEL)aSelector {
    [self checkSelector:aSelector];

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    [self performSelector: aSelector];
#pragma clang diagnostic pop
}

@end

'V' কে _ সি_ভিওআইডি দ্বারা প্রতিস্থাপন করা উচিত? _সি_ভিওআইডি <আপত্তি / রানটাইম.h> এ ঘোষণা করা হয়েছে।
রিক রিনিচ

16

উত্তরসূরির জন্য, আমি আমার টুপিটি রিংয়ের মধ্যে ফেলে দেওয়ার সিদ্ধান্ত নিয়েছি :)

প্রোটোকল, ব্লক ইত্যাদির পক্ষে আমি সম্প্রতি target/ selectorপ্যাড্রাইম থেকে আরও বেশি পুনর্গঠন করতে দেখছি তবে, performSelectorএখন কয়েকবার ব্যবহার করেছি এর জন্য একটি ড্রপ-ইন প্রতিস্থাপন রয়েছে :

[NSApp sendAction: NSSelectorFromString(@"someMethod") to: _controller from: nil];

এগুলি একটি পরিষ্কার, এআরসি-নিরাপদ এবং প্রায় অভিন্ন প্রতিস্থাপন হিসাবে performSelectorখুব বেশি কিছু না বলে মনে হয় objc_msgSend()

যদিও, আইওএস-এ কোনও এনালগ উপলব্ধ রয়েছে কিনা সে সম্পর্কে আমার কোনও ধারণা নেই।


6
এটি সহ জন্য ধন্যবাদ .. এটা iOS এ উপলব্ধ: [[UIApplication sharedApplication] sendAction: to: from: forEvent:]। আমি এটি একবার দেখেছি, তবে আপনার ডোমেন বা পরিষেবাটির মাঝখানে কোনও গতিশীল কল করার জন্য এটি কোনও ইউআই-সম্পর্কিত ক্লাস ব্যবহার করা একরকম বিশ্রী মনে করে .. যদিও এটি অন্তর্ভুক্ত করার জন্য ধন্যবাদ!
এডুয়ার্ডো স্কোজ

2
ছিঃ! এতে আরও ওভারহেড থাকবে (যেহেতু এটি পদ্ধতিটি উপলব্ধ কিনা তা যাচাই করা দরকার এবং প্রতিক্রিয়াশীল চেইনটি যদি তা না পাওয়া যায় তবে এটির বিভিন্ন সমস্যা আছে) যা কেবল ক্র্যাশ করার পরিবর্তে পদ্ধতিটিতে সাড়া দেয়)। এছাড়া কাজ করে না যখন আপনি চান idথেকে-performSelector:...
TC।

2
@tc। এটি to:শূন্য না হলে "প্রতিক্রিয়াশীল চেইন" চালায় না, যা তা নয়। এটি সরাসরি কোনও পরীক্ষার আগে সরাসরি লক্ষ্যবস্তুতে যায়। সুতরাং "আরও ওভারহেড" নেই। এটি কোনও দুর্দান্ত সমাধান নয়, তবে আপনি যে কারণটি দিয়েছেন তা কারণ নয়। :)
ম্যাট 21 ই

15

এই থ্রেডে ম্যাট গ্যাল্লোয়ের উত্তর কেন ব্যাখ্যা করেছে:

নিম্নোক্ত বিবেচনা কর:

id anotherObject1 = [someObject performSelector:@selector(copy)];
id anotherObject2 = [someObject performSelector:@selector(giveMeAnotherNonRetainedObject)];

এখন, এআরসি কীভাবে জানতে পারে যে প্রথমটি 1 টি ধরে রাখার গণনা সহ একটি বস্তুকে ফেরত দেয় তবে দ্বিতীয়টি একটি বস্তু যা স্বতঃস্ফূর্ত হয় তা ফেরত দেয়?

দেখে মনে হচ্ছে আপনি যদি ফেরতের মানটিকে অগ্রাহ্য করেন তবে সতর্কতাটি দমন করা সাধারণত নিরাপদ generally আমি নিশ্চিত না যে যদি আপনি সত্যিই পারফর্মসিলেক্টর থেকে একটি রক্ষণযোগ্য অবজেক্ট পাওয়ার প্রয়োজন হয় তবে সর্বোত্তম অনুশীলনটি কী তা - "" এটি করবেন না "ব্যতীত।


14

@ সি-রোডটি এখানে সমস্যার বর্ণনার সাথে সঠিক লিঙ্ক সরবরাহ করে । নীচে আপনি আমার উদাহরণটি দেখতে পাচ্ছেন, যখন পারফরমেন্সলেক্টর একটি মেমরি ফাঁস হয়।

@interface Dummy : NSObject <NSCopying>
@end

@implementation Dummy

- (id)copyWithZone:(NSZone *)zone {
  return [[Dummy alloc] init];
}

- (id)clone {
  return [[Dummy alloc] init];
}

@end

void CopyDummy(Dummy *dummy) {
  __unused Dummy *dummyClone = [dummy copy];
}

void CloneDummy(Dummy *dummy) {
  __unused Dummy *dummyClone = [dummy clone];
}

void CopyDummyWithLeak(Dummy *dummy, SEL copySelector) {
  __unused Dummy *dummyClone = [dummy performSelector:copySelector];
}

void CloneDummyWithoutLeak(Dummy *dummy, SEL cloneSelector) {
  __unused Dummy *dummyClone = [dummy performSelector:cloneSelector];
}

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    Dummy *dummy = [[Dummy alloc] init];
    for (;;) { @autoreleasepool {
      //CopyDummy(dummy);
      //CloneDummy(dummy);
      //CloneDummyWithoutLeak(dummy, @selector(clone));
      CopyDummyWithLeak(dummy, @selector(copy));
      [NSThread sleepForTimeInterval:1];
    }} 
  }
  return 0;
}

একমাত্র পদ্ধতি, যা আমার উদাহরণে মেমরি ফাঁস হওয়ার কারণ হ'ল কপিডম্মিবিথলিক। কারণটি হ'ল এআরসি জানে না, সেই অনুলিপিটি অনুলিপিযুক্ত বস্তুটি ফিরিয়ে দেয়।

আপনি যদি মেমরি ফুটো সরঞ্জাম চালনা করেন তবে নীচের চিত্রটি দেখতে পাবেন: এখানে চিত্র বর্ণনা লিখুন ... এবং অন্য কোনও ক্ষেত্রে মেমরি ফাঁস নেই: এখানে চিত্র বর্ণনা লিখুন


6

স্কট থম্পসনের ম্যাক্রো আরও জেনেরিক করতে:

// String expander
#define MY_STRX(X) #X
#define MY_STR(X) MY_STRX(X)

#define MYSilenceWarning(FLAG, MACRO) \
_Pragma("clang diagnostic push") \
_Pragma(MY_STR(clang diagnostic ignored MY_STR(FLAG))) \
MACRO \
_Pragma("clang diagnostic pop")

তারপরে এটি ব্যবহার করুন:

MYSilenceWarning(-Warc-performSelector-leaks,
[_target performSelector:_action withObject:self];
                )

FWIW, আমি ম্যাক্রো যুক্ত করিনি। কেউ আমার প্রতিক্রিয়া যোগ করেছেন। ব্যক্তিগতভাবে, আমি ম্যাক্রো ব্যবহার করব না। প্রাগমা কোডটিতে একটি বিশেষ কেস ঘিরে কাজ করার জন্য রয়েছে এবং প্রাগমাসগুলি কী চলছে তা সম্পর্কে খুব স্পষ্ট এবং সরাসরি। আমি তাদের লুকিয়ে রাখার চেয়ে বা ম্যাক্রোর পিছনে বিমূর্ত করার পরিবর্তে সেগুলিকে রাখা পছন্দ করি, তবে এটি কেবল আমারই। YMMV।
স্কট থমসন

@ স্কটথহম্পসন এটি ফর্সা। আমার জন্য আমার কোড বেস জুড়ে এই ম্যাক্রোটি অনুসন্ধান করা সহজ এবং আমি অন্তর্নিহিত সমস্যাটি মোকাবেলা করার জন্য একটি নিঃশব্দ সতর্কতাও যুক্ত করি।
বেন ফ্লিন

6

সতর্কতা দমন করবেন না!

সংকলকটির সাথে টিঙ্কারিংয়ের 12 টিরও কম বিকল্প সমাধান নেই।
প্রথম প্রয়োগের সময় আপনি যখন চালাক হচ্ছেন তখন পৃথিবীতে কয়েকজন প্রকৌশলী আপনার পদক্ষেপগুলি অনুসরণ করতে পারেন এবং এই কোডটি শেষ পর্যন্ত ভেঙে যাবে।

নিরাপদ রুট:

এই সমস্ত সমাধানগুলি আপনার মূল অভিপ্রায় থেকে কিছুটা ভিন্নতার সাথে কাজ করবে। যদি আপনি ইচ্ছা করেন তবে তা paramহতে পারে nil:

নিরাপদ রুট, একই ধারণামূলক আচরণ:

// GREAT
[_controller performSelectorOnMainThread:selector withObject:anArgument waitUntilDone:YES];
[_controller performSelectorOnMainThread:selector withObject:anArgument waitUntilDone:YES modes:@[(__bridge NSString *)kCFRunLoopDefaultMode]];

[_controller performSelector:selector onThread:[NSThread mainThread] withObject:anArgument waitUntilDone:YES];
[_controller performSelector:selector onThread:[NSThread mainThread] withObject:anArgument waitUntilDone:YES modes:@[(__bridge NSString *)kCFRunLoopDefaultMode]];

নিরাপদ রুট, কিছুটা আলাদা আচরণ:

( এই প্রতিক্রিয়াটি দেখুন )
এর পরিবর্তে যে কোনও থ্রেড ব্যবহার করুন [NSThread mainThread]

// GOOD
[_controller performSelector:selector withObject:anArgument afterDelay:0];
[_controller performSelector:selector withObject:anArgument afterDelay:0 inModes:@[(__bridge NSString *)kCFRunLoopDefaultMode]];

[_controller performSelectorOnMainThread:selector withObject:anArgument waitUntilDone:NO];
[_controller performSelectorOnMainThread:selector withObject:anArgument waitUntilDone:NO];
[_controller performSelectorOnMainThread:selector withObject:anArgument waitUntilDone:NO modes:@[(__bridge NSString *)kCFRunLoopDefaultMode]];

[_controller performSelectorInBackground:selector withObject:anArgument];

[_controller performSelector:selector onThread:[NSThread mainThread] withObject:anArgument waitUntilDone:NO];
[_controller performSelector:selector onThread:[NSThread mainThread] withObject:anArgument waitUntilDone:NO modes:@[(__bridge NSString *)kCFRunLoopDefaultMode]];

বিপজ্জনক রুট

কিছু ধরণের সংকলক চুপচাপ দরকার যা বিরতিতে বাধ্য। মনে রাখবেন যে, বর্তমান সময়ে, এটা করেনি মধ্যে বিরতি সুইফট

// AT YOUR OWN RISK
[_controller performSelector:selector];
[_controller performSelector:selector withObject:anArgument];
[_controller performSelector:selector withObject:anArgument withObject:nil];

3
কথাটি খুব ভুল। নিরাপদ রুটগুলি মোটেও বিপজ্জনক চেয়ে নিরাপদ নয়। এটি তর্কতামূলকভাবে আরও বিপজ্জনক কারণ এটি সতর্কতাটি স্পষ্টভাবে গোপন করে।
ব্রায়ান চেন

আমি এই শব্দটি অপমানজনক না হওয়ার সংশোধন করব, তবে আমি আমার কথায় দাঁড়িয়েছি। আমি কোডটির মালিক না হলে কেবলমাত্র নিরব সতর্কতা গ্রহণযোগ্য মনে হয় find কোনও প্রকৌশলী সমস্ত পরিণতি বুঝতে না পেরে নিশ্চিন্ত কোড বজায় রাখতে পারবেন না, যার অর্থ এই যুক্তিটি পড়ুন এবং এই অনুশীলনটি সহজ ঝুঁকিপূর্ণ; বিশেষত আপনি যদি 12 টি, সরল ইংরাজী, শক্ত বিকল্পগুলি বিবেচনা করেন।
সুইফট আরকিটেক্ট

1
না। আপনি আমার বক্তব্য পেলেন না সতর্কতা নিঃশব্দ করার জন্য ব্যবহার performSelectorOnMainThreadকরা ভাল উপায় নয় এবং এর পার্শ্ব প্রতিক্রিয়াও রয়েছে। (এটি মেমরি ফাঁসের সমাধান করে না) অতিরিক্ত #clang diagnostic ignored স্পষ্টভাবে সতর্কতাটিকে খুব পরিষ্কার উপায়ে দমন করে।
ব্রায়ান চেন

সত্য যে নন - (void)পদ্ধতিতে কোনও নির্বাচককে সম্পাদন করা আসল সমস্যা।
সুইফট আরকিটেক্ট

এবং কীভাবে আপনি এই মাধ্যমে একাধিক যুক্তি সহ কোনও নির্বাচককে কল করবেন এবং একই সময়ে নিরাপদ থাকবেন? @ সুইফটআর্কিটেক্ট
ক্যাটালিন

4

আপনি এআরসি ব্যবহার করছেন বলে আপনাকে অবশ্যই আইওএস ৪.০ বা তার পরে ব্যবহার করতে হবে। এর অর্থ আপনি ব্লকগুলি ব্যবহার করতে পারেন। পরিবর্তে যদি নির্বাচককে আপনাকে সম্পাদন করার জন্য মনে রাখার পরিবর্তে একটি ব্লক নিয়ে যায়, তবে এআরসি আসলে কী চলছে তা ভালভাবে আবিষ্কার করতে সক্ষম হবে এবং ঘটনাক্রমে স্মৃতি ফাঁস হওয়ার ঝুঁকিটি আপনাকে চালাতে হবে না।


আসলে, ব্লকগুলি দুর্ঘটনাক্রমে এমন একটি রক্ষণশীল চক্র তৈরি করা খুব সহজ করে তোলে যা আরসি সমাধান করে না। আমি এখনও চাই যে আপনি যখন selfivar (উদাহরণস্বরূপ ivarপরিবর্তে self->ivar) মাধ্যমে সুস্পষ্টভাবে ব্যবহার করেছেন তখন সেখানে একটি সংকলক সতর্কতা ছিল ।
টিসি।

আপনি বলতে চাইছেন - উইম্প্লিফিক-রক্ষণ-স্ব-মত?
অরেঞ্জডগ

2

ব্লক পদ্ধতির ব্যবহারের পরিবর্তে, যা আমাকে কিছু সমস্যা দিয়েছে:

    IMP imp = [_controller methodForSelector:selector];
    void (*func)(id, SEL) = (void *)imp;

আমি এনএসআইভোকেশনটি ব্যবহার করব, এটির মতো:

    -(void) sendSelectorToDelegate:(SEL) selector withSender:(UIButton *)button 

    if ([delegate respondsToSelector:selector])
    {
    NSMethodSignature * methodSignature = [[delegate class]
                                    instanceMethodSignatureForSelector:selector];
    NSInvocation * delegateInvocation = [NSInvocation
                                   invocationWithMethodSignature:methodSignature];


    [delegateInvocation setSelector:selector];
    [delegateInvocation setTarget:delegate];

    // remember the first two parameter are cmd and self
    [delegateInvocation setArgument:&button atIndex:2];
    [delegateInvocation invoke];
    }

1

আপনার যদি কোনও যুক্তি পাস করার প্রয়োজন না হয় তবে একটি সহজ কাজ ব্যবহার করা valueForKeyPath। এটি কোনও Classবস্তুর পক্ষেও সম্ভব ।

NSString *colorName = @"brightPinkColor";
id uicolor = [UIColor class];
if ([uicolor respondsToSelector:NSSelectorFromString(colorName)]){
    UIColor *brightPink = [uicolor valueForKeyPath:colorName];
    ...
}

-2

আপনি এখানে একটি প্রোটোকলও ব্যবহার করতে পারেন। সুতরাং, এর মতো একটি প্রোটোকল তৈরি করুন:

@protocol MyProtocol
-(void)doSomethingWithObject:(id)object;
@end

আপনার ক্লাসে আপনার নির্বাচককে কল করতে হবে, তারপরে আপনার একটি @ প্রপার্টি রয়েছে।

@interface MyObject
    @property (strong) id<MyProtocol> source;
@end

যখন আপনাকে @selector(doSomethingWithObject:)মাইবজেক্টের একটি দৃষ্টিতে কল করতে হবে , এটি করুন:

[self.source doSomethingWithObject:object];

2
আরে উ, ধন্যবাদ, তবে এনএসএসইলেক্টর ফ্রেম স্ট্রিংটি ব্যবহার করার বিষয়টি যখন আপনি জানেন না যে রানটাইমের সময় আপনি কোন নির্বাচককে কল করতে চান to
এডুয়ার্ডো স্কোজ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.