【问题标题】:Objective-C accessing properties inside blockObjective-C 访问块内的属性
【发布时间】:2012-08-21 13:45:21
【问题描述】:

我已阅读 Apple 的 Blocks Programming Topics 和我的尽职调查在线搜索,但我仍然不清楚我是否正确实施了我的块。我有一组客户端作为发送 NSNotification 时填充的属性。 Clients 用作 tableview 数据源。下面的代码有效,但我很好奇它是否将 self 置于保留周期中。我是否应该执行__block id theClients = self.clients; 之类的操作,然后在块内引用theClients

@property (strong, nonatomic) NSMutableArray *clients;

NSNotificationCenter *notifyCenter = [NSNotificationCenter defaultCenter];
__block id observer = [notifyCenter addObserverForName:queryHash
                                                object:nil
                                                 queue:[[NSOperationQueue alloc] init]
                                            usingBlock:^(NSNotification* notification){
                                                // Explore notification

    if ([[notification.userInfo objectForKey:kdatasetReturnKey] objectAtIndex:0]) {
        NSArray *rows = [[notification.userInfo objectForKey:kdatasetReturnKey] objectAtIndex:0];
        if (self.clients)
        {
            self.clients = nil;
        }
        self.clients = [[NSMutableArray alloc] initWithCapacity:rows.count];
        for (NSDictionary *row in rows) {
            [self.clients addObject:row];
        }
    } else {
        NSLog(@"CLIENTS ERROR Returned: %@",[notification.userInfo objectForKey:kerrorReturnKey]);
    }

    [[NSNotificationCenter defaultCenter] removeObserver:observer];
}];

【问题讨论】:

    标签: objective-c ios objective-c-blocks


    【解决方案1】:

    访问 clients 属性没有问题,因为它是一个强(即保留)属性。所以这里不需要__block

    一个问题可能是发送通知时self 可能不再存在。然后您将访问已释放的对象,应用程序可能会崩溃!为避免这种情况,您应该在 dealloc 方法中删除观察者。

    id observer 之前的__block 绝对是必需的!

    编辑:

    在 iOS 5 中,您可以使用弱引用安全地捕获 self

    __weak id weakSelf = self;
    

    然后在块内你可以安全地使用weakSelf.clients。当对象被释放时,变量weakSelf会自动变为nil。

    【讨论】:

    • "一个问题可能是发送通知时 self 可能不再存在。然后您将访问释放的对象,应用程序可能会崩溃!"错误的。 self 被块保留。
    • @newacct 在没有 ARC 的情况下也被保留?
    • 是的,self是块中使用的对象类型的局部变量,所以会自动保留
    • 那么在块内引用self.properties会导致内存泄漏吗?
    • @Helium3,你应该改用__weak typeof(self) weakSelf = self;
    【解决方案2】:

    是的,您有一个保留周期,至少在通知发生之前是这样。当您访问块中的clients ivar 时,块将保留自身。它将由通知中心的块保留,直到通知发生(因为您在块的末尾删除了观察者)。如果您不希望这样做,您可以使用对 self 的弱引用。

    NSNotificationCenter *notifyCenter = [NSNotificationCenter defaultCenter];
    __weak id weakSelf = self;
    id observer = [notifyCenter addObserverForName:queryHash
                                            object:nil
                                             queue:[[NSOperationQueue alloc] init]
                                        usingBlock:^(NSNotification* notification) {
        if (weakSelf) {                                
            if ([[notification.userInfo objectForKey:kdatasetReturnKey] objectAtIndex:0]) {
                NSArray *rows = [[notification.userInfo objectForKey:kdatasetReturnKey] objectAtIndex:0];
                if (weakSelf.clients)
                {
                    weakSelf.clients = nil;
                }
                weakSelf.clients = [[NSMutableArray alloc] initWithCapacity:rows.count];
                for (NSDictionary *row in rows) {
                    [weakSelf.clients addObject:row];
                }
            } else {
                NSLog(@"CLIENTS ERROR Returned: %@",[notification.userInfo objectForKey:kerrorReturnKey]);
            }
        }    
        [[NSNotificationCenter defaultCenter] removeObserver:observer];
    }];
    

    我认为您没有任何理由需要 __block 限定 observer

    也不清楚您在这里使用基于块的 API 有什么收获。如果您不想担心潜在的保留周期,您可以使用 addObserver:selector:name:object: 并将通知回调的主体放在实例方法中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多