NSNotification 是否会保留对象?

21

我的问题涉及到通过-postNotificationName:object: userInfo:方法添加的对象。

NSNotification是否会retain这个对象? (类似于NSMutableDictionary或Array),这是否意味着我可以在发布通知后释放该对象?

下面是一个代码片段,用于说明我的问题...释放对象是否有效。附上苹果文档链接将非常有帮助。

NSMutableDictionary *teamDictCopy = [self.teamDict mutableCopy];
[teamDictCopy setObject:[NSNumber numberWithInt:self.scrollViewIndex] forKey:@"imageIndex"];

if([self.statusButton.title isEqualToString:@"Completed"]){
    [[NSNotificationCenter defaultCenter] postNotificationName:@"UnComplete" object:teamDictCopy userInfo:nil];
}

[teamDictCopy release];
2个回答

31
我不确定该方法中的objectuserInfo参数是否会被保留,但实际上,这并不重要。我认为你可能认为NSNotificationCenter是以异步方式创建这些通知并广播它们,但事实并非如此。根据NSNotificationCenter文档(请参阅NSNotificationCenter Class Reference),通知是同步发布的。因此,在您的代码中,通知中心创建通知,然后通过默认中心广播它。已注册此通知名称和对象组合的任何对象都将接收通知,然后执行其在注册该通知时指定的选择器,之后控制权将返回发布通知的类。换句话说,在您的代码到达[teamDictCopy release]行时,teamDictCopy已被所有感兴趣的方使用过了。因此,在释放它时不应存在任何危险。值得注意的是,通常,object:参数用于表示发布通知的对象,而userInfo:参数用于额外信息的NSDictionary。因此,通常会按以下方式处理通知:
NSMutableDictionary *teamDictCopy = [self.teamDict mutableCopy];
[teamDictCopy setObject:
   [NSNumber numberWithInt:self.scrollViewIndex] forKey:@"imageIndex"];

if([self.statusButton.title isEqualToString:@"Completed"]){
 [[NSNotificationCenter defaultCenter] postNotificationName:@"UnComplete" 
     object:self userInfo:teamDictCopy];
    }

[teamDictCopy release];

1
谢谢你的回答,它解决了比我问题更多的疑惑。 不断学习 - MDMonty
5
如果仅在使用NSNotificationCenters时,这就是正确的。那么对于NSNotificationQueue呢?在这种情况下,我们是异步发送通知,对象是否被保留确实很重要。 - DougW

5

是的 - 你可以在将对象设置为通知对象后释放它。

你还可以创建子类。

至于具体的文档/声明:我不记得有一个特别的了。

然而,这就是对象、它们的实例变量以及在确定类型为对象时的分布式通信和信号的基础。

我为你编写了一个测试,所以你可以确信这一点。如果不保留对象,则通知的用例将很少。只需按照指示在断点处添加断点,然后启用断点运行。享受!

#import <Foundation/Foundation.h>

@interface MONObject : NSObject
@end

@implementation MONObject

- (id)retain {
    return self; /* << add breakpoint here */
}

/* needed to counter retain override
   (although all MONObjects will leak in this example)
*/
- (void)release {
}

@end

int main(int argc, const char* argv[]) {
    NSAutoreleasePool * pool = [NSAutoreleasePool new];

    NSString * name = @"UnComplete";
    MONObject * obj = [MONObject new];
    [[NSNotificationCenter defaultCenter] postNotificationName:name object:obj userInfo:nil];
    [obj release], obj = 0;

    [pool drain];
    return 0;
}

嗨,Justin...你能找到苹果文档来支持你的回答吗?我已经寻找了几个小时,也许我错过了它。 - MDMonty
@MDMonty,我已经扩展了答案。如果您还想查看释放点的执行点,则可以在“-MONObject release]”处添加断点。希望这作为确认的依据。如果它是void*,那么绝对不要期望它被保留,但对象是一个id - justin
非常感谢。非常好的演示。我希望我能授予2个“正确答案”,因为您的回答有助于补充其他答案。 - MDMonty
所以,我的想法是在dealloc中从通知中删除obj本身,这完全是错误的。 - Dan Rosenstark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接