විසඳුමක්
සම්පාදකයා මේ ගැන අනතුරු අඟවන්නේ හේතුවක් ඇතුවයි. මෙම අනතුරු ඇඟවීම නොසලකා හැරීම ඉතා කලාතුරකිනි, එය වටා වැඩ කිරීම පහසුය. මෙන්න කොහොමද:
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>
). මෙම ශ්රිත දර්ශකයන් IMP
s ලෙස හැඳින්වෙන අතර සරල 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
- වස්තුව නොවන වර්ග (නොතකා
void
, int
, ආදී)
- වස්තු අගය රඳවා තබා, එය තවදුරටත් භාවිතා නොකරන විට මුදා හරින්න (සම්මත උපකල්පනය)
- තවදුරටත් භාවිතා නොකරන විට නව වස්තු අගයන් මුදා හරින්න (
init
/ copy
පවුලේ ක්රම හෝ ආරෝපිත ns_returns_retained
)
- කිසිවක් නොකරන්න සහ ආපසු ලබා දුන් වස්තු වටිනාකම දේශීය විෂය පථයට වලංගු වේ යැයි උපකල්පනය කරන්න (අභ්යන්තරයේ බොහෝ මුදාහැරීමේ සංචිතය සිඳී යන තුරු, ආරෝපණය කර ඇත
ns_returns_autoreleased
)
methodForSelector:
උපකල්පනය සඳහා වන ඇමතුම, එය කැඳවන ක්රමයේ ප්රතිලාභ අගය වස්තුවක් වන නමුත් එය රඳවා තබා ගැනීමට / මුදා හැරීමට නොහැකි වේ. එබැවින් ඉහත # 3 හි ඇති ආකාරයට ඔබේ වස්තුව මුදා හැරීමට අවශ්ය නම් ඔබට කාන්දුවක් නිර්මාණය විය හැකිය (එනම්, ඔබ අමතන ක්රමය නව වස්තුවක් ලබා දෙයි).
තේරීම්කරුවන් සඳහා ඔබ එම ආපසු void
හෝ වෙනත් වස්තු නොවන ඇමතුම් ලබා ගැනීමට උත්සාහ කරන්නේ නම් , ඔබට අනතුරු ඇඟවීම නොසලකා හැරීමට සම්පාදක විශේෂාංග සක්රීය කළ හැකි නමුත් එය භයානක විය හැකිය. ක්ලැන්ග් දේශීය විචල්යයන්ට පවරා නැති ප්රතිලාභ අගයන් හසුරුවන ආකාරය පිළිබඳ පුනරාවර්තන කිහිපයක් හරහා මම දැක ඇත්තෙමි. ARC සක්රීය කර ඇති විට ඔබට එය භාවිතා කිරීමට අවශ්ය නොවුවද ආපසු ලබා දුන් වස්තු අගය රඳවා තබා ගැනීමට සහ මුදා හැරීමට නොහැකි බවට කිසිදු හේතුවක් නැත methodForSelector:
. සම්පාදකයාගේ දෘෂ්ටි කෝණයෙන් බලන කල, එය සියල්ලට පසු වස්තුවකි. එයින් අදහස් වන්නේ ඔබ අමතන ක්රමය, someMethod
වස්තුවක් නොවන (ඇතුළුව void
) ආපසු ලබා දෙන්නේ නම් , ඔබට කුණු කන්දක් අගයක් රඳවා තබා ගැනීම / මුදා හැරීම හා බිඳ වැටීම සමඟ අවසන් විය හැකි බවයි.
අතිරේක තර්ක
එක් සලකා බැලීමක් නම්, මෙය එකම අනතුරු ඇඟවීමක් වන අතර එම performSelector:withObject:
ක්රමය පරාමිතීන් පරිභෝජනය කරන ආකාරය ප්රකාශ නොකිරීමත් සමඟ ඔබට සමාන ගැටළු වලට මුහුණ දිය හැකිය. පරිභෝජනය කරන ලද පරාමිතීන් ප්රකාශ කිරීමට ARC ඉඩ ලබා දෙන අතර, ක්රමය පරාමිතිය පරිභෝජනය කරන්නේ නම්, ඔබ අවසානයේදී පිල්ලියකට පණිවිඩයක් යවා බිඳ වැටෙනු ඇත. පාලම් වාත්තු කිරීම සමඟ මෙය වටා වැඩ කිරීමට ක්රම තිබේ, නමුත් ඇත්ත වශයෙන්ම IMP
ඉහත සහ ක්රියාකාරී දර්ශක ක්රමවේදය භාවිතා කිරීම වඩා හොඳය . පරිභෝජනය කරන ලද පරාමිතීන් කලාතුරකින් ගැටළුවක් වන බැවින්, මෙය මතු නොවනු ඇත.
ස්ථිතික තේරීම්
සිත්ගන්නා කරුණ නම්, සංඛ්යාත්මකව ප්රකාශයට පත් කරන ලද තේරීම් කාරක ගැන සම්පාදකයා පැමිණිලි නොකරනු ඇත:
[_controller performSelector:@selector(someMethod)];
එයට හේතුව සම්පාදකයාට තේරීම් කාරකය සහ වස්තුව පිළිබඳ සියලු තොරතුරු සම්පාදනය කිරීමේදී සැබවින්ම පටිගත කිරීමට හැකි වීමයි. එයට කිසිවක් ගැන උපකල්පන කිරීමට අවශ්ය නැත. (මම මීට වසරකට පෙර මූලාශ්රය බැලීමෙන් මෙය පරීක්ෂා කළෙමි, නමුත් දැන් යොමු කිරීමක් නොමැත.)
මර්දනය
මෙම අනතුරු ඇඟවීම යටපත් කිරීම අත්යවශ්ය සහ හොඳ කේත සැලසුමක් ගැන සිතීමට උත්සාහ කිරීමේදී, මම හිස්ව සිටිමි. මෙම අනතුරු ඇඟවීම නිශ්ශබ්ද කිරීම අවශ්ය වූ අත්දැකීමක් ඔවුන් සතුව තිබේ නම් කරුණාකර යමෙක් බෙදා ගන්න (සහ ඉහත කරුණු නිසි ලෙස හසුරුවන්නේ නැත).
තව
මෙය NSMethodInvocation
හැසිරවීමට අවශ්යතාවයක් ගොඩනගා ගත හැකි නමුත් එසේ කිරීම සඳහා තවත් ටයිප් කිරීමක් අවශ්ය වන අතර එය මන්දගාමී වේ, එබැවින් එය කිරීමට සුළු හේතුවක් ඇත.
ඉතිහාසය
වූ විට performSelector:
ක්රම පවුලේ පළමු අරමුණ සී එක් කරන ලදී, ARC පවතී නැත. ARC නිර්මාණය කරන අතරතුර, ඇපල් විසින් මෙම ක්රම සඳහා අනතුරු ඇඟවීමක් ජනනය කළ යුතු බව තීරණය කරන ලද්දේ නම් කරන ලද තේරීම් කාරකයක් හරහා අත්තනෝමතික පණිවිඩ යැවීමේදී මතකය හැසිරවිය යුතු ආකාරය පැහැදිලිව නිර්වචනය කිරීම සඳහා සංවර්ධකයින්ට වෙනත් ක්රම භාවිතා කිරීමට මඟ පෙන්වීම සඳහා ය. පරමාර්ථ-සී හි, අමු ශ්රිත දර්ශක මත සී ස්ටයිල් කැස්ට් භාවිතා කිරීමෙන් සංවර්ධකයින්ට මෙය කළ හැකිය.
ස්විෆ්ට් හදුන්වා දීමත් සමඟ Apple වාර්තා කර ඇත මෙම performSelector:
"වලට අනාරක්ෂිත" ලෙස ක්රම පවුල සහ ඔවුන් ස්විෆ්ට් ලබා නැත.
කාලයත් සමඟ මෙම ප්රගතිය අපි දැක ඇත්තෙමු.
- පරමාර්ථ-සී අවසරයේ මුල් සංස්කරණ
performSelector:
(අතින් මතක කළමනාකරණය)
- ARC සමඟ පරමාර්ථ-සී භාවිතය සඳහා අනතුරු අඟවයි
performSelector:
- ස්විෆ්ට ප්රවේශයක් නොමැති
performSelector:
අතර මෙම ක්රම “සහජයෙන්ම අනාරක්ෂිත” යැයි ලේඛනගත කරයි
කෙසේ වෙතත් නම් කරන ලද තේරීම් කාරකයක් මත පදනම්ව පණිවිඩ යැවීමේ අදහස “සහජයෙන්ම අනාරක්ෂිත” අංගයක් නොවේ. මෙම අදහස දීර් Ob කාලයක් තිස්සේ Objective-C මෙන්ම වෙනත් බොහෝ ක්රමලේඛන භාෂාවල සාර්ථකව භාවිතා කර ඇත.
1 සියලුම අරමුණ සී ක්රම සඟවා තර්ක දෙකක් තියෙනවා, self
හා _cmd
ඔබ ක්රමය කතා කළ බව නිසැකයෙන්ම එකතු වේ.
2 වන ඇමතුම් NULL
සී දී මෙම මුර අපි වස්තුවක් ඇති බව පාලක වගකීම ඉදිරියේ සඳහා පරීක්ෂා කිරීම සඳහා භාවිතා කාර්යය ආරක්ෂිත නෑ. මේ නිසා, අපි කරන්නම් කියලා IMP
සිට methodForSelector:
(එය විය හැකි වුවත් _objc_msgForward
, එම පණිවිඩය යොමු පද්ධතියට පිවිසුම්). මූලික වශයෙන්, ආරක්ෂකයා සිටින විට, අපට ඇමතීමට ශ්රිතයක් ඇති බව අපි දනිමු.
3 ඇත්ත වශයෙන්ම, ඔබ වස්තූන් ලෙස ප්රකාශ කළහොත් id
සහ ඔබ සියලු ශීර්ෂයන් ආනයනය නොකරන්නේ නම් එය වැරදි තොරතුරු ලබා ගත හැකිය . සම්පාදකයා හොඳයි කියා සිතන කේතයේ බිඳවැටීම් සමඟ ඔබට අවසන් විය හැකිය. මෙය ඉතා දුර්ලභ ය, නමුත් සිදුවිය හැකිය. සාමාන්යයෙන් ඔබට අනතුරු ඇඟවීමක් ලැබෙනුයේ කුමන ක්රම දෙකෙන් එකක් තෝරා ගත යුතු දැයි නොදන්නා බවය.
4 දින ARC යොමු බලන්න රඳවා ආපසු වටිනාකම් සහ unretained ආපසු වටිනාකම් වැඩි විස්තර සඳහා.