在Objective C中实现自定义类的委托时引用计数

时间:2009-06-08 18:36:27

标签: iphone objective-c

我有两个类,ClassA将实例化ClassB并将方法作为委托传递。 ClassB最终会调用ClassA的委托。当ClassB存储时,我是否需要在ClassA上添加一个保留?

我正在遵循“Cocoa基础指南:与对象通信”中的“为自定义类实现代理”,但所演示的示例代码似乎并未将内存管理考虑在内。

ClassA将设置委托,并希望稍后在ClassB完成它的工作时回调它。

@implementation ClassA

-(void)launchSomething
{
   ClassB *classB = [[ClassB alloc] init];
   [classB setCallback:self withSelector:@selector(deferredWork)];

   // do some other stuff, assign class B to some View and eventually release class B
}

-(void)deferredWork
{
   NSLog(@"this is the method that will be deferred till some point in time");
}

ClassB的头文件,它将存储然后再调用委托:

@interface ClassB

id targetObject;
SEL targetMethod;

-(void) setCallback:(id)anObject withSelector:(SEL)aMethod

ClassB的实施:

@implementation ClassB
-(void) setCallback:(id)anObject withSelector:(SEL)aMethod
{
   // QUESTION: Do I need to add a 'retain' here on the targetObject?
   targetObject = anObject;
   targetMethod = aMethod;
}

-(void) someWorkLater
{
    if ( [targetObject respondsToSelector:@selector(targetMethod)] ) {
        // invoke the target object with the specific method
        [targetObject targetMethod];
    }
}

2 个答案:

答案 0 :(得分:2)

你不会在ClassB中保留ClassA,因为ClassA已经拥有ClassB,并且假设当ClassA被解除分配时,它将负责清理ClassB中的任何引用。

如果在ClassB中设置委托方法时遵循“正常”所有权规则并保留ClassA,则最终会得到一个保留循环,其中任何对象都不会被释放。相反,你应该使用与你完全一样的弱引用。

答案 1 :(得分:0)

正如Marc所说,Cocoa的正常做法是让代表们成为“弱”链接。也就是说,它们不会被保留。由代理确定当它不再能够作为一个delagate响应时,没有任何不好的事情发生 - 通过将委托设置为nil或释放源对象(假设它是唯一的所有者,它将立即释放)

因此,在您的示例中,如果classB在launchSomething结束后仍然存在,那么您可能已将其存储在ivar中。你的classA的dealloc例程要么

[classB setCallback:nil]; // optionally withSelector:@selector(none)

和/或

[classB release];

如果classB可能有其他所有者,那么你一定要使用setCallback:nil,但通常你知道你是唯一的所有者。

当涉及到视图和窗口时,事情变得复杂,因为很难确保订单对象被释放,并且没有其他人有与classB的强连接,在这种情况下清除回调是必不可少的。

这同样适用于观察者和通知,这些通常是弱链接,并且在你的dealloc例程中清除很多。