Я все еще новичок в 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
». Только не используйте его вместо того, чтобы выяснить настоящую причину предупреждения. ;)Для этого очень простого примера в вопросе
нет никакой разницы в том, что произойдет. doSomething будет синхронно выполняться объектом. Только doSomething - это очень простой метод, который ничего не возвращает и не требует никаких параметров.
было ли это что-то более сложное, например:
все станет сложнее, потому что [object doSomethingWithMyAge: 42];
больше нельзя вызывать с любым вариантом "performSelector", потому что все варианты с параметрами принимают только параметры объекта.
Селектор здесь будет "doSomethingWithMyAge:", но любая попытка
просто не компилируется. передача NSNumber: @ (42) вместо 42 тоже не поможет, потому что метод ожидает базовый тип C, а не объект.
Кроме того, есть варианты performSelector до 2-х параметров, не более. Хотя методы во много раз имеют гораздо больше параметров.
Я обнаружил, что хотя синхронные варианты performSelector:
всегда возвращать объект, я также смог вернуть простой BOOL или NSUInteger, и это сработало.
Одно из двух основных применений performSelector - динамическое составление имени метода, который вы хотите выполнить, как объяснялось в предыдущем ответе. Например
Другое использование - асинхронная отправка сообщения объекту, который будет выполнен позже в текущем цикле выполнения. Для этого есть несколько других вариантов performSelector.
(да, я собрал их из нескольких категорий классов Foundation, таких как NSThread, NSRunLoop и NSObject)
Каждый из вариантов имеет свое особое поведение, но все они имеют что-то общее (по крайней мере, когда для параметра waitUntilDone установлено значение NO). Вызов «performSelector» вернется немедленно, а сообщение объекту будет помещено в текущий цикл выполнения только через некоторое время.
Из-за отложенного выполнения - естественно, нет возвращаемого значения из метода селектора, следовательно, возвращаемое значение - (void) во всех этих асинхронных вариантах.
Надеюсь, я как-то прикрыл это ...
источник
@ennuikiller на высоте. По сути, динамически сгенерированные селекторы полезны, когда вы не знаете (и обычно не можете) знать имя метода, который вы будете вызывать при компиляции кода.
Одно ключевое отличие состоит в том, что
-performSelector:
и друзья (включая многопоточные и отложенные варианты ) несколько ограничены тем, что они предназначены для использования с методами с параметрами 0–2. Например, вызов-outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:
с 6 параметрами и возвращениеNSString
довольно громоздко и не поддерживается предоставленными методами.источник
NSInvocation
объект.performSelector:
все друзья принимают аргументы объекта, то есть вы не можете использовать их для вызова (например)setAlphaValue:
, потому что его аргумент - это число с плавающей запятой.Селекторы немного похожи на указатели функций в других языках. Вы используете их, когда во время компиляции не знаете, какой метод вы хотите вызвать во время выполнения. Также, как указатели на функции, они инкапсулируют только глагольную часть вызова. Если у метода есть параметры, их также необходимо передать.
An
NSInvocation
служит той же цели, за исключением того, что объединяет больше информации. Он не только включает глагольную часть, но также включает целевой объект и параметры. Это полезно, если вы хотите вызвать метод для определенного объекта с определенными параметрами не сейчас, а в будущем. Вы можете построить соответствующийNSInvocation
и запустить его позже.источник
Между ними есть еще одно тонкое различие.
Вот выдержка из документации Apple
"performSelector: withObject: afterDelay: выполняет указанный селектор в текущем потоке во время следующего цикла цикла выполнения и после необязательного периода задержки. Поскольку он ожидает до следующего цикла цикла выполнения, чтобы выполнить селектор, эти методы обеспечивают автоматическую мини-задержку от код, выполняемый в данный момент. Несколько селекторов в очереди выполняются один за другим в том порядке, в котором они были поставлены в очередь ».
источник
performSelector:withObject:afterDelay:
, но вопрос и ваш фрагмент используютperformSelector:
, а это совершенно другой метод. Из документации к нему: <quote>performSelector:
Метод эквивалентен отправкеaSelector
сообщения непосредственно получателю. </quote>performSelector/performSelector:withObject/performSelector:withObject:afterDelay
все вели себя одинаково, что было ошибкой.