Objective C memory management example - objective-c

I'm trying to learn objective c and I'm still a bit confused with memory management.
Yes I know, I should use ARC, but my project uses TouchXML that does not support it.
Also there is a lot of documentation and threads about memory management that I have read but I still have some doubt that I hope you guys will help me to clarify.
I've learnt that who allocs an object is then responsible to free it. I've also learnt that "retain" increments the reference counter whereas "release" decrements it. When an object's reference counter reaches 0, it is automatically de-alloced.
I've finally learnt that "autorelease" releases the object automatically at the end of current event cycle. That's fine.
Now please consider the following case:
I alloc an array that I need to use for the full lifecycle of my object. I'm responsible to release it when my object is deleted:
#implementation MyClass
-(id) init {
myArray = [[NSMutableArray alloc] init]; // this is a #property
}
- (void) dealloc {
[myArray release];
[super dealloc];
}
#end
In this way, in dealloc method, myArray release also causes myArray o be deallocated.
If I then instance a new object from myClass and retain myArray like this...
// MyOtherClass
MyClass *o = [[[MyClass alloc] init] autorelease];
NSMutableArray *retainedArray = [[o.myArray] retain];
...at the end of current event cycle, "o" will be automatically deallocated, whereas retainedArray (actually pointing to o.myArray) will not be deallocated until I'll call [retainedArray release].
Is this correct up to here?
If so, I also guess the same applies if I call something like:
NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:#"somePath" error:nil];
I don't need (actually I can't otherwise it will give a runtime error) call either release or autorelease for "contents" unless I retain it somewhere in my code. Correct?
If so, summing everything up, in the end I only have to call release if I call either alloc or retain. The balance of reference counts in my class should always be 0, where alloc / retains gives +1 and release gives -1. Correct?

It is almost 100% correct what you said, but there are a few more cases where you get
a (+1) retained object that you have to release.
The basic rules are (see "Basic Memory Management Rules"):
You must eventually release or autorelease objects that you own.
You own objects that you created using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy”
You own an object if you take the ownership using retain.
The "Static Analyzer" (Product -> Analyze in the Xcode menu) is quite good at finding
violations to this rule, so I can only recommend to use that.

You can use Touch XML with ARC just fine. I use TouchXML in my project also. Just go to project build phases, double click on each Touch XML.m file, and enter -fno-objc-arc. This will disable ARC for that file.
If you know a lot about memory management or really want to learn more about memory management, then use MRC, but if you want to avoid the hassle, use ARC.

no direct answer to your question, but you also can use non-ARC Code in an ARC Project:
http://www.codeography.com/2011/10/10/making-arc-and-non-arc-play-nice.html
Best regards
Bernhard

Related

How to enforce using `-retainCount` method and `-dealloc` selector under ARC?

Under ARC, compiler will forbid using any method or selector of -retainCount, -retain, -dealloc, -release, and -autorelease.
But sometimes I want to know the retain counts at runtime, or using method swizzling to swap the -dealloc method of NSObject to do something.
Is it possible to suppress (or bypass) the compiler complaining just a couple of lines of code? I don't want to modify ARC environment for whole project or whole file. I think preprocessor can do it, but how?
Additions:
Thanks guys to give me a lesson about the use of -retainCount. But I wonder whether it is possible to enforce invoking/using those forbidden methods/selectors.
I know Instruments is a powerful tool to do this job. But I am still curious about those question.
Why do I want to use -retainCount:
When using block, if you don't specify a __weak identifier on the outside variables, the block will automatically retain those outside objects in the block after the block is copied into the heap. So you need to use a weak self to avoid retain cycle, for example:
__weak typeof(self) weakSelf = self;
self.completionBlock = ^{
[weakSelf doSomething];
};
However, it will still cause retain cycle when you only use instance variables in the copied block (YES, although you didn't use any keyword self in the block).
For example, under Non-ARC:
// Current self's retain count is 1
NSLog(#"self retainCount: %d", [self retainCount]);
// Create a completion block
CompletionBlock completionBlock = ^{
// Using instance vaiable in the block will strongly retain the `self` object after copying this block into heap.
[_delegate doSomething];
};
// Current self's retain count is still 1
NSLog(#"self retainCount: %d", [self retainCount]);
// This will cuase retain cycle after copying the block.
self.completionBlock = completionBlock;
// Current self's retain count is 2 now.
NSLog(#"self retainCount: %d", [self retainCount]);
Without using -retainCount before/after the copied block code, I don't think this retain cycle caused by using instance variables in the completion block will be discovered easily.
Why do I want to use -dealloc:
I want to know whether I can use method swizzling to monitor which object will be deallocated by logging messages on the Xcode console when the -dealloc is invoked. I want to replace the original implementation of -dealloc of NSObject.
That's not recommened at all, I dont know your intentions but they dont sound very safe.
The use of retainCount is not recommended.
From AppleDocs:
This method is of no value in debugging memory management issues.
Because any number of framework objects may have retained an object in
order to hold references to it, while at the same time autorelease
pools may be holding any number of deferred releases on an object, it
is very unlikely that you can get useful information from this method
And, if there's any doubt, check this link:
http://whentouseretaincount.com/
Whatever you are trying to do, please dont.
For future references, I'm going to add some linsk to help you understand the process of how memory works in iOS. Even if you use ARC, this is a must know (remember that ARC is NOT a garbage collector)
Beginning ARC in iOS 5 Tutorial Part 1
Understand memory management under ARC
Memory Management Tutorial for iOS
Advance Memory Managment
And, of course, once you understand how memory works is time to learn how to profile it with instruments:
Instruments User Guide
Agreed 100% with the other commenters about the fact that you do not want to use -retainCount. To your other question, however, about -dealloc:
You also do not want to swizzle -dealloc. If you think you want to swizzle it, you don't understand how it works. There are a lot of optimizations going on there; you can't just mess with it. But, as #bbum hints at, you can easily get notifications when objects are deallocated, and this can be very useful.
You attach an associated object to the thing you want to watch. When the thing you want to watch goes away, so does the associated object, and you can override its dealloc to perform whatever action you want. Obviously you need to be a little careful, because you're in the middle of a dealloc, but you can generally do most anything you'd need to here. Most importantly for many cases, you can put a breakpoint here or add a logging statement, so you can see where the object was released. Here's a simple example.
With ARC
const char kWatcherKey;
#interface Watcher : NSObject
#end
#import <objc/runtime.h>
#implementation Watcher
- (void)dealloc {
NSLog(#"HEY! The thing I was watching is going away!");
}
#end
NSObject *something = [NSObject new];
objc_setAssociatedObject(something, &kWatcherKey, [Watcher new],
OBJC_ASSOCIATION_RETAIN);
Without ARC
const char kWatcherKey;
#interface Watcher : NSObject
- (void)lastRetainDone;
#end
#import <objc/runtime.h>
// turn off ARC!
#implementation Watcher
{
BOOL noMoreRetainsAllowed;
}
- (void)lastRetainDone {
noMoreRetainsAllowed = YES;
}
- (id) retain {
if (noMoreRetainsAllowed) abort();
return [super retain];
}
- (void)dealloc {
NSLog(#"HEY! The thing I was watching is going away!");
[super dealloc];
}
#end
...
NSObject *something = [NSObject new];
Watcher *watcher = [Watcher new];
objc_setAssociatedObject(something, &kWatcherKey, watcher,
OBJC_ASSOCIATION_RETAIN);
[watcher lastRetainDone];
[watcher release];
Now, when something goes away, -[Watcher dealloc] will fire and log for you. Very easy. Completely supported and documented.
EDIT:
Without using -retainCount before/after the copied block code, I don't think this retain cycle caused by using instance variables in the completion block will be discovered easily.
You are somewhat correct here, but there are two lessons to be learned, and neither is to use retainCount (which won't actually help you in this case anyway because retainCount can very often be something you don't expect).
The first lesson is: Do not allow any warnings in ObjC code. The situation you're describing will generally create a compiler warning in recent versions of clang. So it's actually quite easy to discover in many cases. The way you've separated it into multiple assignments, the compiler may miss it, but the lesson there is to change your coding style to help the compiler help you.
The second lesson is: don't access ivars directly outside of init and dealloc. This is one of the many little surprises that can cause. Use accessors.

Is it ok to call release on a property in Objective C?

I've been teaching myself Objective C recently, and have noticed the following pattern used a lot in tutorials and sample code (including samples from the Apple site).
UIView *myUiView = [[UIView alloc] init];
self.uiView = myUiView;
[myUiView release];
I was just wondering though, it seems a bit of a waste to create a new variable, just to set a property. I've also seen the following pattern used too, but from what I understand its considered bad form to use autorelease on an iOS device as the autorelease pool takes up quite a bit of overhead which might not be good on a mobile device
self.uiView = [[[UIView alloc] init] autorelease];
I've been toying with using the following pattern recently, which sets the property, and then calls release on the property (to decrease the reference counter on the property itself).
self.uiView = [[UIView alloc] init];
[self.uiView release];
I've managed to use it on a few ViewControllers with no ill effects, but is this valid code, or am I missing something which makes it a bad idea?
The property getter is a method, and it does not have to return an ivar, it may actually get its return value anywhere, so you could release that, but it could be an autoreleased value already. If that is the case, you're in trouble.
IOW, if a property getter would do something like (not usual, but possible and valid):
- (NSString *) helloString
{
return [[myStringIVar copy] autorelease];
}
and you do:
[self.helloString release];
then you failed in two ways:
You did not release the ivar you wanted to release
You release an autoreleased object
IMO, it is better to release the ivar directly:
[myStringIVar release];
If the implementation of the property getter is simply to return the reference to the underlying ivar, then it is perfectly equivalent and you simply decrease the retain count of the allocated object.
On the other hand, if you can't be sure what the getter does (what if it returns something else than the ivar, e.g. some calculated result etc.), it may be dangerous.
No. It's not valid.
It will probably work on most retain properties but not necessarily. It will probably break on copy properties and assign properties.
Properties are just a pair of methods, one of which sets an abstract entity and one which gets it. There is absolutely no guarantee in general that the getter will give you the exact same object that you just passed to the setter. For instance, if you pass a mutable string to an NSString copy property, you definitely won't get back the same object.
Use either of the first two patterns. The first one does not waste anything. It is likely the local variable will only ever exist in a register. The overhead of the second will only last as long as the next autorelease pool drain and is only a few bytes (bear in mind that the actual object will last as long as self in any case).
It's not valid, and even in the cases where it does work its a bit "ugly" the other two are just to fix the property's retain characteristic from making the retain count 2 after having an alloc already making the retain count 1.
I tend to do what you described in the first example or the following.
in my #interface
#property (nonatomic, retain) UIView *uiView;
in my #implementation
#synthesize uiView = _uiView;
then when I setup the property.
_uiView = [[UIView alloc] init];
Thinking in terms of the reference counter, nothing is wrong with calling release using the property value. However, there are a few things, which I (personally) would dislike:
The property syntax is really just syntactic sugar for method calls. So, what your code really looks like, is
[self setUiView: [[UIView alloc] init]];
[[self uiView] release];
Another thing here might be more due to me thinking in strange ways, but I like to think of the reference counts as actually being related to references. A local variable holding a pointer to my object is such a reference. Having it present in the code reminds me, that I have something to do in order to clean things up properly (or, if not, at least write a short comment, why I don't have to clean up).
Directly going through the property forces me to think in terms of reference counts instead, which I don't like.

How do I fix a memory leak?

After doing a long profile test, I found that in one of my ".m" file memory leak occurs in the viewdidload section. i checked and the xcode highlighted the part where i have initialized picker arrays with values. my program uses pickers for user input. and i have 3 5 different views in my program. the first is a disclaimer ,the second is a menu where the user can choose the type of calculation he/she wants to do. each calculation requires certain inputs which the user enters from a picker. for eg. one of the view has 5 inputs which are handled by 5 different uipickers with seperate arrays for holding the values. these arrays are initialized with the values in the viewdidload method of that view. here is what i found after running the test:
...................................................................................................
This is my first time developing an app and i'm kinda confused about what to do. Any help would be appreciated.
Objects in objective c have a retain count. If this retain count is greater that 0 when the object goes out of scope (when you stop using it), it leaks.
The following things increase the retain count
[[alloc] init]
new
copy
[retain]
adding an object to an array
adding an object as a child (e.g. views)
There are likely more, but you don't appear to use any others in your code
The following decrease the retain count
[release]
removing an object from an array
if you dealloc an array, all of its objects are released
You should go through your code and ensure each of the retains or additions to an array are matched with a corresponding release. (You can release member variables in the dealloc method).
EDIT: Jeremy made a valid point that my answer doesn't
Once you add an object to an array, it takes ownership and will release the object when it is done with it. All you need to do is make sure you release anything you own according to the memory management rules
There are also autorelease objects, have a look at this example;
-(init){
...
stagePickerArray = [[NSMutableArray alloc] init];
for (int i = 0; i < 3; i++)
{
//this string is autoreleased, you don't have call release on it.
//methods with the format [CLASS CLASSwithsomething] tend to be autorelease
NSString *s = [NSString stringWithFormat:#"%d", i);
[stagePickerArray addObject:s];
}
...
}
I think the only thing you are missing is a call to release in your dealloc method
-(void) dealloc
{
[stagepickerarray release]; //Do this for each of your arrays
[super dealloc];
}
The leaks tool will only tell you where yo allocated the objects that it thinks leaks. So, it's telling you, for instance, that
NSString* answer = [NSString stringWithFormat: ...
allocates an object that is never deallocated. Now, -stringWithFormat: gives you an object that you do not own and you don't seem to retain it anywhere. Therefore, you do not need to release it, so it can't be leaking by itself.
That means something else that you do own must be retaining it and you never release that something else. The prime suspect would appear to be stagePickerArray. Check that you are releasing stagePickerArray somewhere. If it's local to -viewDidLoad it must be released or autoreleased before the end of that method. If it's an instance variable, it must be released in the class's -dealloc method.
In Objective-C you need to take care of the retain count of allocated memory. If you don't need it -> release it.
Whenever you alloc an object, it will return an object with retain count = 1.
By using retain, the retain count gets incremented,
by using release, the retain count gets decremented.
Whenever the retain count is equals 0, the object will be destroyed.
So whenever you want to use the object somewhere else you need to retain it. So you make sure that the object is not deleted after the other 'person' (or whatever it used ;)) called release.
This was a very very very short description. Check the following guide
Memory Management Guide for iOS.
(Also you want to read something about ARC - Automatic Retain Counting - which is new in iOS5! ios5 best practice release retain

Why does iPhone sample code use so many intermediate variables?

I'm currently working through Apress's "Beginning iPhone 3 Development". A standard they use in their example applications is like the following code:
- (void)viewDidLoad {
BlueViewController *blueController = [[BlueViewController alloc]
initWithNibName:#"BlueView" bundle:nil];
self.blueViewController = blueController;
[self.view insertSubview:blueController.view atIndex:0];
[blueController release];
}
8.14.11 UPDATE (additional information)
blueViewController is declared as follows:
#property (retain, nonatomic) BlueViewController *blueViewController;
Whenever they perform an alloc they put it in some temp variable (here blueController) then they assign it, then they release it. This temp variable seems superfluous to me.
I simplified the code as follows:
- (void)viewDidLoad {
self.blueViewController = [[BlueViewController alloc]
initWithNibName:#"BlueView" bundle:nil];
[self.view insertSubview:blueViewController.view atIndex:0];
}
- (void)dealloc {
[blueViewController release];
[super dealloc];
}
My modified code ran just the same in the iPhone simulator.
Now, I know the rule that if you alloc something you need to release it. And I'm covering that in my dealloc method. But is there some advantage to having a release directly in the ViewDidLoad (the function where the alloc was called)? Or is it equally ok to have a release in your dealloc method like this?
Thanks for any help,
-j
Assuming blueViewController is a retain property, the temporary variable is not superfluous. Your simplification is creating a memory leak. This statement from the second snippet leaks:
self.blueViewController = [[BlueViewController alloc]
initWithNibName:#"BlueView" bundle:nil];
In terms of ownership, you own the object returned by alloc-init and then the property accessor claims ownership of the object again, resulting in the object being over-retained.
Using a temporary variable solves this problem. Another option is to use autorelease:
self.blueViewController = [[[BlueViewController alloc]
initWithNibName:#"BlueView" bundle:nil] autorelease];
Note that after this statement you effectively own the object and you must release it in dealloc.
You did not mention how the property blueViewController is declared. Anyway, whatever the semantics of the setter are (retain, copy, assign), that statement is wrong. I already explained the most likely scenario: retain. Let's have a look at the other two possibilites (without considering if they make sense at all):
If blueViewController happened to be a copy property, the statement would leak too. The property accessor copies the original object and now the property holds a pointer to the copy and you lost track of the original object, immediately leaking it.
The least likely scenario is that blueViewController is an assign property because this is most likely wrong and you really want retain. But, anyway, the assign properties are for objects you do not own, e.g. delegates, and you are not supposed to release them. You are assigning an object you own to it, so either you leak it or you incorrectly release the assign property.
#property (retain) MyCLass *obj;
MyClass *tmpObj = [[MyClass alloc] init];
self.obj = tmpObj;
[tmpObj release];
In the first line you get ownership once via alloc. Then in 2nd line you get ownership again as the property is retained. In 3rd line you release the ownership that you got via alloc. Now you have a single ownership via retain property which you may release in future, may be in dealloc.
Now consider what happens if you remove the tmpObj.
self.obj = [[MyClass alloc] init];
In this line you get ownership twice, once via alloc and once via property. Now [obj release] once is not enough. You need to release it twice to avoid the leak, and naturally releasing twice is extremely bad and possible source to further memory leak. If you make another call to self.obj = anotherObj then you are leaking the old one. To avoid this you need this temporary pointer.
There's two reasons I can think of off the top of my head; the first, more specific to the example, is that you will often see similar methods where blueController is allocated and initialized, then tested for validity before actually being assigned to self's ivar. Following this pattern in every such method will make it easier for you to do tests in between creating the object and assigning it, should you realize that needs to happen. To my knowledge, if such an intermediary indeed remains superfluous, the compiler should optimize it out.
The second, more general purpose for this pattern within Cocoa is simply that Obj-C and Cocoa encourage extremely long, verbose names for methods and variables, so a single method call could end up spanning multiple lines; using method calls as direct arguments for other methods can quickly become unreadable, so conventions encourage setting up each argument for a method ahead of time, placing them in intermediary variables, then using the variables as arguments to enhance readability, and make it easier to change a single argument without having to dig around nested method calls.

Allocating and releasing memory in iPhone Xcode 3.2.5, iOS 4.2.1

I am having a strange issue with tableview showing (null) when another ViewController comes and goes. I traced it down to the place that it reads the data to display to the tableview and found that it read null for data. To debug this, I need to understand how memory management really works for iPhone. I used the following code in my application delegate to create an array of objects. This was from a sample code which I modified for my app. My question is when one creates an array like this, would the [tempArray release] actually release the array that was just created?
//Initialize the hardware array.
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
self.hardwareArray = tempArray;
[tempArray release];
This type of code seems to be very common for iPhone. The tutorials keeps saying for example, now that you passed the data to the controller you can release it. But my C and C++ experience tells me, if you release the memory it would be gone, and if its address is sitting someplace on the stack, its no good. Is the data being copied to another place rather than address being passed?
Also when releasing memory in a set routine like the one below, should I be checking to see if the modleName is not nil before releasing it. What happens if one released modelName that is already nil?
-(void) setModelName:(NSString *)newValue {
self.isDirty = YES;
[modelName release];
modelName = [newValue copy];
}
My question is when one creates an array like this, would the [tempArray release] actually release the array that was just created?
If the #property of the object is assign it would get released. But usually you use retain or copy as #property. And if the property is retain, the setter you call with self.hardwareArray = ... (ie [self setHardwareArray:...]) will retain the object. If the property is copy it will create a new object that is retained already.
Also when releasing memory in a set routine like the one below, should I be checking to see if the modleName is not nil before releasing it. What happens is one released modelName that is already nil?
In objective-c messages sent to nil are perfectly legal. No need to worry, no need to check for nil.
If you release an instance variable outside of dealloc you should set it to nil after releasing it.
release doesn't do what you think - it isn't equivalent to free() or delete and doesn't cause the memory to be gone.
It really is important to fully understand the few simple memory management rules before you do any coding. It's not difficult, the best resources are the Apple Developer Guides, like this one
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html%23//apple_ref/doc/uid/10000011i