Reputation: 531
What I've found using the profiling tool in Xcode (Allocations) is that when you nil out a property it does not get deallocated until the parent class gets nilled out. Now let's say you want to make sure that you don't keep an expensive modal view controller in memory (assuming that it won't get used very often), if the expensive VC is a property, the allocated memory for that property will not get released when the property gets nilled out, which means that when the user wants to use the expensive VC again we'll allocate the same amount of memory each time. This is easy to spot in the profiler as the graph just keeps climbing.
However, if I only define the expensive VC as an instance variable and define my own setter&getter the profiler allocation graph actually decreases immediately when the variable gets nilled out and goes back up with the same amount upon each new allocation.
So my question is, why does a variable 'seem' to get deallocated when defined as an instance variable but not when defined as a property?
// What I call defining something as an instance variable:
@interface SomeViewController ()
{
UIPopoverController *somePopover;
}
// What I call defining something as a property
@property (nonatomic,strong) UIPopoverController *somePopover;
// Nilling out a property which does not get allocated unless it does not have a parent (root node memory graph wise)
self.somePopover = nil;
// Nilling out an instance variable which does make the memory graph in the profiler go down by the same amount it went up
somePopover = nil;
AFAIK, you cannot force an object to release all of its memory until its parent calls deallocate whereupon all of its children get cascade deallocated.. https://stackoverflow.com/a/7631831/2536815
Upvotes: 2
Views: 876
Reputation: 531
So it seems like I just confused hiding/showing an expensive view with allocating/nilling, the memory graph goes down when the view isn't visible and vice versa, really silly of me I know..
Just to verify that you cannot force arc to release a property/ivar I created a new xcode project where I just put the code below in the didFinishLaunching method. And unfortunately the memory allocated for the property and ivar are kept in memory no matter if I nil them out or not. In my case the code below generates 2.8 MB of memory and when this method finishes and the application launches the profiler memory graph stays at 2.8MB indefinitely..
@interface SSAppDelegate ()
{
NSMutableArray *ivVC;
}
@property (nonatomic, strong) NSMutableArray *propertyVC;
@end
@implementation SSAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
for (int k=0; k<10; k++) {
ivVC = [NSMutableArray array]; // Doesn't matter if it's alloc] init]
self.propertyVC = [NSMutableArray array];
for (int i=0; i<1000;i++) {
[ivVC addObject:@"..................................................................................."];
[_propertyVC addObject:@"..................................................................................."];
}
ivVC = nil;
self.propertyVC = nil;
}
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Upvotes: 0
Reputation: 79033
I don't think your analysis is correct. If properly used, both a property and an instance variable have the same effect on reference counting: setting it to nil decreases the reference counter and if it goes to 0, the instance (be it a view controller or something else) is immediately deallocated.
If this is not the case in your app, then the cause must be something else than property vs. instance variable.
To further analyze your specific problem, we'll need more information. So please post your code, describe the set up for measuring the memory management effects, what the effective results are and what you would expect instead.
Upvotes: 6