Можно ли динамически реализовать протокол в Objective-C?

Я знаю, что могу расширить класс (например, класс фреймворка) с помощью категорий, но возможно ли, чтобы класс, для которого вы не контролируете исходный код, реализовывал один из ваших пользовательских протоколов? Я не только хочу, чтобы он отвечал на определенные сообщения, если они отправлены экземпляру, но также, в идеале, хочу, чтобы объекты этого класса возвращали true при проверке типа во время выполнения при запросе протокола.


person SoftMemes    schedule 27.04.2012    source источник
comment
Почему бы вам не создать подкласс и не добавить этот протокол?   -  person kuba    schedule 27.04.2012
comment
@kuba, потому что я хочу добавить его к существующим экземплярам, ​​предоставляемым фреймворком, а не только к экземплярам, ​​которые я создаю сам.   -  person SoftMemes    schedule 27.04.2012


Ответы (2)


Вы можете определить категорию, которая соответствует протоколу, поэтому вы должны сделать что-то вроде:

@interface UIWebView (MyGreatExtensions) <UITableViewDelegate>
@end

@implementation UIWebView (MyGreatExtensions)

- (CGFloat)tableView: (UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath *)indexPath {
  return 42.0;
}

// ...

@end

Небольшой пограничный случай, который следует учитывать, заключается в том, что если кто-то другой попытается сделать то же самое (например, сторонняя платформа также добавит протокол через категорию), вы не можете гарантировать, что ваш будет использоваться версия (и, конечно же, они не могут).

Подробнее об этом подходе от Марка Далримпла.

person Community    schedule 27.04.2012
comment
Последняя проблема в данном случае не является проблемой, поскольку я владею как самим протоколом, так и его реализацией. Приведет ли это к тому, что существующие экземпляры UIWebView вернут значение true для соответствия протоколу для UITableViewDelegate? - person SoftMemes; 27.04.2012
comment
Да, это будет. На самом деле нет никаких существующих экземпляров, вы расширяете класс, добавляя к нему свою реализацию протокола. - person ; 27.04.2012

Я думаю, это возможно. Вы можете легко создавать динамические прокси-серверы в Objective-C (именно так NSUndoManager делает свое волшебство), перезаписывая метод forwardInvocation: NSObject, перехватывая все нераспознанные сообщения, на которые мог бы ответить разработчик протокола. Я никогда не делал этого сам, поэтому может быть более элегантный способ сделать это.

Кроме того, чтобы обмануть проверки времени выполнения и заставить их согласиться с тем, что ваш объект действительно реализует протокол, вы можете переопределить метод класса NSObject соответственно:

+ (BOOL)conformsToProtocol:(Protocol *)aProtocol {
    if (aProtocol == @protocol(MyDynamicallyImplementedProtocol))
        return YES;
    return [super conformsToProtocol:aProtocol];
}

Может быть больше методов, которые вам нужно переопределить, одним из примеров может быть instancesRespondToSelector: NSObject: и методы resolve*:. Изучите класс NSObject чтобы узнать больше.

person Kristian Duske    schedule 27.04.2012