BKObject is a custom object and I want to put mutiple BKObject in to an array.
BKViewController:
#import <UIKit/UIKit.h>
#import "BKObject.h"
@interface BKViewController : UIViewController
@property (strong, nonatomic) NSArray *data;
@property (weak, nonatomic) BKObject *tmpObject;
@end
BKViewController.m:
#import "BKViewController.h"
@implementation BKViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableArray *arr = [[NSMutableArray alloc] init];
for(NSInteger i = 0; i < 100000; i++){
[arr addObject:[[BKObject alloc] initWithName:@""]];
}
self.data = [NSArray arrayWithArray:arr];
__weak BKObject *weakMutableObject = arr[0];
[arr removeAllObjects];
NSLog(@"%@", weakMutableObject); // print out the object, why?
__weak BKObject *weakObject = self.data[0];
self.data = nil;
NSLog(@"%@", weakObject); // print out the object again, but why?
self.tmpObject = [[BKObject alloc] initWithName:@""];
NSLog(@"%@", self.tmpObject); // print null, very clear
}
@end
I'm curious about why the first 2 NSLog messages show an object instead of null(as in the last NSLog). I'm using the latest Xcode 5.0.1 with iOS 7 SDK.
NSMutableArray *arr = [[NSMutableArray alloc] init];
for(NSInteger i = 0; i < 100000; i++){
[arr addObject:[[BKObject alloc] initWithName:@""]];
}
OK, so at this point, we have a bunch of objects retained by an array.
self.data = [NSArray arrayWithArray:arr];
And now at this point, we have a bunch of objects retained by two different arrays.
__weak BKObject *weakMutableObject = arr[0];
[arr removeAllObjects];
NSLog(@"%@", weakMutableObject); // print out the object, why?
Because the object pointed to by arr[0]
is also retained by self.data
.
__weak BKObject *weakObject = self.data[0];
self.data = nil;
NSLog(@"%@", weakObject); // print out the object again, but why?
This one is a bit interesting. The "problem" is that arrayWithArray:
is adding an extra retain/autorelease, which it's free to do since they're balanced. You can demonstrate that pretty simply by draining the autorelease pool at different points.
This shows a live object:
__weak NSObject *weakObject;
self.data = [NSArray arrayWithArray:arr]; // Note outside nested autorelease pool
@autoreleasepool {
...
weakObject= self.data[0];
self.data = nil;
}
NSLog(@"%@", weakObject); // print out the object
This shows nil:
__weak NSObject *weakObject;
@autoreleasepool {
self.data = [NSArray arrayWithArray:arr]; // Note inside nested autorelease pool
...
weakObject= self.data[0];
self.data = nil;
}
NSLog(@"%@", weakObject); // print nil
The lesson here is that you should not assume that an object will deallocate at any given point within an autorelease block. That is not a promise ARC gives. It only promises a minimum amount of time that the object will be valid. Other parts of the system are free to attach balanced retain/autorelease pairs as much as they like, which will delay deallocation until the pool drains.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With