内存管理与Cocoa中的void * context相关

时间:2011-03-04 02:56:15

标签: objective-c cocoa-touch ios memory-management

有许多Foundation类允许您提供指向void的指针,该指针稍后作为参数传递给回调函数。例如,addObserver:forKeyPath:options:context:of NSKeyValueObserving。

由于指向void的指针可能不会扩展NSObject,因此不能指望接受这种参数的函数保留它。因此,您的代码必须类似于以下内容:

- (void)sharedInit
{
    MyObject *myObject = [[MyObject alloc] init];
    [x addObserver:y forKeyPath:@"z" options:0 context:myObject];
    // cannot (auto)release myObject here
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    MyObject *myObject = (MyObject *)context;
    [myObject release]; // myObject is released here
}

这是有道理的,虽然它似乎违反了Cocoa / Objective-C对象所有权的每一个原则。此外,如果您忘记在这种情况下手动管理内存,通常(尽管不总是)会导致EXC_BAD_ACCESS崩溃。此外,Xcode分析器抱怨。

我问这个问题的原因是因为我正在编写一个网络连接库,它在其公共API中使用了相同类型的上下文指针。但是,在我自己的代码中必须跟踪一些与手动内存管理需求相关的内存管理错误之后,我相信必须有更好的方法。一种解决方案是将我的API的上下文参数的类型更改为(id< NSObject>)而不是(void *)。

为什么基础课通常使用(void *)而不是(id< NSObject>)?

2 个答案:

答案 0 :(得分:2)

MHC对推理是正确的。不要求对象是NSObject。但是,正如您所注意到的,在任何情况下,您都在不正确地进行内存管理。

在这种情况下,管理对象的常见模式是将其存储为注册类的ivar,而不是泄漏对象,然后再尝试清理它。另一种常见模式是将self作为上下文传递,确保在-dealloc期间取消注册回调。

答案 1 :(得分:1)

因为它并不总是id。数据可以是C结构,也可以是Core Foundation对象,甚至是标量。