Я все ще є новим для Objective-C, і мені цікаво, в чому різниця між наступними двома твердженнями?
[object performSelector:@selector(doSomething)];
[object doSomething];
Я все ще є новим для Objective-C, і мені цікаво, в чому різниця між наступними двома твердженнями?
[object performSelector:@selector(doSomething)];
[object doSomething];
Відповіді:
В основному PerformSelector дозволяє динамічно визначати, яким селектором викликати селектор на даному об'єкті. Іншими словами, селектор не потрібно визначати до часу виконання.
Таким чином, хоча вони є рівнозначними:
[anObject aMethod];
[anObject performSelector:@selector(aMethod)];
Друга форма дозволяє зробити це:
SEL aSelector = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector: aSelector];
перш ніж надіслати повідомлення.
performSelector:
- це те, що ви, мабуть, робите лише в тому випадку, якщо реалізуєте цільові дії у своєму класі. Братів performSelectorInBackground:withObject:
і сестер performSelectorOnMainThread:withObject:waitUntilDone:
часто корисніші. Для нерестування фонової нитки та для виклику результатів до головної нитки із зазначеної фонової нитки.
performSelector
також корисно для придушення компіляційних попереджень. Якщо ви знаєте, що метод існує (як, наприклад, після використання respondsToSelector
), він зупинить Xcode від "не може відповісти your_selector
". Просто не використовуйте його замість того, щоб з’ясувати справжню причину попередження. ;)
Для цього дуже базового прикладу в питанні,
[object doSomething];
[object performSelector:@selector(doSomething)];
немає різниці в тому, що буде. doSomething буде синхронно виконано об'єктом. Тільки "doSomething" - це дуже простий метод, який нічого не повертає і не вимагає ніяких параметрів.
це було щось трохи складніше, як-от:
(void)doSomethingWithMyAge:(NSUInteger)age;
все ускладнюватиметься, тому що [object doSomethingWithMyAge: 42];
більше не можна викликати жоден варіант "performSelector", оскільки всі варіанти з параметрами приймають лише параметри об'єкта.
Селектор тут буде "doSomethingWithMyAge:", але будь-яка спроба
[object performSelector:@selector(doSomethingWithMyAge:) withObject:42];
просто не збирається. передача NSNumber: @ (42) замість 42, також не допоможе, оскільки метод очікує базового типу C - не об'єкта.
Крім того, існують варіанти performSelector до 2 параметрів, не більше. У той час як методи багато разів мають набагато більше параметрів.
Я з'ясував, що хоча і синхронні варіанти performSelector:
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
Завжди повертайте об'єкт, я також міг повернути простий BOOL або NSUInteger, і він спрацював.
Одне з двох основних напрямків виконанняSelector - динамічно складати назву методу, який потрібно виконати, як пояснено в попередній відповіді. Наприклад
SEL method = NSSelectorFromString([NSString stringWithFormat:@"doSomethingWithMy%@:", @"Age");
[object performSelector:method];
Інше використання полягає в асинхронному відправленні повідомлення на об'єкт, яке буде виконано пізніше на поточному циклі запуску. Для цього існує кілька інших варіантів performSelector.
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
- (void)performSelector:(SEL)aSelector target:(id)target argument:(id)arg order:(NSUInteger)order modes:(NSArray *)modes;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg;
(так, я зібрав їх з декількох категорій класів Foundation, таких як NSThread, NSRunLoop та NSObject)
Кожен з варіантів має свою особливу поведінку, але всі вони поділяють щось спільне (принаймні, коли функція waitUntilDone встановлена на НІ). Виклик "performSelector" повернеться негайно, а повідомлення на об'єкт буде розміщено на поточному циклі через деякий час.
Через затримку виконання - природно, значення повернення не доступне у методі селектора, отже, - (недійсне) значення повернення у всіх цих асинхронних варіантах.
Сподіваюся, я якось висвітлював це ...
@ennuikiller не ввімкнено. В основному, динамічно згенеровані селектори корисні для тих випадків, коли ви не знаєте (і зазвичай не можете) назви методу, до якого ви будете викликати, коли компілюєте код.
Ключова відмінність полягає в тому, що -performSelector:
друзі (включаючи багатопотокові та затримані варіанти ) дещо обмежені тим, що вони розроблені для використання з методами з параметрами 0-2. Наприклад, дзвінки -outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:
з 6 параметрами і повернення NSString
значень досить непрості, і не підтримуються наданими методами.
NSInvocation
об’єкт.
performSelector:
і друзі приймають об'єктивні аргументи, тобто ви не можете використовувати їх для виклику (наприклад) setAlphaValue:
, оскільки його аргумент є плаваючою.
Селектори трохи схожі на функціональні вказівники іншими мовами. Ви використовуєте їх, коли під час компіляції не знаєте, який метод потрібно зателефонувати під час виконання. Також, як і покажчики функцій, вони лише інкапсулюють частину дієслова виклику. Якщо у методу є параметри, вам потрібно буде також їх передавати.
Служба NSInvocation
служить подібній меті, за винятком того, що вона пов'язує разом більше інформації. Вона не тільки включає в себе частину дієслова, вона також включає цільовий об'єкт і параметри. Це корисно, коли ви хочете викликати метод на певному об'єкті з певними параметрами не зараз, а в майбутньому. Ви можете побудувати відповідний NSInvocation
і звільнити його пізніше.
Є ще одна тонка різниця між ними.
[object doSomething]; // is executed right away
[object performSelector:@selector(doSomething)]; // gets executed at the next runloop
Ось уривок з Apple Documentation
"performSelector: withObject: afterDelay: Виконує вказаний селектор на поточному потоці протягом наступного циклу циклу запуску та після необов'язкового періоду затримки. Оскільки він чекає, поки наступний цикл циклу запуску виконає селектор, ці методи забезпечують автоматичну міні-затримку з код, який виконується в даний час. Кілька селекторів у черзі виконуються один за одним у тому порядку, в якому вони стояли в черзі. "
performSelector:withObject:afterDelay:
, але питання та ваш фрагмент використовуються performSelector:
- це зовсім інший метод. З документів для цього: <quote> performSelector:
Метод еквівалентний відправці aSelector
повідомлення безпосередньо одержувачу. </quote>
performSelector/performSelector:withObject/performSelector:withObject:afterDelay
всі поводилися однаково, що було помилкою.