Weak property not zeroing using ARC

前端 未结 1 532
天命终不由人
天命终不由人 2020-12-21 13:08

I have the following simple code for an object that holds a weak reference:

// interface

@interface GMWeakRefObj : NSObject
@property (weak)         


        
相关标签:
1条回答
  • 2020-12-21 13:44

    Try some custom class class instead of NSData for d, e.g. MyData. Implement dealloc method in it and set breakpoint in it. You will see, that dealloc is called by autorelease pool after the last NSAssert. Only after that week reference will become nil.

    ADD: Looks like I have to extend my answer to make it clear, why it works that way. First, lets look at your example (from comments):

    NSData* data = [[NSData alloc] init];
    __weak NSData* weakRef = data;
    data = nil;
    NSAssert(weakRef == nil, @"Failed to zero");
    

    It works as expected, weakRef become nil after data = nil. The next example works too:

    NSData* data = [[NSData alloc] init];
    __weak NSData* weakRef = data;
    NSLog(@"%@", data);
    data = nil;
    NSAssert(weakRef == nil, @"Failed to zero");
    

    But the last example doesn't work:

    NSData* data = [[NSData alloc] init];
    __weak NSData* weakRef = data;
    NSLog(@"%@", weakRef);
    data = nil;
    NSAssert(weakRef == nil, @"Failed to zero");
    

    The only difference is that we use weak reference to output log. Why?

    (the rest of the answer can be wrong :) )

    Imaging that you NSLog (or any other function/selector we call before data = nil) rely on it's argument not to be nil. For example, it has "if (arg == nil) return;" at the very beginning.

    In multithreaded environment weak reference can become nil after if.

    So properly written function should look like:

      // ...
      T* local_arg = arg;   // NOTE: it is strong!
      if (local_arg == nil)
        return;
      // work with local_arg here, not with arg
      // ...
    

    But usually we don't want to do it everywhere -- it will be ugly. So we want to be sure that arguments will not disappear somewhere in the middle. Compiler does it for us by autoreleasing weak reference.

    So, it should be clear how, why your GMWeakRefObj test case doesn't work -- weakRef is autoreleased before calling setObject setter.

    0 讨论(0)
提交回复
热议问题