NSArray of weak references (__unsafe_unretained) to objects under ARC

前端 未结 12 746
南旧
南旧 2020-11-27 11:26

I need to store weak references to objects in an NSArray, in order to prevent retain cycles. I\'m not sure of the proper syntax to use. Is this the correct way?



        
12条回答
  •  感动是毒
    2020-11-27 12:10

    I've just faced with same problem and found that my before-ARC solution works after converting with ARC as designed.

    // function allocates mutable set which doesn't retain references.
    NSMutableSet* AllocNotRetainedMutableSet() {
        CFMutableSetRef setRef = NULL;
        CFSetCallBacks notRetainedCallbacks = kCFTypeSetCallBacks;
        notRetainedCallbacks.retain = NULL;
        notRetainedCallbacks.release = NULL;
        setRef = CFSetCreateMutable(kCFAllocatorDefault,
        0,
        ¬RetainedCallbacks);
        return (__bridge NSMutableSet *)setRef;
    }
    
    // test object for debug deallocation
    @interface TestObj : NSObject
    @end
    @implementation TestObj
    - (id)init {
       self = [super init];
       NSLog(@"%@ constructed", self);
       return self;
    }
    - (void)dealloc {
       NSLog(@"%@ deallocated", self);
    }
    @end
    
    
    @interface MainViewController () {
       NSMutableSet *weakedSet;
       NSMutableSet *usualSet;
    }
    @end
    
    @implementation MainViewController
    
    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
        self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
        if (self) {
            // Custom initialization
          weakedSet = AllocNotRetainedMutableSet();
          usualSet = [NSMutableSet new];
       }
        return self;
    }
    
    - (IBAction)addObject:(id)sender {
       TestObj *obj = [TestObj new];
       [weakedSet addObject:obj]; // store unsafe unretained ref
       [usualSet addObject:obj]; // store strong ref
       NSLog(@"%@ addet to set", obj);
       obj = nil;
       if ([usualSet count] == 3) {
          [usualSet removeAllObjects];  // deallocate all objects and get old fashioned crash, as it was required.
          [weakedSet enumerateObjectsUsingBlock:^(TestObj *invalidObj, BOOL *stop) {
             NSLog(@"%@ must crash here", invalidObj);
          }];
       }
    }
    @end
    

    Output:

    2013-06-30 00:59:10.266 not_retained_collection_test[28997:907] constructed 2013-06-30 00:59:10.267 not_retained_collection_test[28997:907] addet to set 2013-06-30 00:59:10.581 not_retained_collection_test[28997:907] constructed 2013-06-30 00:59:10.582 not_retained_collection_test[28997:907] addet to set 2013-06-30 00:59:10.881 not_retained_collection_test[28997:907] constructed 2013-06-30 00:59:10.882 not_retained_collection_test[28997:907] addet to set 2013-06-30 00:59:10.883 not_retained_collection_test[28997:907] deallocated 2013-06-30 00:59:10.883 not_retained_collection_test[28997:907] deallocated 2013-06-30 00:59:10.884 not_retained_collection_test[28997:907] deallocated 2013-06-30 00:59:10.885 not_retained_collection_test[28997:907] * -[TestObj respondsToSelector:]: message sent to deallocated instance 0x1f03c8c0

    Checked with iOS versions 4.3, 5.1, 6.2. Hope it will be useful to somebody.

提交回复
热议问题