„PerformSelector“ gali sukelti nuotėkį, nes jo selektorius nežinomas.

Iš ARC kompiliatoriaus gaunu tokį įspėjimą:

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

Štai ką aš darau:

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

Kodėl gaunu šį įspėjimą? Suprantu, kad kompiliatorius negali patikrinti, ar selektorius yra ar ne, bet kodėl tai gali sukelti nuotėkį? Ir kaip aš galiu pakeisti savo kodą, kad nebebūtum šio įspėjimo?

1146
10 авг. nustatė Eduardo Scoz 10 rug . 2011-08-10 23:23 '11 11:23 PM 2011-08-10 23:23
@ 20 atsakymų

Sprendimas

Kompiliatorius apie tai įspėja dėl bet kokios priežasties. Labai retai šis įspėjimas turėtų būti paprasčiausiai ignoruojamas ir lengvai apeinamas. Štai kaip:

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

Arba sunkiau (nors ir sunku skaityti be apsaugos):

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

Aprašymas

Tai, kas čia vyksta, paprašo valdiklio C funkcijų rodyklės už valdiklį atitinkantį metodą. Visi „ NSObject atsako į methodForSelector: bet jūs taip pat galite naudoti class_getMethodImplementation objektyvo-C vykdymo metu (naudinga, jei turite tik protokolą, pvz., id<SomeProto> ). Šie funkcijų rodikliai vadinami IMP s ir yra paprastos nuorodos į typedef ed ( id (*IMP)(id, SEL, ...) ) 1 funkciją. Tai gali būti arti faktinio metodo parašo, bet ne visada tiksliai atitinka.

Kai turėsite IMP , turite nukreipti jį į funkcijų žymeklį, kuris apima visas detales, kurių reikia ARC (įskaitant du paslėptus argumentus, self ir _cmd kiekvieno skambučio į _cmd C metodą). Tai apdorojama trečiojoje eilutėje ( (void *) dešinėje pusėje), tiesiog informuoja kompiliatorių, kad žinote, ką darote, ir nesukurkite įspėjimo, nes žymeklio tipai nesutampa.

Galiausiai skambinate funkcijų rodykle 2 .

Išsamus pavyzdys

Kai selektorius priima argumentus arba grąžina vertę, turite šiek tiek pakeisti situaciją:

 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; 

Priežastys dėl įspėjimo

Šio įspėjimo priežastis yra ta, kad su ARC vykdymo laikas turi žinoti, ką daryti su to metodo rezultatu, kurį skambinate. Rezultatas gali būti bet koks: void , int , char , NSString * , id ir tt ARC paprastai gauna šią informaciją iš objekto antraštės, kurioje dirbate. 3

Yra tik 4 dalykai, kuriuos ARC atsižvelgs į grąžos vertę: 4

  • Ignoruoti ne objektus ( void , int ir tt)
  • Išsaugokite objekto vertę, tada atleiskite, kai jis nebenaudojamas (standartinė prielaida)
  • Atleiskite naujas objekto reikšmes, kai jos nebenaudojamos (metodai ns_returns_retained / copy šeimoje arba susiję su ns_returns_retained )
  • Nieko nedarykite ir darykite prielaidą, kad grąžinto objekto vertė bus galiojanti vietinėje vietovėje (kol bus išnaudotas vidinis išleidimo ns_returns_autoreleased , priskirtas ns_returns_autoreleased )

Skambinimo methodForSelector: daroma prielaida, kad metodo, kurį jis methodForSelector: , grąžinimo reikšmė yra objektas, tačiau jo nėra. Tokiu būdu, galite sukurti nuotėkį, jei tikitės, kad jūsų objektas bus paleistas, kaip nurodyta aukščiau Nr. 3 (tai reiškia, kad jūsų paskambintas metodas grąžina naują objektą).

Pasirinktuvams, kuriuos bandote skambinti grąžinimo void ar kitiems neobjektams, galite įtraukti kompiliatoriaus funkcijas, kad ignoruotumėte šį įspėjimą, tačiau jis gali būti pavojingas. Matiau, kad „C>methodForSelector: grąžinto objekto methodForSelector: net jei nenorite jo naudoti. Kompiliatoriaus požiūriu tai yra objektas. Tai reiškia, kad jei metodas, kurį skambinate, someMethod , negrąžina objekto (įskaitant someMethod ), galite gauti šiukšlių žymeklio vertę, kuri bus išsaugota / išleista ir dirbama.

Papildomi argumentai

Vienas iš svarstymų yra tas, kad jis bus tas pats įspėjimas su „ performSelector:withObject: ir jūs galite susidurti su panašiomis problemomis nedeklaruodami, kaip šis metodas naudoja parametrus. ARC leidžia jums deklaruoti vartojimo parametrus , o jei šis metodas naudoja šį parametrą, tikriausiai baigsite siųsti zombių pranešimą ir gedimą. Yra būdų, kaip tai pasiekti su tilto liejimu, bet iš tikrųjų būtų geriau naudoti aukščiau esančias IMP metodikas ir funkcijų rodyklės funkcijas. Kadangi suvartoti parametrai retai yra problema, tai vargu ar įmanoma.

Statinis selektorius

Įdomu tai, kad kompiliatorius nesiskundžia dėl statinių deklaracijų, kurios yra paskelbtos statiniu būdu:

 [_controller performSelector:@selector(someMethod)]; 

Taip yra todėl, kad kompiliatorius gali rengti visą informaciją apie selektorių ir objektą kompiliavimo metu. Nereikia daryti jokių prielaidų apie viską. (Aš patikrinau prieš metus, žiūrėdamas į šaltinį, bet dabar aš neturiu nuorodos.)

Slopinimas

Bandydamas galvoti apie situaciją, kai būtinas šio įspėjimo slopinimas ir geras kodo dizainas, aš sugalvoju. Kažkas, prašome pasidalinti, jei jie turi patirties, kai reikėjo nutildyti šį įspėjimą (ir virš jo jis neveikia tinkamai).

Skaityti daugiau

Taip pat galite sukurti „ NSMethodInvocation kad galėtumėte tai apdoroti, tačiau tam reikia daug daugiau teksto įvedimo ir taip pat lėčiau, todėl nėra jokios priežasties.

Istorija

Kai performSelector: metodų šeima pirmą kartą buvo įtraukta į Objective-C, ARC neegzistavo. Kuriant ARC, „Apple“ nusprendė, kad šiems metodams turėtų būti sukurtas įspėjimas, kaip būdas nukreipti kūrėjus naudoti kitas priemones, kad būtų galima aiškiai nustatyti, kaip atmintis turėtų būti tvarkoma siunčiant savavališkus pranešimus naudojant pavadinimą. „Objective-C“ kūrėjai gali tai padaryti naudodamiesi „C“ stiliaus liejimu į nukreipimus į žaliavas.

Įdiegus „Swift“, „Apple“ dokumentavoperformSelector: “ metodų šeimą performSelector: „natūraliai nesaugus“ ir „Swift“ nėra.

Laikui bėgant matėme šį progresą:

  • Ankstyvosios „Objective-C“ versijos leidžia performSelector: (rankinis atminties valdymas)
  • „Objective-C“ su ARC įspėjimais, kad galėtumėte naudoti „ performSelector:
  • „Swift“ neturi prieigos prie „ performSelector: ir dokumentuoja šiuos metodus kaip „natūraliai nesaugus“

Idėja siųsti pranešimus pagal pavadinimą nėra „nesaugi būdinga“ funkcija. Ši idėja sėkmingai naudojama ilgą laiką „Objective-C“, taip pat daugelyje kitų programavimo kalbų.


1 Visi „Objective-C“ metodai turi du paslėptus argumentus, self ir _cmd , kurie netiesiogiai pridedami, kai vadinamas metodas.

2 Skambinimas į NULL funkciją nėra saugus C. Apsauga, naudojama tikrinant valdiklio buvimą, užtikrina, kad mes turime objektą. Todėl žinome, kad mes gausime IMPmethodForSelector: (nors tai gali būti _objc_msgForward , rašykite į pranešimų perdavimo sistemą). Iš esmės, turint omenyje apsaugą, žinome, kad turime funkciją, į kurią reikia skambinti.

3 Tiesą sakant, gali būti, kad ji gauna neteisingą informaciją, jei deklaruojate objektus kaip id , ir ne importuojate visų antraščių. Galite gauti kodą, kurį kompiliatorius mano teisingai, gedimo. Tai labai retai, bet gali atsitikti. Paprastai gausite įspėjimą, kad jis nežino, kuris iš dviejų metodų yra pasirenkamas.

4 Išsamesnės informacijos ieškokite ARC nuorodoje apie išsaugotas grąžinimo reikšmes ir negaliojančias grąžinimo reikšmes .

1107
19 нояб. Atsakymą pateikė wbyoung 19 lapkritis 2013-11-19 00:44 '13, 0:44 2013-11-19 00:44

„LLVM 3.0“ kompiliatoriuje, esančiame „Xcode 4.2“, galite atmesti šį įspėjimą:

 #pragma c> 

Jei keliose vietose atsiranda klaida ir norite naudoti „C“ makrokomandą paslėpti pragmas, galite nustatyti makrokomandą, kad būtų lengviau įspėti įspėjimą:

 #define SuppressPerformSelectorLeakWarning(Stuff) \ do { \ _Pragma("c> 
border=0

Galite naudoti tokį makrokomandą:

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

Jei reikia užbaigto pranešimo rezultato, galite tai padaryti:

 id result; SuppressPerformSelectorLeakWarning( result = [_target performSelector:_action withObject:self] ); 
1160
28 окт. atsakymas, kurį pateikė Scott Thompson, spalio 28 d 2011-10-28 22:30 '11 22:30 val. 2011-10-28 22:30

Mano prielaida apie tai yra tokia: kadangi selektorius kompiliatoriui nežinomas, ARC negali užtikrinti tinkamo atminties valdymo.

Tiesą sakant, yra kartų, kai atminties valdymas yra susietas su metodo pavadinimu konkrečia konvencija. Visų pirma, manau, kad patogumo konstruktoriai palyginti su metodais; pirmasis grąžinimas pagal sutartį automatiškai realizuotas objektas; paskutinis yra išsaugotas objektas. Konvencija grindžiama selektoriaus pavadinimais, todėl jei kompiliatorius nežino selektoriaus, jis negali užtikrinti tinkamo atminties valdymo.

Jei tai teisinga, manau, kad galite saugiai naudoti savo kodą, jei įsitikinsite, kad viskas tvarkinga su atminties valdymu (pvz., Kad jūsų metodai negrąžina jų skiriamų objektų).

205
10 авг. atsakymas suteiktas sergio 10 rug. 2011-08-10 23:43 '11 11:43 val. 2011-08-10 23:43

Projekto „Nustatymų nustatymai“ skyriuje „Kiti -Wno-arc-performSelector-leaks ) pridėkite -Wno-arc-performSelector-leaks

Dabar tik įsitikinkite, kad jūsų pasirinktas valdiklis nesukelia jūsų objekto išsaugojimo ar kopijavimo.

119
31 окт. atsakymas pateikiamas 0xced 31 okt. 2011-10-31 16:57 '11, 16:57, 2011-10-31 16:57

Kaip problemos sprendimo būdą, kol kompiliatorius nepaiso įspėjimo, galite naudoti vykdymo laiką

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

vietoj

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

Jums reikia

 #import <objc/message.h> 
109
16 авг. atsakymas duotas jluckyiv 16 rug . 2011-08-16 07:56 2011-11-08 07:56 07:56

Jei norite ignoruoti tik failo klaidą naudodami parametrų parinkiklį, pridėkite #pragma taip:

 #pragma c> 

Tai ignoruos įspėjimą dėl šios linijos, tačiau vis tiek leis tai atlikti visame projekte.

87
19 янв. atsakymą pateikė Barlow Tucker 19 sausis 2012-01-19 00:31 '12 0:31 2012-01-19 00:31

Keista, bet tiesa: jei tai priimtina (t. Y. Rezultatas yra negaliojantis ir jūs neprieštaraujate, kad paleistumėte ciklo ciklą vieną kartą), pridėkite vėlavimą, net jei jis yra nulis:

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

Tai pašalina įspėjimą, turbūt todėl, kad jis užtikrina kompiliatorių, kad nė vienas objektas negali būti grąžinamas ir kažkaip susipynęs.

66
11 нояб. atsakymas pateikiamas mat. 11 nov. 2012-11-11 22:19 '12, 10:19 PM 2012-11-11 22:19

Čia pateikiamas atnaujintas makrotas, pagrįstas pirmiau pateiktu atsakymu. Tai turėtų leisti jums įvesti kodą net ir sugrąžinimo ataskaitoje.

 #define SUPPRESS_PERFORM_SELECTOR_LEAK_WARNING(code) \ _Pragma("c> 
34
07 мая '13 в 17:58 2013-05-07 17:58 atsakymas pateikiamas 07 gegužės 13 d. 17:58 2013-05-07 17:58

Į šį kodą neįeina kompiliatoriaus vėliavos arba tiesioginiai skambučiai:

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

NSInvocation leidžia nustatyti kelis argumentus, kad, skirtingai nei „ performSelector tai veiks su bet kuriuo metodu.

30
01 февр. Benedict Cohen atsakymas 01 vasaris 2012-02-01 18:46 '12 at 6:46 2012-02-01 18:46

Na, čia yra daug atsakymų, bet kadangi tai yra šiek tiek kitokia, sujungus kelis atsakymus, aš maniau, kad juos įtrauksiu. Aš naudoju „NSObject“ kategoriją, kuri patikrina, ar selektorius grąžina tuščią vietą, ir taip pat slopina kompiliatoriaus įspėjimą.

 #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 c> 
20
21 февр. Atsakymą pateikė Chris Prince , vasario 21 d. 2014-02-21 07:32 '14 ne 7:32 2014-02-21 07:32

Dėl palikuonių aš nusprendžiau mesti skrybėlę į žiedą :)

Neseniai matiau vis daugiau restruktūrizavimo iš target / selector paradigmos, naudodamas tokius dalykus kaip protokolai, blokai ir tt Tačiau yra vienas „ performSelector pakeitimas, performSelector dabar naudoju kelis kartus:

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

Atrodo, kad tai yra švarus, saugus ARC ir beveik identiškas „ performSelector , neturintis didelės reikšmės objc_msgSend() .

Nors aš nežinau, ar yra lygiavertė informacija iOS.

16
26 февр. Atsakymą pateikė Patrick Perini , vasario 26 d. 2012-02-26 07:17 '12 at 7:17 2012-02-26 07:17

Matt Galloway atsakymas į šį srautą paaiškina, kodėl:

Apsvarstykite šiuos dalykus:

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

Dabar, kaip ARC gali žinoti, kad pirmasis grąžina objektą, išsaugodamas skaičių 1, o antrasis grąžina objektą, kuris yra automatiškai įdiegtas?

Atrodo, kad saugu atmesti įspėjimą, jei ignoruojate grąžinimo vertę. Nežinau, kas yra geriausia, jei iš tikrųjų reikia iš išsaugotojo objekto gauti iš performSelector - išskyrus „nedaryk“.

15
15 мая '12 в 23:17 2012-05-15 23:17 atsakymas duotas c roald gegužės 15 d., 23:17 2012-05-15 23:17

@ c-road suteikia teisingą nuorodą, kurioje aprašoma problema. Žemiau galite pamatyti mano pavyzdį, kai performSelector sukelia atminties nutekėjimą.

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

Vienintelis būdas, kuris sukelia atminties nutekėjimą mano pavyzdyje, yra „CopyDummyWithLeak“. Taip yra todėl, kad ARC nežino, kad copySelector grąžina išsaugotą objektą.

Jei paleisite „Memory Leak“ įrankį, pamatysite šį vaizdą: 2019

14
25 дек. Atsakymą pateikė Pavel Osipov gruodžio 25 d. 2012-12-25 13:23 '12 at 13:23 PM 2012-12-25 13:23

Padarykite „Scott Thomson“ makrokomandą universalesnį:

 // String expander #define MY_STRX(X) #X #define MY_STR(X) MY_STRX(X) #define MYSilenceWarning(FLAG, MACRO) \ _Pragma("c> 

Tada naudokite jį taip:

 MYSilenceWarning(-Warc-performSelector-leaks, [_target performSelector:_action withObject:self]; ) 
5
04 авг. Atsakymą pateikė Ben Flynn 04 rug. 2015-08-04 00:46 '15 - 0:46 2015-08-04 00:46

Kadangi naudojate ARC, turite naudoti „iOS 4.0“ arba naujesnę versiją. Tai reiškia, kad galite naudoti blokus. Jei vietoj to, kad nepamirškite, kad pasirinkėjas pasirinko jus, vietoj blokavimo, ARC galės geriau stebėti, kas iš tikrųjų vyksta, ir jums nereikės atsitiktinai patekti į atminties nutekėjimą.

4
23 нояб. Atsakymą davė pagyrimas lapkričio 23 d. 2011-11-23 05:33 '11, 5:33, 2011-11-23 05:33

Nepalikite įspėjimų!

Yra mažiausiai 12 alternatyvių sprendimų, kaip bendrauti su kompiliatoriumi.
Nors esate protingas pirmojo įgyvendinimo metu, keli Žemėje esantys inžinieriai gali sekti jūsų veiksmus, ir šis kodas galiausiai sulaužys.

Saugus maršrutas:

Visi šie sprendimai veiks su tam tikru skirtumu nuo jūsų pradinio tikslo. Tarkime, kad „ param gali būti nil jei norite:

Saugus maršrutas, tas pats konceptualus elgesys:

 // 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]]; 

Saugus maršrutas, šiek tiek kitoks elgesys:

(žr. šį atsakymą)
Vietoj [NSThread mainThread] naudokite bet kurią temą.

 // 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]]; 

Pavojingi maršrutai

Reikalingas tam tikras kompiliatoriaus nutildymas, kuris lūžs. Atkreipkite dėmesį, kad šiuo metu susidarė spragas.

 // AT YOUR OWN RISK [_controller performSelector:selector]; [_controller performSelector:selector withObject:anArgument]; [_controller performSelector:selector withObject:anArgument withObject:nil]; 
3
31 дек. Atsakymą pateikė „ SwiftArchitect“ gruodžio 31 d. 2015-12-31 06:58 '16 at 6:58 2015-12-31 06:58

Užuot naudojusi blokinį metodą, kuris man davė problemų:

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

Aš naudosiu NSIpaskyrimą, pavyzdžiui:

  -(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: atIndex:2]; [delegateInvocation invoke]; } 
2
21 мая '15 в 11:52 2015-05-21 11:52 atsakymas pateikiamas supersabbatui gegužės 21 d., 15 val. 11:52 2015-05-21 11:52

Jei jums nereikia perduoti jokių argumentų, yra lengva naudoti valueForKeyPath . Tai įmanoma net ir Class objektui.

 NSString *colorName = @"brightPinkColor"; id uicolor = [UIColor class]; if ([uicolor respondsToSelector:NSSelectorFromString(colorName)]){ UIColor *brightPink = [uicolor valueForKeyPath:colorName]; ... } 
1
15 февр. Atsakymą pateikė arsenijus vasario 15 d. 2017-02-15 07:08 '17, 07:08 2017-02-15 07:08

Čia taip pat galite naudoti protokolą. Taigi, sukurkite tokį protokolą:

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