В объекте-C (iphone), как мне управлять памятью ссылок «@protocol»?

17

Я думал, что у меня неплохая ручка управления памятью для объектива-c, но я не могу понять следующую ситуацию:

@protocol MyProtocol
@end
@interface MyObject : NSObject {
    id<MyProtocol> reference;
}
@property (nonatomic, retain) id<MyProtocol> reference;
@end
@implementation MyObject 
@synthesize reference;
-(void) dealloc {
    [reference release];
    [super dealloc];
}
...
@end

Это дает мне предупреждение : '-release' не найден в протоколе . Можно ли игнорировать эту ошибку? Или я делаю что-то ужасно неправильно?

    
задан chris.f.jones 13.05.2009 в 01:42
источник

3 ответа

30

Да, вы можете спокойно проигнорировать эту ошибку. Объект, объявленный как тип id<MyProtocol> , не может наследовать от NSObject (вы не имеете , чтобы использовать библиотеки Cocoa для программирования в Objective-C, и есть другие корневые классы даже в Cocoa, такие как% код%). Поскольку NSProxyretain , release ) объявлены в autorelease , компилятор не может знать, что экземпляр, объявленный как тип NSObject , отвечает на эти сообщения. Чтобы обойти это, Cocoa также определяет протокол id<MyProtocol> , который отображает NSObject API. Если вы объявите свой протокол как

@protocol MyProtocol <NSObject>
@end

, указав, что NSObject расширяет протокол MyProtocol , вы будете установлены.

    
ответ дан Barry Wark 13.05.2009 в 01:47
источник
13

Обычно, когда вы объявляете объект как id , он подсчитывает «любой» объект (это означает, что Objective-C позволит вам вызывать любой метод из любого класса или протокола на id без предупреждения).

Однако, когда вы объявляете объект как id<SomeProtocol> , значение изменяется. В этом случае вы говорите: я буду ссылаться только на методы SomeProtocol на этом объекте.

Метод:

- (void)release;

объявляется в протоколе NSObject , но вы явно указали: я буду ссылаться только на методы MyProtocol . Поэтому компилятор дает вам предупреждение, чтобы сообщить вам, что вы нарушили свое собственное обещание.

Следовательно, вместо:

id<MyProtocol> reference;

вы должны фактически объявить:

id<MyProtocol, NSObject> reference;

или

NSObject<MyProtocol> reference;

, так как NSObject (класс) реализует NSObject (протокол).

или

id reference;

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

Вы также можете (как предположил Барри Уорк), MyProtocol включить протокол NSObject - хотя с точки зрения дизайна вы обычно это делаете, только если для реализации MyProtocol обязательно нужно использовать NSObject . Обычно мы делаем это только в том случае, если NSObject и MyProtocol связаны по наследству или семантически.

Немного информации о протоколе NSObject :

Все, что вы ссылаетесь на сохранение / освобождение / автоопределение, должно реализовать этот протокол. Как вы можете это сделать: в основном все реализует протокол NSObject (хотя некоторые из них не относятся к базовому классу NSObject ).

Еще одно быстрое разъяснение: NSObject (класс) и NSObject (протокол) не являются повторной реализацией одного и того же API. Они разбиваются следующим образом:

  • NSObject (протокол) реализует все необходимое для обработки / проверки существующего объекта в общем смысле (сохранение / освобождение, isEqual, класс, responseSToSelector: и т. д.).

  • NSObject (класс) реализует менее общие методы: построение / уничтожение, интеграция потоков, интеграция сценариев.

Таким образом, в большинстве случаев протокол является более важным из двух. Помните, что класс включает протокол, поэтому, если вы сходите из NSObject, вы получаете оба.

    
ответ дан Matt Gallagher 13.05.2009 в 03:15
источник
-2

Изменить

@property (nonatomic, retain) id<MyProtocol> reference;

to

@property (nonatomic, assign) id<MyProtocol> reference;

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

    
ответ дан helios 14.07.2011 в 08:28
источник
  • что делать, если он освобождается? –  user102008 26.07.2011 в 03:50
  • Вы не можете предположить, что ему не нужно сохранять объект без дополнительного контекста. –  pablasso 27.04.2012 в 18:56