我认为我对objective-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
这给了我一个“警告:在协议中找不到' - 释放'”。 我可以安全地忽略这个错误吗?或者我在做一些可怕的错误?
答案 0 :(得分:30)
是的,您可以安全地忽略此错误。声明为类型id<MyProtocol>
的对象可能不会从NSObject
继承(您没有有使用Cocoa库在Objective-C中编程,并且还有其他根类,即使在可可,如NSProxy
)。由于retain
(和release
,autorelease
)在NSObject
中声明,编译器无法知道声明为类型id<MyProtocol>
的实例会响应这些消息。为了解决这个问题,Cocoa还定义了NSObject
协议,它反映了NSObject
API。如果您将协议声明为
@protocol MyProtocol <NSObject>
@end
表示MyProtocol
扩展了NSObject
协议,您将被设置。
答案 1 :(得分: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;
这是最广泛的一部分:让我在这个对象上调用任何东西,永远不要抱怨。
你也可以(正如Barry Wark建议的那样)MyProtocol
包含NSObject
协议 - 尽管从设计的角度来看,如果实施MyProtocol
必然意味着使用{ {1}}。通常情况下,如果NSObject
和NSObject
在遗传或语义上相关联,我们才会执行此操作。
关于MyProtocol
协议的一些信息:
您调用的所有内容都必须执行此协议时保留/释放/自动释放。正如你可以从中推断的那样:基本上所有东西都实现了NSObject
协议(即使有些东西不是来自NSObject
基类)。
另一个快速澄清:NSObject
(类)和NSObject
(协议)不是相同API的重新实现。它们按如下方式划分:
NSObject(协议)实现了处理/检查一般意义上的现有对象所需的一切(retain / release,isEqual,class,respondsToSelector:等)。
NSObject(类)实现了不太通用的方法:构造/销毁,线程集成,脚本集成。
因此,在大多数情况下,协议是两者中更重要的。请记住,该类包含协议,因此,如果您从NSObject继承,则可以同时获得这两个协议。
答案 2 :(得分:-2)
更改
@property (nonatomic, retain) id<MyProtocol> reference;
到
@property (nonatomic, assign) id<MyProtocol> reference;
为什么还要保留实现协议的对象?您只需要一个指向对象的指针,通过该指针可以调用协议中声明的方法。