我以为我已经很了解弱引用和 block ,但是在尝试下面的代码片段时,有一些我不明白的地方。
方法测试 1 : 一切正常,对象不保留
方法测试 2 : 我不明白为什么对象似乎一直保留到方法结束 测试3 !甚至明确设置 object = nil
在方法结束时 测试 2 不会改变任何东西。
方法测试3 : 对象没有保留。为什么是方法测试 2 不是这样吗?
作为一个附带问题,我实际上想知道弱变量是否是线程安全的?即,如果我在尝试从不同线程访问弱变量时永远不会得到任何 BAD_ACCESS 异常。
@interface Object : NSObject
@property (nonatomic) NSInteger index;
@end
@implementation Object
- (id)initWithIndexNSInteger) index {
if (self = [super init]) {
_index = index;
}
return self;
}
- (void)dealloc {
NSLog(@"Deallocating object %d", _index);
}
@end
- (void) test1 {
NSLog(@"test1");
Object* object = [[Object alloc] initWithIndex:1];
NSLog(@"Object: %@", object);
__weak Object* weakObject = object;
dispatch_async(dispatch_queue_create(NULL, NULL), ^{
//NSLog(@"Weak object: %@", weakObject);
[NSThread sleepForTimeInterval:2];
NSLog(@"Exiting dispatch");
});
[NSThread sleepForTimeInterval:1];
NSLog(@"Exiting method");
}
- (void) test2 {
NSLog(@"test2");
Object* object = [[Object alloc] initWithIndex:2];
NSLog(@"Object: %@", object);
__weak Object* weakObject = object;
dispatch_async(dispatch_queue_create(NULL, NULL), ^{
NSLog(@"Weak object: %@", weakObject);
[NSThread sleepForTimeInterval:2];
NSLog(@"Exiting dispatch");
});
[NSThread sleepForTimeInterval:1];
NSLog(@"Exiting method");
}
- (void) test3 {
NSLog(@"test3");
Object* object = [[Object alloc] initWithIndex:3];
NSLog(@"Object: %@", object);
NSValue *weakObject = [NSValue valueWithNonretainedObjectbject];
dispatch_async(dispatch_queue_create(NULL, NULL), ^{
NSLog(@"Weak object: %@", [weakObject nonretainedObjectValue]);
[NSThread sleepForTimeInterval:2];
NSLog(@"Exiting dispatch");
});
[NSThread sleepForTimeInterval:1];
NSLog(@"Exiting method");
}
- (void) test {
[self test1];
[NSThread sleepForTimeInterval:3];
[self test2];
[NSThread sleepForTimeInterval:3];
[self test3];
}
2013-05-11 19:09:56.753 test[1628:c07] test1
2013-05-11 19:09:56.754 test[1628:c07] Object: <Object: 0x7565940>
2013-05-11 19:09:57.755 test[1628:c07] Exiting method
2013-05-11 19:09:57.756 test[1628:c07] Deallocating object 1
2013-05-11 19:09:58.759 test[1628:1503] Exiting dispatch
2013-05-11 19:10:00.758 test[1628:c07] test2
2013-05-11 19:10:00.758 test[1628:c07] Object: <Object: 0x71c8260>
2013-05-11 19:10:00.759 test[1628:1503] Weak object: <Object: 0x71c8260>
2013-05-11 19:10:01.760 test[1628:c07] Exiting method
2013-05-11 19:10:02.760 test[1628:1503] Exiting dispatch
2013-05-11 19:10:04.761 test[1628:c07] test3
2013-05-11 19:10:04.762 test[1628:c07] Object: <Object: 0x71825f0>
2013-05-11 19:10:04.763 test[1628:1503] Weak object: <Object: 0x71825f0>
2013-05-11 19:10:05.764 test[1628:c07] Exiting method
2013-05-11 19:10:05.764 test[1628:c07] Deallocating object 3
2013-05-11 19:10:05.767 test[1628:c07] Deallocating object 2
2013-05-11 19:10:06.764 test[1628:1503] Exiting dispatch
在我触及你的一些问题之前,我对你的三个测试有两个观察:
dispatch_async
的身份进行所有这些测试。 ,它非常快速地启动分派(dispatch) block ,有时比底层对象超出范围更快,并且您经常访问 weakObject
作为调度 block 中的第一步。我建议使用 dispatch_after
(所以你真的给了调用方法一个让变量超出范围的机会),所以你最好看看发生了什么。 dispatch_after
测试相同的东西也很有用一次做一个测试,少一些 sleepForTimeInterval
.感觉就像你测试的一些特性正在伪造一些关键行为。Method test2: I don't understand why the object seems to get retained until the end of method test3! Even explicitly setting object = nil at the end of method test2 does not change anything.
test
才会被排空。方法完成。test2
再次,但在访问 weakObject
之前让操作等待两秒钟(或者去掉所有这些 sleepForTimeInterval
语句并使用 dispatch_after
而不是 dispatch_sync
):- (void) test2 {
NSLog(@"test2");
Object* object = [[Object alloc] initWithIndex:2];
NSLog(@"Object: %@", object);
__weak Object* weakObject = object;
dispatch_async(dispatch_queue_create(NULL, NULL), ^{
[NSThread sleepForTimeInterval:2]; // new sleep
NSLog(@"Weak object: %@", weakObject);
[NSThread sleepForTimeInterval:2];
NSLog(@"Exiting dispatch");
});
// [NSThread sleepForTimeInterval:1]; // not really necessary
NSLog(@"Exiting method");
}
Method test3: the object is not retained. Why is method test2 not behaving like this?
test3
是严重的坏消息,很容易崩溃。例如,尝试注释掉 sleep 行:- (void) test3 {
NSLog(@"test3");
Object* object = [[Object alloc] initWithIndex:3];
NSLog(@"Object: %@", object);
NSValue *weakObject = [NSValue valueWithNonretainedObjectbject];
dispatch_async(dispatch_queue_create(NULL, NULL), ^{
NSLog(@"Weak object: %@", [weakObject nonretainedObjectValue]);
[NSThread sleepForTimeInterval:2];
NSLog(@"Exiting dispatch");
});
// [NSThread sleepForTimeInterval:1];
NSLog(@"Exiting method");
}
weak
和更多类似 unsafe_unretained
.As a side question, I was actually wondering if weak variables are thread safe? ie if I will never get any BAD_ACCESS exception when trying to access a weak variable from different threads.
weakObject
某些方法要求它不是 nil
(例如 NSMutableArray
方法 addObject
),你会得到一个异常(exception)。如果您为 nil
取消引用 ivars,您也可以获得异常。对象指针,例如obj->objectIvar
.例如,想象一个 Object
实例方法,doSomethingLater
,它使用弱引用来确保它不保留 Object
,但随后有一个本地强引用,因此它可以取消引用 ivar:- (void)doSomethingLater
{
__weak Object *weakSelf = self;
double delayInSeconds = 10.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
Object *strongSelf = weakSelf;
NSLog(@"%d", strongSelf->_index); // **BAD** - this can crash of `self` has been released by this point
});
}
- (void)doSomethingLater
{
__weak Object *weakSelf = self;
double delayInSeconds = 10.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
Object *strongSelf = weakSelf;
if (strongSelf) {
NSLog(@"%d", strongSelf->_index);
}
});
}
weakObject
不是 nil
可以防止许多此类问题(有一些我不打算讨论的警告)。这在调用对象方法时不太重要(因为向 nil
发送任何消息都会导致 nil
),但在您的 weakObject
时很重要。是一个参数或正在为 ivar 取消引用。dispatch_barrier_async
用于写入,dispatch_sync
用于读取)。关于ios - ARC block ,弱和保留计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16499739/
欢迎光临 OStack程序员社区-中国程序员成长平台 (https://ostack.cn/) | Powered by Discuz! X3.4 |