[英]Why my code crash only in release and after upgrade to Xcode 4.6?
由于释放包含对正在执行的块的引用的变量而导致崩溃。 这是代码示例:
这是现在发布的错误,在同一设备上的调试中可以正常运行,它必须作为临时运行才能崩溃。
- (void)test {
_test = [self doLater:^{
_count++;
[self test];
} :3];
}
这在NSObject类别中定义:
- (DoLaterProcess *)doLater:(void (^)())method :(double)delay {
return [[DoLaterProcess new] from:method :delay];
}
结束使用类的实现:
@implementation DoLaterProcess {
id _method;
BOOL _stop;
}
- (void)methodToPerform:(void (^)())methodToInvoke {
if (_stop)return;
if (NSThread.isMainThread) methodToInvoke();
else [self performSelectorOnMainThread:@selector(methodToPerform:) withObject:methodToInvoke waitUntilDone:NO];
}
- (DoLaterProcess *)from:(void (^)())method:(NSTimeInterval)delay {
[self performSelector:@selector(methodToPerform:) withObject:method afterDelay:delay];
_method = method;
return self;
}
- (void)stop {
_stop = YES;
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(methodToPerform:) object:_method];
}
@end
所以我知道_test变量被释放,然后在释放时可能也会阻塞? 那就是为什么它崩溃? 但是,为什么它在调试时不崩溃,我是否可以在调试中以某种方式强制编译器在此崩溃? 谢谢。
块捕获本地状态。 在您的情况下,该块正在捕获_count
和self
。 为了有效地做到这一点,当您创建一个块时,它最初位于堆栈中,其结果是仅在该方法不返回的情况下才可以安全使用它。 因此,您可以向下传递块,但不能保留它们或将它们向上传递而不将它们移到堆中。 您可以通过copy
它们来实现(如果该块已经在堆上,则copy
被定义为retain
,因此您不必为过度复制付钱)。
在您的情况下,正确的做法是使用doLater::
复制块(尽管出于记录目的,未命名的参数被认为是极差的做法 )。
我对为什么都将方法分配给实例变量并计划将其调度以供以后传递给它感到有些困惑,但是最快的解决方法是:
- (DoLaterProcess *)from:(void (^)())method:(NSTimeInterval)delay {
method = [method copy];
[self performSelector:@selector(methodToPerform:) withObject:method afterDelay:delay];
_method = method;
return self;
}
关于为什么它在4.6下似乎已被打破:您所依赖的是未记录的行为(尽管感觉像是自然的未记录的行为),因此允许对工具集或OS进行任何更改(或者实际上,不做任何更改)都可以影响该行为。
(此外:您似乎还重新实现了GCD中内置的许多功能;您可以直接用from::
methodToPerform:
替换dispatch_after
methodToPerform:
和methodToPerform:
使用dispatch_async
替换,在两种情况下都提供dispatch_get_main_queue()
作为队列)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.