我有一个私有串行队列,它被声明为属性,但我遇到了一个非常奇怪的问题。如果我将该属性作为dispatch_async参数调用,程序会崩溃(EXC_BAD_ACCESS (code=EXC_i386_GPFLT))。在调试后,我发现发生崩溃是由于getter方法被调用。如果不调用getter方法,则不会发生崩溃。此外,每次调用self.queue的第二个时间都会崩溃。看下面的第二个示例。就好像第一次合成的getter调用已经导致ivar被过度释放一样。这是针对iOS 9及以上版本的,因此我没有检查OS_OBJECT_USE_OBJC。 示例1)以下示例无效:
例子5)如果我使用ivar代替property或者将self.initQueue分配给主队列也可以正常工作。
这种行为的原因是什么?
其他开源库使用dispatch_queue_t的property和getter,但它们没有任何问题。例如:https://github.com/rs/SDWebImage/blob/7e0964f8d90dcd80d535c52dd9f6d5fa7432052b/SDWebImage/SDImageCache.m#L57
@interface Test ()
@property (nonatomic, strong) dispatch_queue_t initQueue;
@end
- (instancetype)init {
self = [super init];
if (self) {
_initQueue = dispatch_queue_create("com.test.initQueue", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)onCompletion:(void (^)())completion {
// Crashes here - EXC_BAD_ACCESS (code=EXC_i386_GPFLT)
// the second time self.queue is accessed - either by subsequent call into
// this method, or by adding NSLog(@"%@", self.queue) before this line.
dispatch_async(self.initQueue, ^{
...
});
}
例子2)这样也不行:
@interface Test ()
@property (nonatomic, strong) dispatch_queue_t initQueue;
@end
- (instancetype)init {
self = [super init];
if (self) {
_initQueue = dispatch_queue_create("com.test.initQueue", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)onCompletion:(void (^)())completion {
NSLog(@"%@", self.initQueue);
// Crashes below - EXC_BAD_INSTRUCTION (code=EXC_i386_INVOP, subcode=0x0)
NSLog(@"%@", self.initQueue);
}
示例3)如果我避免使用getter,它将正常工作:
@interface Test ()
@property (nonatomic, strong) dispatch_queue_t initQueue;
@end
- (instancetype)init {
self = [super init];
if (self) {
_initQueue = dispatch_queue_create("com.test.initQueue", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)onCompletion:(void (^)())completion {
// Works fine
dispatch_async(_initQueue, ^{
...
});
}
例4)如果我提供getter,它也可以工作:
@interface Test ()
@property (nonatomic, strong) dispatch_queue_t initQueue;
@end
- (instancetype)init {
self = [super init];
if (self) {
_initQueue = dispatch_queue_create("com.test.initQueue", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (dispatch_queue_t)initQueue {
return _initQueue;
}
- (void)onCompletion:(void (^)())completion {
// Works fine
dispatch_async(self.initQueue, ^{
...
});
}
例子5)如果我使用ivar代替property或者将self.initQueue分配给主队列也可以正常工作。
这种行为的原因是什么?
其他开源库使用dispatch_queue_t的property和getter,但它们没有任何问题。例如:https://github.com/rs/SDWebImage/blob/7e0964f8d90dcd80d535c52dd9f6d5fa7432052b/SDWebImage/SDImageCache.m#L57
new
或init
为前缀的方法都被假定为NS_RETURNS_RETAINED
,因此返回值不会增加其保留值,所以你的保留计数是错误的。如果它是一个非属性iVar,你可能可以使用_initQueue
。 - Mgetznew
开头的属性。 - Rob