У меня есть три класса, которые реализуют тот же протокол и имеют тот же родительский класс, который не реализует протокол. Обычно у меня был бы протокол как чистые виртуальные функции в родительском классе, но я не мог найти Objective C способом сделать это.
Я хочу использовать полиморфизм на этих подклассах путем объявления, что чистые виртуальные функции в суперклассе затем сделали, чтобы дети реализовали те функции. Однако единственный Objective C путем, который я нашел, чтобы сделать, это должно иметь каждого ребенка, явно решают реализовать протокол, когда я делаю это этот способ, которым суперкласс не знает, что дети реализуют тот протокол, таким образом, будут предупреждения времени компиляции повсеместно.
Некоторый псевдокод, если это не имело смысла:
@interface superclass: NSObject
{}
@interface child1: superclass<MyProtocol>
{}
@interface child2: superclass<MyProtocol>
{}
Потребитель этих классов:
@class child1
@class child2
@class superclass
@interface SomeViewController: UIViewController
{
child1 *oneView;
child2 *otherView;
superclass *currentView;
}
-(void) someMethod
{
[currentView protocolFunction];
}
Единственным хорошим путем я нашел, чтобы сделать, чистые виртуальные функции в Objective C являются взломом путем помещения [self doesNotRecognizeSelector:_cmd];
в родительском классе, но это не идеально, так как это вызовет ошибки периода выполнения, а не время компиляции.
Мне удалось заставить компилятор правильно предупреждать меня, сделав свойство суперкласса * currentView
выглядеть следующим образом:
@property (nonatomic, retain) superclass<MyProtocol> *currentView;
Лично я бы реализовал протокол в суперклассе, но реализовал бы такие методы:
- (id) myProtocolMethod {
NSAssert(NO, [NSString stringWithFormat:@"-[%@ %@] must be overridden", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]);
return nil;
}
Таким образом, если вы когда-нибудь забудете переопределить метод в конкретном подклассе, это должно быть сразу очевидно.
В таких ситуациях разработчики Objective-C обычно используют динамическую проверку, а не проверку во время компиляции, потому что язык и фреймворки так хорошо ее поддерживают. Так, например, вы можете написать свой метод так:
- (void)someMethod
{
// See if the object in currentView conforms to MyProtocol
//
if ([currentView conformsToProtocol:@protocol(MyProtocol)])
{
// Cast currentView to the protocol, since we checked to make
// sure it conforms to it. This keeps the compiler happy.
//
[(SuperClass<MyProtocol> *) currentView protocolMethod];
}
}
В качестве альтернативы вы можете использовать следующий
if ([unknownObject conformsToProtocol:@protocol(MyProtocol)])
[unknownObject performSelector:@selector(methodInProtocol)];
вместо следующего, если вы просто хотите подавить предупреждение.
if ([unknownObject conformsToProtocol:@protocol(MyProtocol)])
[unknownObject methodInProtocol]; // will cause warning
performSelector: будет работать, только если количество аргументов равно нулю или единице. Более гибкие вызовы могут быть достигнуты с помощью NSInvocation.