Objective C ARC release without assigning a variable - objective-c

In Objective C ARC, is it safe to do [[[MYObject alloc] init] callingSomeMethod]? Will it get released even if I dont assign to a variable?

Yes it will. If you're nervous about it, it's easy to verify. Just put NSLog(#"it did!"); in that object's -dealloc method and check to make sure it logs.

If you don't need the object to live after callingSomeMethod returns, it is safe to do [[[MyObject alloc] init] callingSomeMethod].
If you need the object to live after callingSomeMethod returns, then your program needs to create a strong reference to it before callingSomeMethod returns. Examples:
If callingSomeMethod sets the object as the target of an NSTimer, you are safe because NSTimer retains its target.
If callingSomeMethod only sets the object as the delegate of a UITableView, you are not safe, because UITableView does not retain its delegate. In that case, you must also create a strong reference to the object somewhere else.

Related

Objective C memory management example

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

What does ARC do if I forcefully point an allocated object's pointer to nil?

I am allocating an object like
A *a = [[A alloc] init];
At another point I am forcefully setting
a = nil;
Does it flash a message to ARC that the object can be released now?
Quick answer - YES.
Once you set your object to nil it will get killed by Arc (most of the cases, from my experience you can lay your trust on ARC)
Dealloc methods in arc will be created for you. You must not make a dealloc call directly. However you can still create a custom dealloc method if you need to release resources other than instance variables. When creating a custom dealloc method, do not call the [super dealloc] method. This will be done for you and is enforced by the compiler.
You can read more about it here
I think the original object you were pointing at (an empty A object you created with alloc/init) will be released, but you can still use your "a" pointer, and make it point at another object.

Retain or copy UIKit elements

First Question
When an object's property is retained in Objective-C, why does a second instance of the same class point to the same object? If you instantiate a new class, then you would logically want a separate class with separate properties. retain I understand increases the retain count only and copy will shallow copy.
I've created a class which has a retained NSURLRequest. I initialized two instances of that class. Changing the property on any of the created classes will change them for all. When I used copy on the property, it stopped doing that. Reading online however, it says that copy on an immutable object is essentially a shallow copy since you really do not want a separate entity since it can never be changed. In this case, NSURLRequest is immutable so how did my example work by invoking copy on an immutable object when it supposedly deep copied it? Here's how I copied it:
- (id)initWithRequest:(NSURLRequest *)request {
self = [super initWithNibName:nil bundle:nil];
if (self) {
_request = [request copy];
}
return self;
}
Second Question
I've been reading that essentially for all immutable objects, I need to use copy and for mutable objects use retain (or now in ARC, strong). If IBOutlets are weak pointers, what if I draw my views without Interface Builder? Would UIKit elements be copy or retain/strong?
Thanks!
A retain tells iOS not to release that memory even if the original property or pointer sets itself to nil which would decrement the retain count. So if you do a shallow copy which would be assigning one pointer to an existing object it will retain it. If you need to do a deep copy then you should specify copy or create a copy constructor.
A weak reference is similar to using the old method of "assign" on a piece of memory that you do not want to increment the retain count on. There are situations where you can have circular references and could potentially never release the memory. If you do not use IB to create UIKit objects ARC will be sure to retain the memory for you assuming you have a valid pointer to that object. For instance if you have a UIButton pointer as a member of a view controller and you dynamically create a button it will retain that memory for as long as that pointer is valid and release it once the pointer is set to nil.

When to use `self` in Objective-C?

It's now more than 5 months that I'm in Objective-C, I've also got my first app published in the App Store, but I still have a doubt about a core functionality of the language.
When am I supposed to use self accessing iVars and when I'm not?
When releasing an outlet you write self.outlet = nil in viewDidUnload, instead in dealloc you write [outlet release]. Why?
When you write self.outlet = nil the method [self setOutlet:nil]; is called. When you write outlet = nil; you access variable outlet directly.
if you use #synthesize outlet; then method setOutlet: is generated automatically and it releases object before assigning new one if you declared property as #property (retain) NSObject outlet;.
Very very important blog to understand about properties getter-setter method in objective c
Understanding your (Objective-C) self
http://useyourloaf.com/blog/2011/2/8/understanding-your-objective-c-self.html
You use self when you are refering to a #property.
Usually it will have been #synthesize'd.
You do not use self if you are refering to a "private" variable. Typically, I use properties for UI elements such as UIButtons or for elements I want easily reachable from other classes.
You can use the #private, #protected modifiers to explicitly enforce visibility. You cannot however use private methods, that do not exist in Objective-C.
The part about nil, release and dealloc is unrelated to the use of "self". You release what you retained, you nil what is autoretained.
You should read the Objective-C guide, it's well written and very enlightening.
You use self. when you're accessing properties of class that you're in (hence self). Basically you use self when you want to retain a value, but is only when you have retain in your property definition.
release just releases object that you've retained. You shouldn't release something that you haven't retained cuz it will lead to crash (zombie object).

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.