performanceSelector එහි තේරීම නොදන්නා නිසා කාන්දුවක් ඇති විය හැක


1262

ARC සම්පාදකයා විසින් මට පහත අනතුරු ඇඟවීම ලැබෙමින් පවතී:

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

මෙන්න මම කරන්නේ:

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

මට මෙම අනතුරු ඇඟවීම ලැබෙන්නේ ඇයි? තේරීම් කාරකය සිටීද නැද්ද යන්න සම්පාදකයාට පරීක්ෂා කළ නොහැකි බව මට වැටහී ඇත, නමුත් එය කාන්දු වීමට හේතුව කුමක්ද? මට තවදුරටත් මෙම අනතුරු ඇඟවීම නොලැබෙන පරිදි මගේ කේතය වෙනස් කරන්නේ කෙසේද?


3
විචල්යයේ නම ගතිකය, එය වෙනත් බොහෝ දේ මත රඳා පවතී. නොපවතින දෙයක් මා හඳුන්වන අවදානමක් ඇත, නමුත් එය ගැටළුව නොවේ.
එඩ්වාඩෝ ස්කොස්

6
වස්තුවක් මත ගතිකව ක්‍රමයක් කැඳවීම නරක පුරුද්දක් වන්නේ ඇයි? NSSelectorFromString () හි සම්පූර්ණ අරමුණ මෙම භාවිතයට සහාය වීම නොවේද?
එඩ්වාඩෝ ස්කොස්

7
PerformSelector හරහා එය සැකසීමට පෙර ඔබට [_controller responseToSelector: mySelector] පරීක්ෂා කළ යුතුය:
mattacular

50
මට ඡන්දය දිය හැකිය: "එය ... නරක පුරුද්දකි."
ctpenrose

6
නූල වචනානුසාරයෙන් බව ඔබ දන්නේ නම්, @selector () භාවිතා කරන්න, එවිට සම්පාදකයාට තේරීම්කරුගේ නම කුමක්දැයි කිව හැකිය. ඔබගේ සත්‍ය කේතය NSSelectorFromString () අමතන්නේ ධාවන වේලාවේදී හෝ සපයන ලද නූලක් සමඟ නම්, ඔබ NSSelectorFromString () භාවිතා කළ යුතුය.
ක්‍රිස් පේජ්

Answers:


1214

විසඳුමක්

සම්පාදකයා මේ ගැන අනතුරු අඟවන්නේ හේතුවක් ඇතුවයි. මෙම අනතුරු ඇඟවීම නොසලකා හැරීම ඉතා කලාතුරකිනි, එය වටා වැඩ කිරීම පහසුය. මෙන්න කොහොමද:

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, ඔබට එය ARC ට අවශ්‍ය සියලු තොරතුරු ඇතුළත් වන ක්‍රියාකාරී දර්ශකයකට දැමිය යුතුය (ව්‍යාජ සැඟවුණු තර්ක දෙක 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;

අවවාදය සඳහා තර්කනය

මෙම අනතුරු ඇඟවීමට හේතුව ARC සමඟ, ඔබ අමතන ක්‍රමයේ ප්‍රති result ලය සමඟ කුමක් කළ යුතු දැයි ධාවන කාලයට දැන ගැනීමට අවශ්‍ය වේ. ප්රතිඵලය කිසිම දෙයක් විය හැකි: void, int, char, NSString *, id, ආදිය ARC සාමාන්යයෙන් මෙම තොරතුරු ඔබ සමඟ වැඩ කරන්නේ වස්තුව වර්ගයේ ශීර්ෂ ලැබෙනවා. 3

ප්‍රතිලාභ අගය සඳහා ARC විසින් සලකා බැලිය යුතු කරුණු 4 ක් පමණි: 4

  1. වස්තුව නොවන වර්ග (නොතකා void, int, ආදී)
  2. වස්තු අගය රඳවා තබා, එය තවදුරටත් භාවිතා නොකරන විට මුදා හරින්න (සම්මත උපකල්පනය)
  3. තවදුරටත් භාවිතා නොකරන විට නව වස්තු අගයන් මුදා හරින්න ( init/ copyපවුලේ ක්‍රම හෝ ආරෝපිත ns_returns_retained)
  4. කිසිවක් නොකරන්න සහ ආපසු ලබා දුන් වස්තු වටිනාකම දේශීය විෂය පථයට වලංගු වේ යැයි උපකල්පනය කරන්න (අභ්‍යන්තරයේ බොහෝ මුදාහැරීමේ සංචිතය සිඳී යන තුරු, ආරෝපණය කර ඇත ns_returns_autoreleased)

methodForSelector:උපකල්පනය සඳහා වන ඇමතුම, එය කැඳවන ක්‍රමයේ ප්‍රතිලාභ අගය වස්තුවක් වන නමුත් එය රඳවා තබා ගැනීමට / මුදා හැරීමට නොහැකි වේ. එබැවින් ඉහත # 3 හි ඇති ආකාරයට ඔබේ වස්තුව මුදා හැරීමට අවශ්‍ය නම් ඔබට කාන්දුවක් නිර්මාණය විය හැකිය (එනම්, ඔබ අමතන ක්‍රමය නව වස්තුවක් ලබා දෙයි).

තේරීම්කරුවන් සඳහා ඔබ එම ආපසු voidහෝ වෙනත් වස්තු නොවන ඇමතුම් ලබා ගැනීමට උත්සාහ කරන්නේ නම් , ඔබට අනතුරු ඇඟවීම නොසලකා හැරීමට සම්පාදක විශේෂාංග සක්‍රීය කළ හැකි නමුත් එය භයානක විය හැකිය. ක්ලැන්ග් දේශීය විචල්‍යයන්ට පවරා නැති ප්‍රතිලාභ අගයන් හසුරුවන ආකාරය පිළිබඳ පුනරාවර්තන කිහිපයක් හරහා මම දැක ඇත්තෙමි. ARC සක්‍රීය කර ඇති විට ඔබට එය භාවිතා කිරීමට අවශ්‍ය නොවුවද ආපසු ලබා දුන් වස්තු අගය රඳවා තබා ගැනීමට සහ මුදා හැරීමට නොහැකි බවට කිසිදු හේතුවක් නැත methodForSelector:. සම්පාදකයාගේ දෘෂ්ටි කෝණයෙන් බලන කල, එය සියල්ලට පසු වස්තුවකි. එයින් අදහස් වන්නේ ඔබ අමතන ක්‍රමය, someMethodවස්තුවක් නොවන (ඇතුළුව void) ආපසු ලබා දෙන්නේ නම් , ඔබට කුණු කන්දක් අගයක් රඳවා තබා ගැනීම / මුදා හැරීම හා බිඳ වැටීම සමඟ අවසන් විය හැකි බවයි.

අතිරේක තර්ක

එක් සලකා බැලීමක් නම්, මෙය එකම අනතුරු ඇඟවීමක් වන අතර එම performSelector:withObject:ක්‍රමය පරාමිතීන් පරිභෝජනය කරන ආකාරය ප්‍රකාශ නොකිරීමත් සමඟ ඔබට සමාන ගැටළු වලට මුහුණ දිය හැකිය. පරිභෝජනය කරන ලද පරාමිතීන් ප්‍රකාශ කිරීමට ARC ඉඩ ලබා දෙන අතර, ක්‍රමය පරාමිතිය පරිභෝජනය කරන්නේ නම්, ඔබ අවසානයේදී පිල්ලියකට පණිවිඩයක් යවා බිඳ වැටෙනු ඇත. පාලම් වාත්තු කිරීම සමඟ මෙය වටා වැඩ කිරීමට ක්‍රම තිබේ, නමුත් ඇත්ත වශයෙන්ම IMPඉහත සහ ක්‍රියාකාරී දර්ශක ක්‍රමවේදය භාවිතා කිරීම වඩා හොඳය . පරිභෝජනය කරන ලද පරාමිතීන් කලාතුරකින් ගැටළුවක් වන බැවින්, මෙය මතු නොවනු ඇත.

ස්ථිතික තේරීම්

සිත්ගන්නා කරුණ නම්, සංඛ්‍යාත්මකව ප්‍රකාශයට පත් කරන ලද තේරීම් කාරක ගැන සම්පාදකයා පැමිණිලි නොකරනු ඇත:

[_controller performSelector:@selector(someMethod)];

එයට හේතුව සම්පාදකයාට තේරීම් කාරකය සහ වස්තුව පිළිබඳ සියලු තොරතුරු සම්පාදනය කිරීමේදී සැබවින්ම පටිගත කිරීමට හැකි වීමයි. එයට කිසිවක් ගැන උපකල්පන කිරීමට අවශ්‍ය නැත. (මම මීට වසරකට පෙර මූලාශ්‍රය බැලීමෙන් මෙය පරීක්ෂා කළෙමි, නමුත් දැන් යොමු කිරීමක් නොමැත.)

මර්දනය

මෙම අනතුරු ඇඟවීම යටපත් කිරීම අත්‍යවශ්‍ය සහ හොඳ කේත සැලසුමක් ගැන සිතීමට උත්සාහ කිරීමේදී, මම හිස්ව සිටිමි. මෙම අනතුරු ඇඟවීම නිශ්ශබ්ද කිරීම අවශ්‍ය වූ අත්දැකීමක් ඔවුන් සතුව තිබේ නම් කරුණාකර යමෙක් බෙදා ගන්න (සහ ඉහත කරුණු නිසි ලෙස හසුරුවන්නේ නැත).

තව

මෙය NSMethodInvocationහැසිරවීමට අවශ්‍යතාවයක් ගොඩනගා ගත හැකි නමුත් එසේ කිරීම සඳහා තවත් ටයිප් කිරීමක් අවශ්‍ය වන අතර එය මන්දගාමී වේ, එබැවින් එය කිරීමට සුළු හේතුවක් ඇත.

ඉතිහාසය

වූ විට performSelector:ක්රම පවුලේ පළමු අරමුණ සී එක් කරන ලදී, ARC පවතී නැත. ARC නිර්මාණය කරන අතරතුර, ඇපල් විසින් මෙම ක්‍රම සඳහා අනතුරු ඇඟවීමක් ජනනය කළ යුතු බව තීරණය කරන ලද්දේ නම් කරන ලද තේරීම් කාරකයක් හරහා අත්තනෝමතික පණිවිඩ යැවීමේදී මතකය හැසිරවිය යුතු ආකාරය පැහැදිලිව නිර්වචනය කිරීම සඳහා සංවර්ධකයින්ට වෙනත් ක්‍රම භාවිතා කිරීමට මඟ පෙන්වීම සඳහා ය. පරමාර්ථ-සී හි, අමු ශ්‍රිත දර්ශක මත සී ස්ටයිල් කැස්ට් භාවිතා කිරීමෙන් සංවර්ධකයින්ට මෙය කළ හැකිය.

ස්විෆ්ට් හදුන්වා දීමත් සමඟ Apple වාර්තා කර ඇත මෙම performSelector:"වලට අනාරක්ෂිත" ලෙස ක්රම පවුල සහ ඔවුන් ස්විෆ්ට් ලබා නැත.

කාලයත් සමඟ මෙම ප්‍රගතිය අපි දැක ඇත්තෙමු.

  1. පරමාර්ථ-සී අවසරයේ මුල් සංස්කරණ performSelector:(අතින් මතක කළමනාකරණය)
  2. ARC සමඟ පරමාර්ථ-සී භාවිතය සඳහා අනතුරු අඟවයි performSelector:
  3. ස්විෆ්ට ප්‍රවේශයක් නොමැති performSelector:අතර මෙම ක්‍රම “සහජයෙන්ම අනාරක්ෂිත” යැයි ලේඛනගත කරයි

කෙසේ වෙතත් නම් කරන ලද තේරීම් කාරකයක් මත පදනම්ව පණිවිඩ යැවීමේ අදහස “සහජයෙන්ම අනාරක්ෂිත” අංගයක් නොවේ. මෙම අදහස දීර් Ob කාලයක් තිස්සේ Objective-C මෙන්ම වෙනත් බොහෝ ක්‍රමලේඛන භාෂාවල සාර්ථකව භාවිතා කර ඇත.


1 සියලුම අරමුණ සී ක්රම සඟවා තර්ක දෙකක් තියෙනවා, selfහා _cmdඔබ ක්රමය කතා කළ බව නිසැකයෙන්ම එකතු වේ.

2 වන ඇමතුම් NULLසී දී මෙම මුර අපි වස්තුවක් ඇති බව පාලක වගකීම ඉදිරියේ සඳහා පරීක්ෂා කිරීම සඳහා භාවිතා කාර්යය ආරක්ෂිත නෑ. මේ නිසා, අපි කරන්නම් කියලා IMPසිට methodForSelector:(එය විය හැකි වුවත් _objc_msgForward, එම පණිවිඩය යොමු පද්ධතියට පිවිසුම්). මූලික වශයෙන්, ආරක්ෂකයා සිටින විට, අපට ඇමතීමට ශ්‍රිතයක් ඇති බව අපි දනිමු.

3 ඇත්ත වශයෙන්ම, ඔබ වස්තූන් ලෙස ප්‍රකාශ කළහොත් idසහ ඔබ සියලු ශීර්ෂයන් ආනයනය නොකරන්නේ නම් එය වැරදි තොරතුරු ලබා ගත හැකිය . සම්පාදකයා හොඳයි කියා සිතන කේතයේ බිඳවැටීම් සමඟ ඔබට අවසන් විය හැකිය. මෙය ඉතා දුර්ලභ ය, නමුත් සිදුවිය හැකිය. සාමාන්‍යයෙන් ඔබට අනතුරු ඇඟවීමක් ලැබෙනුයේ කුමන ක්‍රම දෙකෙන් එකක් තෝරා ගත යුතු දැයි නොදන්නා බවය.

4 දින ARC යොමු බලන්න රඳවා ආපසු වටිනාකම් සහ unretained ආපසු වටිනාකම් වැඩි විස්තර සඳහා.


ඔබේ කේතය රඳවා ගැනීමේ ගැටලුව විසඳන්නේ නම්, 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 *'නවතම Xcode භාවිතා කිරීමේදී "සංකීර්ණ උදාහරණය" දෝෂයක් ලබා දෙයි . (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;
අයිසැක් ඔසිපොවිච් ඩුනයෙව්ස්කි

1183

Xcode 4.2 හි LLVM 3.0 සම්පාදකයා තුළ ඔබට පහත පරිදි අනතුරු ඇඟවීම යටපත් කළ හැකිය:

#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]
);

සිදු කළ පණිවිඩයේ ප්‍රති result ලය ඔබට අවශ්‍ය නම්, ඔබට මෙය කළ හැකිය:

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

ප්‍රශස්තිකරණය කිසිවක් හැර වෙනත් දෙයකට සකසා ඇති විට මෙම ක්‍රමය මතක කාන්දු වීමට හේතු වේ.
එරික්

4
Ric එරික් නැත, ඔබ "initSomething" හෝ "newSomething" හෝ "somethingCopy" වැනි විහිලු ක්‍රම භාවිතා නොකරන්නේ නම් එය කළ නොහැක.
ඇන්ඩ්‍රි ටැරන්ට්සොව්

3
Ul ජූලියන් එය ක්‍රියාත්මක වන නමුත් එය සමස්ත ගොනුව සඳහාම අනතුරු ඇඟවීම අක්‍රිය කරයි - ඔබට එය අවශ්‍ය නොවනු ඇත. popසහ push-ප්‍රාග්මා සමඟ එය ඔතා ගැනීම වඩා පිරිසිදු හා වඩා ආරක්ෂිත වේ.
එමිල්

2
මේ සියල්ල කරන්නේ එය සම්පාදකයා නිහ ces කිරීමයි. මෙය ගැටළුව විසඳන්නේ නැත. තේරීම් කාරකය නොපවතී නම්, ඔබ බොහෝ සෙයින් ඉස්කුරුප්පු කර ඇත.
ඇන්ඩ්‍රා ටොඩොරෙස්කු

2
මෙය භාවිතා කළ යුත්තේ if ([_target respondsToSelector:_selector]) {සමාන හෝ සමාන තර්කනයකින් ඔතා ඇති විට පමණි .

208

මේ පිළිබඳ මගේ අනුමානය මෙයයි: තේරීම්කරු සම්පාදකයා නොදන්නා බැවින් ARC හට නිසි මතක කළමනාකරණය බලාත්මක කළ නොහැක.

ඇත්ත වශයෙන්ම, විශේෂිත සම්මුතියක් මගින් මතක කළමනාකරණය ක්‍රමයේ නමට බැඳී ඇති අවස්ථා තිබේ. විශේෂයෙන්, මම හිතනකොටත් පහසුව ඉදිකරන්නන් එදිරිව පසුබිම ක්රම; සම්මුතියෙන් කලින් ආපසු පැමිණීම ස්වයංක්‍රීයව මුදා හරින ලද වස්තුවකි; දෙවැන්න රඳවා ගත් වස්තුවකි. සම්මුතිය තේරීම්කරුගේ නම් මත පදනම් වේ, එබැවින් සම්පාදකයා තේරීම් කාරකය නොදන්නේ නම් එයට නිසි මතක කළමනාකරණ රීතිය ක්‍රියාත්මක කළ නොහැක.

මෙය නිවැරදි නම්, මතක කළමනාකරණය සම්බන්ධයෙන් සෑම දෙයක්ම හරි යැයි ඔබ සහතික කර ඇත්නම්, ඔබට ආරක්ෂිතව ඔබේ කේතය භාවිතා කළ හැකි යැයි මම සිතමි (උදා: ඔබේ ක්‍රම මඟින් ඔවුන් වෙන් කළ වස්තු ආපසු නොදෙනු ඇත).


5
පිළිතුරට ස්තූතියි, සිදුවන්නේ කුමක්දැයි බැලීමට මම මේ ගැන වැඩි විස්තර සොයා බලමි. අනතුරු ඇඟවීම මග හැර එය අතුරුදහන් කරන්නේ කෙසේද යන්න පිළිබඳ කිසියම් අදහසක් තිබේද? ආරක්ෂිත ඇමතුමක් සඳහා අනතුරු ඇඟවීම මගේ කේතයේ සදහටම තබා ගැනීමට මම අකමැතියි.
එඩ්වාඩෝ ස්කොස්

84
ඒ නිසා ඇපල් හි කෙනෙකුගෙන් ඔවුන්ගේ සංසදවලදී මට තහවුරු විය. අනාගත නිකුතු වලදී මෙම අනතුරු ඇඟවීම අක්‍රිය කිරීමට මිනිසුන්ට ඉඩ දීම සඳහා ඔවුන් අමතක වූ පෙරළියක් එකතු කරනු ඇත. ස්තූතියි.
එඩ්වාඩෝ ස්කොස්

5
මෙම පිළිතුර සමහර ප්‍රශ්න මතු කරයි, සම්මුතිය සහ ක්‍රම නාම මත පදනම්ව යමක් මුදා හැරිය යුත්තේ කවදාද යන්න තීරණය කිරීමට ARC උත්සාහ කරන්නේ නම්, එය “යොමු ගණන් කිරීම” කරන්නේ කෙසේද? ARC කේතය කිසියම් සම්මුතියක් අනුගමනය කරයි යැයි උපකල්පනය කරන්නේ නම්, ඔබ විස්තර කරන හැසිරීම මුළුමනින්ම අත්තනෝමතික ලෙසට වඩා සුළු වශයෙන් වඩා හොඳය.
aroth

8
සම්පාදනයේදී රඳවා තබා ගැනීම සහ මුදා හැරීම එකතු කිරීමේ ක්‍රියාවලිය ARC ස්වයංක්‍රීය කරයි. එය කසළ එකතු කිරීමක් නොවේ (ඒ නිසා එය ඇදහිය නොහැකි තරම් වේගවත් හා අඩු පිරිවැයක් දරයි). එය කිසිසේත්ම අත්තනෝමතික නොවේ. පෙරනිමි රීති පදනම් වී ඇත්තේ දශක ගණනාවක් තිස්සේ අඛණ්ඩව ක්‍රියාත්මක වන හොඳින් ස්ථාපිත ObjC සම්මුතීන් මත ය. __attributeඑහි මතක කළමනාකරණය පැහැදිලි කරන සෑම ක්‍රමයකටම පැහැදිලිව එකතු කිරීමේ අවශ්‍යතාව මෙයින් වළක්වයි . නමුත් මෙම රටාව නිසියාකාරව හැසිරවීමට අනුකූලයාට නොහැකි වේ (මෙය ඉතා සුලභ වූ නමුත් මෑත වසරවලදී වඩාත් ශක්තිමත් රටා සමඟ ප්‍රතිස්ථාපනය කර ඇත).
රොබ් නේපියර්

8
එබැවින් අපට තවදුරටත් ඇත්දළ වර්ගයක් නොතිබිය හැකි SELඅතර තත්වය අනුව විවිධ තේරීම්කරුවන් පත් කළ හැකිද? යා යුතු මාර්ගය, ගතික භාෂාව ...
නිකොලස් මාරි

121

ඔබගේ ව්‍යාපෘතියේ සැකසුම් ගොඩනඟන්න , වෙනත් අනතුරු ඇඟවීමේ කොඩි ( WARNING_CFLAGS) යටතේ, එකතු කරන්න
-Wno-arc-performSelector-leaks

දැන් ඔබ අමතන තේරීම් කාරකය ඔබේ වස්තුව රඳවා තබා ගැනීමට හෝ පිටපත් කිරීමට හේතු නොවන බවට වග බලා ගන්න.


12
සම්පූර්ණ ව්‍යාපෘතියට වඩා විශේෂිත ලිපිගොනු සඳහා ඔබට එකම ධජය එක් කළ හැකි බව සලකන්න. ඔබ ගොඩනැඟීමේ අදියර-> සම්පාදක ප්‍රභවයන් යටතේ බැලුවහොත්, ඔබට එක් ගොනුවකට සම්පාදක ධජ සැකසිය හැකිය (ARC වෙතින් ලිපිගොනු බැහැර කිරීම සඳහා ඔබට කිරීමට අවශ්‍ය පරිදි). මගේ ව්‍යාපෘතියේ එක් ගොනුවක් පමණක් තේරීම්කරුවන් මේ ආකාරයෙන් භාවිතා කළ යුතුය, එබැවින් මම එය බැහැර කර අනෙක් ඒවා අතහැර දැමුවෙමි.
මයිකල්

111

සම්පාදකයා අනතුරු ඇඟවීම ඉක්මවා යාමට ඉඩ දෙන තෙක් ක්‍රියාමාර්ගයක් ලෙස, ඔබට ධාවන කාලය භාවිතා කළ හැකිය

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

වෙනුවට

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

ඔයාට කරන්න වෙනවා

#import <objc/message.h>


8
ARC විසින් කොකෝවා සම්මුතීන් හඳුනාගෙන පසුව එම සම්මුතීන් මත පදනම්ව රඳවා තබා ගැනීම් සහ මුදා හැරීම් එකතු කරයි. C එම සම්මුතීන් අනුගමනය නොකරන නිසා, ARC මඟින් ඔබට අතින් මතක කළමනාකරණ ක්‍රම භාවිතා කිරීමට බල කරයි. ඔබ CF වස්තුවක් නිර්මාණය කරන්නේ නම්, ඔබ එය CFRelease () කළ යුතුය. ඔබ dispatch_queue_create () නම්, ඔබ dispatch_release () කළ යුතුය. බොටම් ලයින්, ඔබට ARC අනතුරු ඇඟවීම් වළක්වා ගැනීමට අවශ්‍ය නම්, ඔබට C වස්තු සහ අතින් මතක කළමනාකරණය භාවිතා කිරීමෙන් ඒවා වළක්වා ගත හැකිය. තවද, එම ගොනුවේ -fno-objc-arc සම්පාදක ධජය භාවිතා කිරීමෙන් ඔබට එක් ගොනුවකට ARC අක්‍රීය කළ හැකිය.
jluckyiv

8
වාත්තු නොකර, ඔබට බැහැ. Varargs පැහැදිලිවම ටයිප් කළ තර්ක ලැයිස්තුවකට සමාන නොවේ. එය සාමාන්‍යයෙන් අහම්බෙන් ක්‍රියාත්මක වනු ඇත, නමුත් "අහම්බෙන්" නිවැරදි යැයි මම නොසිතමි.
bbum

21
ඒක කරන්න, එපා [_controller performSelector:NSSelectorFromString(@"someMethod")];හා objc_msgSend(_controller, NSSelectorFromString(@"someMethod"));සමාන නොවේ! ක්‍රමයේ අත්සන නොගැලපීම් දෙස බලන්න සහ පරමාර්ථය-සී හි දුර්වල ටයිප් කිරීමේ විශාල දුර්වලතාවයක් ඔවුන් ගැටලුව ගැඹුරින් පැහැදිලි කරයි.
0xced

5
X 0xced මේ අවස්ථාවේ දී, එය හොඳයි. performanceSelector හි නිවැරදිව ක්‍රියා කළ හැකි ඕනෑම තේරීම් කාරකයක් සඳහා objc_msgSend විසින් ක්‍රම අත්සන නොගැලපීමක් නිර්මාණය නොකරනු ඇත: හෝ එහි ප්‍රභේදයන් වස්තූන් පරාමිතීන් ලෙස පමණක් ගන්නා බැවින්. ඔබගේ සියලු පරාමිතීන් දර්ශකයන් (වස්තූන් ඇතුළුව), දෙගුණයක් සහ එන්එස්ඉන්ටෙගර් / දිගු වන තාක් කල් සහ ඔබේ ආපසු පැමිණීමේ වර්ගය අවලංගු, දර්ශක හෝ දිගු නම්, objc_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. ඔබ බර පැටවීම අක්‍රිය කරන්නේ නම් සහ ඔබේ කේතයේ ප්‍රාග්මා රේඛා නැවත සක්‍රීය කිරීමට අවශ්‍ය නොවන්නේ නම් ප්‍රයෝජනවත් වේ.
deanWombourne

එය පහත රේඛාව නොසලකා හරිනු ඇත්ද?
hfossli

70

අමුතු නමුත් සත්‍යය: පිළිගත හැකි නම් (එනම් ප්‍රති result ලය අවලංගු වන අතර ධාවන පථ චක්‍රයට එක් වරක් ඉඩ දීමට ඔබට අවශ්‍ය නැත), මෙය ශුන්‍ය වුවද ප්‍රමාදයක් එක් කරන්න:

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

මෙය අනතුරු ඇඟවීම ඉවත් කරයි, අනුමාන වශයෙන් එය කිසිදු වස්තුවක් ආපසු ලබා දිය නොහැකි බවත් කෙසේ හෝ වැරදි ලෙස කළමනාකරණය කළ නොහැකි බවත් සම්පාදකයාට සහතික කරයි.


3
මෙය ඇත්ත වශයෙන්ම අදාළ මතක කළමනාකරණ ගැටළු නිරාකරණය කරන්නේ දැයි ඔබ දන්නවාද, නැතහොත් එයට සමාන ගැටළු තිබේද නමුත් මෙම කේතය සමඟ ඔබට අනතුරු ඇඟවීමට Xcode දක්ෂ නොවේද?
ආරොන් බ්‍රැගර්

මෙය අර්ථාන්විතව එකම දෙයක් නොවේ! PerformSelector භාවිතා කිරීම: withObject: AfterDelay: ධාවන පථයේ ඊළඟ ධාවනයේදී තේරීම් කාරකය සිදු කරයි. එමනිසා, මෙම ක්රමය වහාම ආපසු පැමිණේ.
ෆ්ලෝරියන්

10
Lor ෆ්ලෝරියන් ඇත්තෙන්ම එය එසේ නොවේ! මගේ පිළිතුර කියවන්න: පිළිගත හැකි නම් මම කියන්නේ ප්‍රති result ලය අවලංගු වන අතර ධාවන පථ චක්‍රයයි. ඒ තියෙන්නේ පළමු වාක්යය මගේ පිළිතුර.
matt

34

ඉහත දක්වා ඇති පිළිතුර මත පදනම්ව යාවත්කාලීන කළ සාර්වයක් මෙන්න. ආපසු ප්‍රකාශයක් සමඟ වුවද ඔබේ කේතය එතීමට මෙය ඔබට ඉඩ දිය යුතුය.

#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මෙය මෙන් නොව ඕනෑම ක්‍රමයක් මත ක්‍රියා කරයි.


4
මෙය ඇත්ත වශයෙන්ම අදාළ මතක කළමනාකරණ ගැටළු නිරාකරණය කරන්නේ දැයි ඔබ දන්නවාද, නැතහොත් එයට සමාන ගැටළු තිබේද නමුත් මෙම කේතය සමඟ ඔබට අනතුරු ඇඟවීමට Xcode දක්ෂ නොවේද?
ආරොන් බ්‍රැගර්

1
එය මතක කළමනාකරණ ගැටළු විසඳන බව ඔබට පැවසිය හැකිය; නමුත් එයට හේතුව එය මූලික වශයෙන් හැසිරීම නියම කිරීමට ඔබට ඉඩ සලසන බැවිනි. නිදසුනක් ලෙස, ආයාචනයට තර්ක රඳවා ගැනීමට හෝ නොකිරීමට ඔබට තෝරා ගත හැකිය. මගේ වර්තමාන දැනුමට අනුව, ඔබ කරන්නේ කුමක්දැයි ඔබ දන්නා බවත් වැරදි දත්ත ලබා නොදෙන බවත් විශ්වාස කිරීමෙන් පෙනී යා හැකි අත්සන නොගැලපීමේ ගැටලු විසඳීමට එය උත්සාහ කරයි. සියලුම චෙක්පත් ධාවන වේලාවේදී සිදු කළ හැකිදැයි මට විශ්වාස නැත. තවත් අදහස් දැක්වීමක සඳහන් වන පරිදි, mikeash.com/pyblog/… නොගැලපීම් වලට කළ හැකි දේ මනාව පැහැදිලි කරයි.
මිහයි ටිමාර්

20

හොඳයි, මෙහි පිළිතුරු ගොඩක් ඇත, නමුත් මෙය ටිකක් වෙනස් බැවින්, පිළිතුරු කිහිපයක් ඒකාබද්ධ කරමින් මම එය තැබිය යුතු යැයි සිතුවෙමි. මම එන්එස්ඕබෙක්ට් කාණ්ඩයක් භාවිතා කරමි, එය තේරීම්කරු අවලංගු වන බව තහවුරු කර ගැනීමටත්, සම්පාදකයා මර්දනය කිරීමටත් පරීක්ෂා කරයි. අනතුරු ඇඟවීම.

#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' _C_VOID මගින් ප්‍රතිස්ථාපනය කළ යුතුද? _C_VOID <objc / runtime.h> හි ප්‍රකාශයට පත් කෙරේ.
රික් රෙනිච්

16

පසු පරම්පරාව වෙනුවෙන්, මම මගේ තොප්පිය වළල්ලට විසි කිරීමට තීරණය කළෙමි :)

මෑතකදී මම තව තවත් ඈත් කරන ප්රතිව්යුහගත දුටු හිටියේ target/ selectorසුසමාදර්ශය, එවැනි ආදිය ප්රොටෝකෝල, කුට්ටි, ලෙස දේවල් පක්ෂව කෙසේ වෙතත්, එහි එක් ඩ්රොප් සඳහා ආදේශ කිරීම පමණි performSelectorමම දැන් කිහිප වතාවක් භාවිතා කර ඇති බව:

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

මේවා පිරිසිදු, ARC- ආරක්ෂිත සහ බොහෝ දුරට සමාන performSelectorනොවී ප්‍රතිස්ථාපනය කිරීමක් ලෙස objc_msgSend()පෙනේ.

IOS හි ඇනලොග් තිබේදැයි මට අදහසක් නැත.


6
මෙය ඇතුළත් කිරීම ගැන ස්තූතියි .. එය iOS වලින් ලබා ගත හැකිය : [[UIApplication sharedApplication] sendAction: to: from: forEvent:]. මම වරක් එය සොයා බැලුවෙමි, නමුත් ගතික ඇමතුමක් ලබා ගැනීම සඳහා ඔබේ වසම හෝ සේවාව මධ්‍යයේ UI ආශ්‍රිත පන්තියක් භාවිතා කිරීම අමුතු දෙයක් ලෙස හැඟේ .. මෙය ඇතුළත් කිරීමට ස්තූතියි!
එඩ්වාඩෝ ස්කොස්

2
ඊව්! එයට වැඩි පිරිවැයක් දැරීමට සිදුවේ (එයට ක්‍රමවේදය තිබේදැයි පරීක්ෂා කර එය නොමැති නම් ප්‍රතිචාර දාමය ඉහළට ගෙන යා යුතුය) සහ විවිධ දෝෂ හැසිරීම් ඇත (ප්‍රතිචාර දක්වන දාමය ඉහළට ගොස් කිසිවක් සොයාගත නොහැකි නම් ආපසු එවන්න එය හුදෙක් බිඳ වැටීම වෙනුවට ක්‍රමයට ප්‍රතිචාර දක්වයි). ඔබ අවශ්ය වන විට එය ද වැඩ කරන්නේ නැත idසිට-performSelector:...
ටීසී.

2
ctc. to:නිල් නොවේ නම් එය "ප්‍රතිචාර දක්වන දාමය ඉහළට" නොයනු ඇත . එය කලින් පරීක්ෂා කිරීමකින් තොරව ඉලක්කගත වස්තුව වෙත කෙලින්ම යයි. එබැවින් "වැඩි වැඩියෙන්" නොමැත. එය විශිෂ්ට විසඳුමක් නොවේ, නමුත් ඔබ දෙන හේතුව හේතුව නොවේ. :)
matt

15

මෙම ත්‍රෙඩ් එකේ මැට් ගැලෝවේගේ පිළිතුර එයට හේතුව පැහැදිලි කරයි:

පහත සඳහන් කරුණු සලකා බලන්න:

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

දැන්, පළමුවැන්න රඳවා තබා ගැනීමේ ගණන් 1 ක් සහිත වස්තුවක් ආපසු ලබා දෙන බව ARC දැන ගන්නේ කෙසේද?

ඔබ ප්‍රතිලාභ අගය නොසලකා හරිනවා නම් අනතුරු ඇඟවීම යටපත් කිරීම සාමාන්‍යයෙන් ආරක්ෂිත බව පෙනේ. Performanceelector වෙතින් රඳවා ගත් වස්තුවක් ලබා ගැනීමට ඔබට අවශ්‍ය නම් හොඳම පුහුණුව කුමක්දැයි මට විශ්වාස නැත - "එසේ නොකරන්න" හැර.


14

@ c-road මෙහි ගැටළු විස්තරය සමඟ නිවැරදි සබැඳිය සපයයි . PerformSelector මතකය කාන්දු වන විට ඔබට මගේ උදාහරණය පහත දැක්වේ.

@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;
}

මගේ උදාහරණයේ මතක කාන්දු වීමට හේතු වන එකම ක්‍රමය වන්නේ CopyDummyWithLeak ය. හේතුව, ARC නොදන්නා නිසා, පිටපත් සෙලෙක්ටර් විසින් රඳවා ගත් වස්තුව නැවත ලබා දෙයි.

ඔබ මතක කාන්දු කිරීමේ මෙවලම ක්‍රියාත්මක කරන්නේ නම් ඔබට පහත පින්තූරය දැකිය හැකිය: රූප විස්තරය මෙහි ඇතුළත් කරන්න ... සහ වෙනත් කිසිදු අවස්ථාවක මතක කාන්දුවීම් නොමැත: රූප විස්තරය මෙහි ඇතුළත් කරන්න


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, මම සාර්ව එකතු කළේ නැහැ. මගේ ප්‍රතිචාරයට කවුරුහරි එය එකතු කළා. පුද්ගලිකව, මම සාර්ව භාවිතා නොකරමි. කේතයේ විශේෂ අවස්ථාවක් වටා වැඩ කිරීම සඳහා ප්‍රාග්මාව පවතින අතර සිදුවෙමින් පවතින දේ පිළිබඳව ප්‍රායෝගිකව ඉතා පැහැදිලිව හා සෘජු වේ. මම කැමතියි ඒවා සැඟවීමට හෝ සාර්ව පිටුපස වියුක්ත කිරීමට වඩා ඒවා තැනින් තැන තබා ගැනීමට, නමුත් එය මා පමණි. වයි.එම්.එම්.වී.
ස්කොට් තොම්සන්

@ ස්කොට් තොම්සන් එය සාධාරණයි. මට නම් මගේ කේත පදනම හරහා මෙම සාර්ව සෙවීම පහසු වන අතර සාමාන්‍යයෙන් මම යටින් පවතින ගැටලුව සමඟ කටයුතු කිරීම සඳහා නිශ්ශබ්ද නොවන අනතුරු ඇඟවීමක් එක් කරමි.
බෙන් ෆ්ලින්

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
වචන ඉතා වැරදිය. ආරක්ෂිත මාර්ග කිසිසේත් අනතුරුදායක නොවේ. එය අනතුරු ඇඟවීම ව්‍යංගයෙන් සඟවන හෙයින් එය වඩාත් භයානක ය.
බ්‍රයන් චෙන්

අපහාස නොකිරීමට මම වචන නිවැරදි කරමි, නමුත් මම මගේ වචනයට එකඟව සිටිමි. නිශ්ශබ්ද කිරීමේ අනතුරු ඇඟවීම පිළිගත හැකි එකම අවස්ථාව මා සතුව කේතය නොමැති නම් පමණි. සියලු ප්‍රතිවිපාක තේරුම් නොගෙන කිසිදු ඉංජිනේරුවෙකුට නිශ්ශබ්ද කේතය ආරක්ෂිතව පවත්වා ගත නොහැක, එයින් අදහස් කරන්නේ මෙම තර්කය කියවිය හැකි අතර මෙම ක්‍රියාව සරල අවදානම් සහිත ය; විශේෂයෙන් ඔබ 12, සරල ඉංග්‍රීසි, ශක්තිමත් විකල්ප සලකා බැලුවහොත්.
ස්විෆ්ට්ආර්කිටෙක්ට්

1
ඔබට මගේ අදහස තේරුණේ නැහැ. අනතුරු ඇඟවීම නිහ to කිරීමට භාවිතා performSelectorOnMainThreadකිරීම හොඳ ක්‍රමයක් නොවන අතර එය අතුරු ආබාධ ඇති කරයි. (එය මතක කාන්දු වීම විසඳන්නේ නැත) අමතර #clang diagnostic ignored පැහැදිලිවම අනතුරු ඇඟවීම ඉතා පැහැදිලිව යටපත් කරයි.
බ්‍රයන් චෙන්

තෝරා නොගත් - (void)ක්‍රමයක් මත තේරීම් කාරකයක් ඉටු කිරීම සැබෑ ගැටළුව බව ඇත්ත.
ස්විෆ්ට්ආර්කිටෙක්ට්

සහ ඔබ මේ හරහා බහුවිධ තර්ක ඇති තේරීම් කාරයෙකු අමතා එකම වේලාවක ආරක්ෂිත වන්නේ කෙසේද? W ස්විෆ්ට් ආර්කිටෙක්ට්
කැටලින්

4

ඔබ ARC භාවිතා කරන නිසා ඔබ iOS 4.0 හෝ ඊට පසු භාවිතා කළ යුතුය. මෙයින් අදහස් කරන්නේ ඔබට කුට්ටි භාවිතා කළ හැකි බවයි. ඔබ ඉටු කිරීමට තේරීම් කාරකය මතක තබා ගැනීම වෙනුවට අවහිරයක් ගත්තේ නම්, ඇත්ත වශයෙන්ම සිදුවන්නේ කුමක්ද යන්න වඩා හොඳින් සොයා ගැනීමට ARC හට හැකි වනු ඇති අතර අහම්බෙන් මතක කාන්දුවක් හඳුන්වා දීමේ අවදානම ඔබ විසින් ක්‍රියාත්මක කළ යුතු නොවේ.


ඇත්ත වශයෙන්ම, බ්ලොක් මඟින් ARC විසින් විසඳන්නේ නැති රඳවා ගැනීමේ චක්‍රයක් අහම්බෙන් නිර්මාණය කිරීම ඉතා පහසු කරයි. ඔබ තවමත් selfඅයිවරයක් හරහා ව්‍යංගයෙන් භාවිතා කරන විට (උදා: ivarඒ වෙනුවට self->ivar) සම්පාදක අනතුරු ඇඟවීමක් තිබෙන්නට ඇතැයි මම ප්‍රාර්ථනා කරමි .
ටී.සී.

ඔබ අදහස් කළේ -විම්පිස්ට්-රඳවා තබා ගැනීම-ස්වයං?
OrangeDog

2

බ්ලොක් ප්රවේශය භාවිතා කරනවා වෙනුවට, මට ගැටළු කිහිපයක් ලබා දුන්නේය:

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

මම මේ ආකාරයට NSInvocation භාවිතා කරමි:

    -(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

ඔබේ පන්තියේ ඔබේ තේරීම්කරු අමතන්න, එවිට ඔබට ropproperty එකක් ඇත.

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

ඔබට @selector(doSomethingWithObject:)MyObject හි උදාහරණයක් ඇමතීමට අවශ්‍ය වූ විට , මෙය කරන්න:

[self.source doSomethingWithObject:object];

2
හේයි වු, ස්තූතියි, නමුත් ධාවන කාලය තුළ ඔබට ඇමතිය යුත්තේ කුමන තේරීම් කාරකයදැයි ඔබ නොදන්නා විට NSSelectorFromString භාවිතා කිරීමේ කාරණයයි.
එඩ්වාඩෝ ස්කොස්
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.