Когда использовать responsesToSelector в objective-c

- (void)someMethod
{
    if ( [delegate respondsToSelector:@selector(operationShouldProceed)] )
    {
        if ( [delegate operationShouldProceed] )
        {
            // do something appropriate
        }
    }
}

documentation говорит:

Меры предосторожности необходимы только для необязательных методов в формальном протоколе или методах неофициального протокола

Что это значит? Если я использую формальный протокол, я могу просто использовать [delegate myMethod]?

Ответ 1

Вы используете его в значительной степени, только когда думаете, что вам нужно: проверить, реализует ли объект метод, который вы собираетесь вызывать. Обычно это делается, когда у вас есть необязательные методы или неофициальный протокол.

Я когда-либо использовал respondsToSelector, когда пишу код, который должен связываться с объектом-делегатом.

if ([self.delegate respondsToSelector:@selector(engineDidStartRunning:)]) {
        [self.delegate engineDidStartRunning:self];
    }

Иногда вы хотели бы использовать respondsToSelector для любого возвращаемого метода и id или generic NSObject, где вы не уверены, что класс возвращаемого объекта.

Ответ 2

Просто чтобы добавить к тому, что сказал @kubi, в другой раз я использую его, когда метод был добавлен в уже существующий класс в более новой версии фреймворков, но мне все еще нужно быть обратно совместимым. Например:

if ([myObject respondsToSelector:@selector(doAwesomeNewThing)]) {
  [myObject doAwesomeNewThing];
} else {
  [self doOldWorkaroundHackWithObject:myObject];
}

Ответ 3

Как упоминается kubi respondsToSelector, обычно используется, когда у вас есть экземпляр метода, который соответствует протоколу.

// Extend from the NSObject protocol so it is safe to call `respondsToSelector` 
@protocol MyProtocol <NSObject> 

// @required by default
- (void) requiredMethod;

@optional

- (void)optionalMethod;

@end

Учитывая и экземпляр этого протокола, мы можем безопасно вызвать любой требуемый метод.

id <MyProtocol> myObject = ... 
[myObject requiredMethod];

Однако необязательные методы могут быть или не быть реализованы, поэтому вам нужно проверить их во время выполнения.

if ([myObject respondsToSelector:@selector(optionalMethod)]) 
{
     [myObject optionalMethod];
}

Выполнение этого предотвратит сбой с непризнанным селектором.


Кроме того, вы должны объявлять протоколы как расширение NSObjects, т.е.

@protocol MyProtocol <NSObject> 

Это потому, что протокол NSObject объявляет селектор respondsToSelector:. В противном случае XCode подумает, что это небезопасно.

Ответ 4

Старый вопрос, но я научился быть очень осторожным с использованием таких вещей, как addTarget: @selector (fu:), потому что имя метода не проверено и не включено в рефакторинг XCODE. Это уже вызвало у меня неприятности. Итак, теперь я сделал привычкой всегда встраивать такие вещи, как addTarget или addObserver, в responsesToSelector-Check, например:

if([self respondsToSelector:@selector(buttonClicked:)]){
    [self.button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
}else{
    DebugLog(@"Warning - a class or delegate did not respond to selector in class %@", self);
} 

Я знаю, что это не очень элегантно, но я бы скорее добавил код шаблона, чем неожиданное падение моих приложений в App Store.