2010-04-18 4 views
7

У меня есть три класса, которые реализуют один и тот же протокол и имеют один и тот же родительский класс, который не реализует протокол. Обычно у меня был бы протокол как чистые виртуальные функции в родительском классе, но я не мог найти способ Objective-C для этого.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]; в родительский класс, но он не идеален, так как это вызовет ошибки во время выполнения, а не время компиляции.

+0

Похоже пути ObjC чистых виртуальных/абстрактных методы «класс кластеры». Возможно, вам стоит что-то изучить. – nmr

ответ

5

я смог правильно получить компилятор, чтобы предупредить меня, делая superclass *currentView свойства выглядеть следующим образом:

@property (nonatomic, retain) superclass<MyProtocol> *currentView; 
11

Разработчики 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]; 
    } 
} 
+3

Конечно, более надежно использовать 'responsesToSelector: @selector (protocolMethod)'. – kennytm

+2

... и необходимо, если протокол имеет необязательные методы. – jlehr

+0

Я бы не стал рекомендовать использовать такую ​​информацию типа времени выполнения, как это - это очень маловероятно, чтобы быть подлинным случаем, когда вы не знаете тип своего объекта достаточно хорошо во время компиляции, чтобы этого не делать. Наиболее распространенные случаи, когда я видел использование RTTI, являются излишними с небольшими размышлениями. Исключением является реализация кода типа generics в Objective-C, где, к сожалению, мы вынуждены использовать принципиально менее эффективный механизм, чем компилятор способен генерировать код, просто потому, что в спецификации языка нет компиляторов обобщенного времени (a проблема, совместно используемая/унаследованная от C).Кроме того, удаленный exec – jheriko

1

Лично я хотел бы реализовать протокол на суперкласса, но реализовать методы, как это:

- (id) myProtocolMethod { 
    NSAssert(NO, [NSString stringWithFormat:@"-[%@ %@] must be overridden", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]); 
    return nil; 
} 

Таким образом, если вы когда-либо забыть переопределить метод в конкретном подклассе, он должен быть сразу очевиден.

+0

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

+0

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

+0

Это поведение, которое я хочу, только с ошибкой компилятора, а не с исполняемой программой. Это не похоже, что Objective-C имеет способ сделать это. – Winder

3

В качестве альтернативы вы можете использовать следующие

if ([unknownObject conformsToProtocol:@protocol(MyProtocol)]) 
    [unknownObject performSelector:@selector(methodInProtocol)]; 

вместо следующее, если вы просто хотите, чтобы подавить предупреждение.

if ([unknownObject conformsToProtocol:@protocol(MyProtocol)]) 
    [unknownObject methodInProtocol]; // will cause warning 

performSelector: работает только в том случае, если количество аргументов равно нулю или одному. Более гибкие вызовы могут быть достигнуты с помощью NSInvocation.

Смежные вопросы