Соответствие списку протоколов

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

Есть ли способ проверить, соответствует ли он какому-либо из этих 4 протоколов, не выполняя связки или операторов в моем if?

Можете ли вы сделать массив протоколов?

2 ответа

Решение

Конечно, вы можете сделать массив протоколов:

NSArray *protocols = @[@protocol(UIApplicationDelegate),
    @protocol(UIImagePickerControllerDelegate),
    @protocol(UIScrollViewDelegate),
    @protocol(NSFileManagerDelegate)];

Затем вы можете проверить, что какой-то объект соответствует всем им:

UIViewController *vc = ...;
for (Protocol *protocol in protocols) {
    if (![vc conformsToProtocol:protocol]) {
        NSLog(@"object doesn't conform to %@", protocol);
    }
}

Трудно представить, почему вы хотите сделать это во время выполнения, хотя.

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

@property (nonatomic, strong) id<UIApplicationDelegate, UIImagePickerController,
    UIScrollViewDelegate, NSFileManagerDelegate> swissArmyKnife;

Если вы попытаетесь что-то присвоить этому свойству, а оно не соответствует всем четырем протоколам, компилятор выдаст предупреждение.

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

Если вы хотите отправить сообщение объекту, но не уверены, что оно поймет сообщение, вероятно, лучше проверить специально для сообщения, которое вы хотите отправить, вместо проверки соответствия протокола.

// This is probably not such a good idea.
if ([object conformsToProtocol:@protocol(NSFileManagerDelegate)]) {
    return [object fileManager:myFileManager shouldRemoveItemAtURL:url];
} else {
   return arc4random_uniform(2);
}


// This is probably better.
if ([object respondsToSelector:@selector(fileManager:shouldRemoveItemAtURL:)]) {
    return [object fileManager:myFileManager shouldRemoveItemAtURL:url];
} else {
   return arc4random_uniform(2);
}

Конечно.

id object = ...;
Protocol *protocols[] = {@protocol(Blah), @protocol(Foo), @protocol(Bar)};
for(unsigned i = 0; i < sizeof(protocols) / sizeof(Protocol *); ++i) {
   if([object conformsToProtocol:protocols[i]]) {
     //do something...
     break;
   }
}
Другие вопросы по тегам