在objective-C(iphone)中,如何管理'@protocol'引用的内存?

时间:2009-05-12 23:42:28

标签: iphone objective-c memory-management

我认为我对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

这给了我一个“警告:在协议中找不到' - 释放'”。 我可以安全地忽略这个错误吗?或者我在做一些可怕的错误?

3 个答案:

答案 0 :(得分:30)

是的,您可以安全地忽略此错误。声明为类型id<MyProtocol>的对象可能不会从NSObject继承(您没有使用Cocoa库在Objective-C中编程,并且还有其他根类,即使在可可,如NSProxy)。由于retain(和releaseautorelease)在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}}。通常情况下,如果NSObjectNSObject在遗传或语义上相关联,我们才会执行此操作。


关于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;

为什么还要保留实现协议的对象?您只需要一个指向对象的指针,通过该指针可以调用协议中声明的方法。