Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/358.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 块和异步回调,dealloc对象-需要将块置零_Objective C_Asynchronous_Dealloc_Block_Nszombie - Fatal编程技术网

Objective c 块和异步回调,dealloc对象-需要将块置零

Objective c 块和异步回调,dealloc对象-需要将块置零,objective-c,asynchronous,dealloc,block,nszombie,Objective C,Asynchronous,Dealloc,Block,Nszombie,这里有一个类似的问题,它不能准确地解释我想要什么: 我有一个视图控制器,它使用异步回调调用服务。回调使用块完成,块引用视图控制器上的变量来填充它们 看起来是这样的: - (void) loadData { __block MyViewController *me = self; [self.service executeWithCompletion:^(NSArray *result, NSError *error) { if (!error) {

这里有一个类似的问题,它不能准确地解释我想要什么:

我有一个视图控制器,它使用异步回调调用服务。回调使用块完成,块引用视图控制器上的变量来填充它们

看起来是这样的:

- (void) loadData {
    __block MyViewController *me = self;
    [self.service executeWithCompletion:^(NSArray *result, NSError *error) {
        if (!error) {
            me.data = result;  
        }
    }];
}
但是,如果我解除锁定视图控制器,“me”则会被回调严重访问

使“我”为空的最简单方法是什么?如果我把它作为一个iVar,它会带回循环引用。。。我想是吧

我想我遗漏了一些明显的东西


谢谢

您的目标是iOS 5.0或更高版本(或Mac OS X 10.7或更高版本)?如果是这样,您可以使用ARC和
\uuu弱
变量(而不是
\uu块
一个)。取消分配引用对象时,这将自动归零。你的代码看起来像

- (void)loadData {
    __weak MyViewController *me = self;
    [self.service executeWithCompletion:^(NSArray *result, NSError *error) {
        if (!error) {
            MyViewController *strongMe = me; // load __weak var into strong
            if (strongMe) {
                strongMe.data = result;
            }
        }
    }];
}

如果您需要对旧操作系统的支持,那么您需要找到不同的解决方案。一种解决方案是继续,让块保留
self
。如果服务保证执行完成块(然后释放它),这将只产生一个临时循环,当完成块运行时,该循环将自动中断。或者,如果您有办法取消服务(以确保取消后无法调用块的方式),您可以坚持使用
\u块
,只需确保在
-dealoc
中取消服务即可。还有其他选择,但它们更复杂。

是否存在您试图避免的真正的保留周期问题?是否有理由不应简单地保留
self
,直到
-executeWithCompletion:
完成?这真的有可能完成吗


只要它最终真的会完成(即使失败),并且只要它在调用它后释放块(可能通过将属性设置为
nil
),那么保留周期最终会被打破,一切都会好起来。

我结合了上面的建议。包括将街区归零。尽管如此,我的对象仍然没有立即释放。i、 例如,我在MyViewController的dealoc上设置了一个断点,如果没有_block变量,它将在稍后的时间点被调用(可能是由于异步连接),有时甚至根本不会

这段代码相当复杂——因此我想还有其他一些事情会让它无法像上面建议的那样工作

我还用了迈克·阿什(Mike Ash)的MAZeroingWeakRef,我想这和用uu-weak是一样的,这是凯文巴拉德(KevinBallard)建议的

下面是我如何实现它的,它似乎正在工作。在处理视图控制器时立即调用Dealloc,这是我想要的。我不能让它崩溃。。。通过我在日志中的评论,我已经可以看出我在躲避子弹

- (void) loadData {
    __block MAZeroingWeakRef *zeroWeakRef = [[MAZeroingWeakRef alloc] initWithTarget:self];
    [zeroWeakRef setCleanupBlock: ^(id target) {
        [zeroWeakRef autorelease];
    }];
    [self.service executeWithCompletion:^(NSArray *result, NSError *error) {
        MyViewController *me = [zeroWeakRef target];
        if (!me) {
            DULog(@"dodged a bullet");
        }
        if (!error) {
            me.data = result;  
        }
    }];
}

我还不能将整个项目迁移到ARC。太大了。不管怎样,我的目标是iOS 4。是的,我正在考虑取消这项服务。我能不能把_块变量放在iVar范围内,把它放在dealloc中nill/NULL?这是在一篇类似于我的文章中提到的。@bandejapaisa:你会在块之前怎么做?你还需要一种方法来取消它,或者有同样的崩溃问题。@KevinBallard是的-你是对的。和任何iVar一样,仍然指向self,我得到了retain循环。@user102008 before blocks。。。。我会使用一个委托,我会将我的委托设为零。@bandejapaisa:对,所以你需要做一些类似于“将委托设为零”的事情。你需要告诉它,当它停止工作时,不要再调用块。我的设计可能有缺陷。但有明确的保留周期。网络调用返回得相当快,很明显视图控制器没有被释放(没有调用dealloc),然后通过仪器泄漏和循环运行它,确认问题所在。使它成为_块肯定会修复这个保留周期,instruments再次确认了这一点。正如我所说的,在调用块后,无论在什么代码后面,都必须释放块
-executeWithCompletion:
。尝试显示该代码。如果查看我的代码段,MyViewController保留“服务”,而赋予“服务”的块保留MyViewController(如果我不使用_块)。这是一个循环,但这是一个临时的循环,有外部事件(网络通信的完成)来打破它。没有理由认为这个周期是个真正的问题,它绝对不是暂时的。它永远挂在那里。我明白你现在用你的其他评论说了些什么。当我调用服务时,当我调用异步网络服务时,我将块存储到iVar:savedCompletionBlock中——这就是保留问题所在。当网络调用返回时,我执行savedCompletionBlock();您的意思是,在执行此操作后,我调用self.savedCompletionBlock=nil;。这将消除临时保留周期。我要试一试。虽然我刚刚实现了一个cancel方法,它执行nil,这也很有效。