Възможно ли е динамично внедряване на протокол в 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 при conformsToProtocol за UITableViewDelegate? - person SoftMemes; 27.04.2012
comment
Да, ще стане. Всъщност няма съществуващи екземпляри, вие разширявате класа, като добавяте вашата реализация на протокола към него. - person ; 27.04.2012

Мисля, че това е възможно. Можете лесно да създавате динамични прокси сървъри в Objective-C (ето как NSUndoManager прави своята магия) чрез презаписване на метода forwardInvocation: на NSObject, прихващайки всички неразпознати съобщения, на които би отговорил имплементатор на протокола. Никога не съм правил това сам, така че може да има по-елегантен начин да го направя.

В допълнение, за да заблудите проверките по време на изпълнение, за да се съгласите, че вашият обект наистина прилага протокола, можете да замените метода на класа на NSObject conformsToProtocol: така:

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

Може да има повече методи, които трябва да замените, един пример биха били instancesRespondToSelector: и методите resolve*: на NSObject. Разгледайте NSObject референция за клас, за да разберете повече.

person Kristian Duske    schedule 27.04.2012