2

我一定是做错了什么,但是 Automatic Reference Counting 文档并没有给我提示它可能是什么。我正在做的是从委托方法内部调用一个带有块回调的方法。从块内部访问同一个委托会导致访问错误。问题是我正在传递的对象 - loginController将消息发送给它的委托 - 显然没有释放,当我不在块内访问它时,我可以多次调用该方法而不会出现问题。这是我的代码:

- (void)loginViewDidSubmit:(MyLoginViewController *)loginController
{
    NSString *user = loginController.usernameLabel.text;
    NSString *pass = loginController.passwordLabel.text;

    __block MyLoginViewController *theController = loginController;
    [self loginUser:user withPassword:pass callback:^(NSString *errorMessage) {
        DLog(@"error: %@", errorMessage);
        DLog(@"View Controller: %@", theController);    // omit this: all good
        theController = nil;
    }];
}

NSZombieEnabled 不记录任何内容,并且 gdb 没有可用的堆栈跟踪。我在这里做错了什么?感谢您的任何指点!


编辑:

我认为问题的范围更大——上面的回调是从 NSURLConnectionDelegate 方法调用的(块本身是该委托的强属性,因此 ARC 应该调用 Block_copy())。在这种情况下我需要进行特殊测量吗?

流程(loginController 始终可见):

登录控制器

[delegate loginViewDidSubmit:self];

查看代表

(method shown above calls the loginUser: method, which does something like:)
httpDelegate.currentCallback = callback;
httpDelegate.currentConnection = // linebreak for readability
    [[NSURLConnection alloc] initWithRequest:req
                                    delegate:httpDelegate
                            startImmediately:YES];

NSURLConnectionDelegate

- (void)connection:(NSURLConnection *)aConnection
  didFailWithError:(NSError *)error
{
    if (NULL != currentCallback) {
        currentCallback([error localizedDescription]);
        self.currentCallback = NULL;
    }
}

这就是我获得错误访问权限的地方,但只有当我访问该 loginController 变量时...

4

3 回答 3

3

将复制属性设置为属性,或者只为块调用“复制”方法。

- (void)loginUser:(NSString *)user withPassword:(NSString *)pass callback:(void (^callback)(NSString *))
{
    callback = [callback copy];
于 2011-09-14T23:21:20.240 回答
1

实际的解决方案是我将块作为一个属性,但它应该是一个复制属性!哦!


第一个“解决方案”:

我刚刚找到了一种防止不良访问的方法。如我上面的编辑所示,View Delegate将块转发给 httpDelegate(另一个类的实例),而后者又保持对块的强引用。无论出于何种原因,将块分配给临时变量并转发临时块变量都可以解决问题。所以:

如所述,这会在块执行时崩溃

httpDelegate.currentCallback = callback;

这有效

MyCallbackType aCallback = callback;
httpDelegate.currentCallback = aCallback;

我会接受这个作为答案,如果有人有更多见解,我很乐意修改我的决定。:)

于 2011-09-13T18:39:55.380 回答
0

我认为那里发生的事情是 loginController 在调用其委托后立即死亡。因此发生崩溃。如果没有更多信息,我只能想到可能的情况:

  1. 该块不保留 loginController 对象(__block 类型修饰符)。如果块是异步执行的,loginController 可能不再可用,如果它在 elsewere 中被杀死。因此,无论你想用它做什么,你都无法在块内访问它,应用程序将崩溃。如果控制器在发送 loginViewDidSubmit 后被终止,则可能会发生这种情况。

  2. 我认为这很可能是您的情况: loginController 调用其委托对象。委托方法最终会同步调用杀死控制器的回调块。调用委托方法后,控制器应该是活动的。在委托方法中杀死它,很可能会导致崩溃发生。为了确保这是问题所在,只需在委托方法中将 loginController 设为 nil,并在调用委托后将 NSLog 语句放入控制器中,别管这个块,你会在那里崩溃。

也许如果您粘贴一些代码,我们可以提供更多帮助。

我最好的。

于 2011-09-13T17:07:14.063 回答