views:

888

answers:

5

I'm just starting out (reading up a lot for the past couple of days). Here's some questions that I have stacked up, hopefully someone can answer them.

1. the (self != nil) check in initializer code. Why do it? To prevent accidental access to some "run-only-once" code that's wrapped up in there? Where from could this accidental access come from? Doing such checks suggest that I don't have control over what's going on.

- (id)init {
    self = [super init]
    if (self != nil) {
    // Code..
    }
    return self;
}

2. How is it that you don't have to free up anything that static methods return? (or this is the idea I've got)

3. How is str = @"Hi there!" different from

str = [[NSString alloc] initWithString:@"Hi there!"];

As I understand, you have to release str in aquired with second method, but not with first? If so, when does the first one get released? Which one is preferable (not minding the typing length)?

4. What is autorelease, if iphone has no garbage collection? I've noticed something called "an autorelease pool" being created in main.m. Is [myObject autorelease]; a way of adding myObject to the nearest wrapping "autorelease pool", which will release it? Basically, some magic to avoid releasing it yourself? Why use it?

Well, thats it for now. Thanks for any answers!

+1  A: 

1: This check is to ensure that the super constructor returned a new object.

2: Static methods don't refer to an instance

3:

str = @"Hi there!"

This assigns the address of the constant string "Hi there!" to the pointer str

str = [[NSString alloc] initWithString:@"Hi there!"];

This allocates a string and copies "Hi There!" to it. This means that a) str is modifiable and b) needs to be deallocated when you are done with it.

Brian Mitchell
But in general sense, both str usages would consume same amounts of memory, just that the first one is immutable. Doesn't using the second method guarantee the space is freed whenever I need it? Simply asigning @"Hi there!" takes up space too, no? But no control over that space in memory, right?
Karolis
NSString is immutable, so str is not modifiable in either instance.
Jason Coco
No, str is a mutable container for an immutable string.
Brian Mitchell
Brian, so basically, it's possible to change the value of str using the second method, by releasing current value and allocating a new one? How would that be done? [str release]; str = [[NSString... ?
Karolis
+1  A: 

calling

self = [super init];

May return nil if the superclass cannot initialize itself for some reason or other, including memory being unavailable, or certain prerequisites have not been met. If that is the case, you don't want to be trying to set variables of self, or set self as a delegate, or add self to an array, if self is nil.

The autorelease pool is something created upon every event the iPhone sends your application. It is created before any code runs, and released after all your code is done, for each event. Any objects that you call autorelease on will be put into the current autorelease pool. Any objects in the autorelease pool will be released as many times as they were added, after your code completes. In this way, you don't have to worry about who's responsible for releasing an object created by one method and returned to another method.

You can create your own autorelease pools as necessary.

str = [[NSString alloc] initWithString:@"Hi there!"];

This line creates a string that is not in an autorelease pool, so you have to release it manually. Simply writing

@"Hi there!";

returns a string that you don't have to worry about releasing. Extending your previous example:

str = [[[NSString alloc] initWithString:@"Hi there!"] autorelease];

would be another method of creating a string you don't need to worry about releasing.

One difference between garbage collection and autorelease pools is that garbage collection works with circular references. Using autorelease pools, you don't want to have two objects that retain each other and hope that once nothing else refers to them, they will go out of existence; they won't.

Ed Marty
So the benefit of putting objects into autorelease pools is not having to release them manually, but the drawback is loosing control on *when* to release it? Basically, if I give my object to autorelease pool, I'm at it's mercy for releasing it whenever that happens?
Karolis
You may lose control of when you release it, but not when it becomes deallocated. If you want to keep around an object that has been placed in an autorelease pool, you can simply call [obj retain] so that its retain count is still larger than 1 after the autorelease pool releases it.
Ed Marty
+1  A: 
  1. If self is nil after the super initialisation then you're probably out of memory. Your only reasonable course of action is to return nil and hope things get handled gracefully further up the stack.

  2. Static methods aren't allowed allocate on the heap, therefore there's nothing to free.

  3. In the first instance, the string is compiled into the data segment of your app and cannot be freed. In the second instance, you are allocating memory from the heap and copying your static string (from the data segment) into it.

  4. It's simple garbage collection. As to why to use it, the simple answer is don't. It's not recommended to use autorelease on the iPhone due to limited resources.

edoloughlin
So basically, str = @"Hi there!" sits in this data segment for the whole app runtime, regardless of wether the code portion doing the asignment is reached or not? In other words, the more such strings I have, the more memory my app will require initially? Thanks
Karolis
"Hi there!" sits in the bss section, str (that is, the storage for the 4-8 bytes it takes to represent an address) sits in the data section. str is initialized with the address of the string in the bss section.
Brian Mitchell
+2  A: 
  1. There is a school of thought that in most cases, allocating the self pointer is something that the system should do, and not the programmer.

Also, many people prefer to keep the main line of program flow as un-indented as possible. In which case the initialisation code could be re-written as:

- (id)init {
    if (![super init]) {
        return nil; // There is a problem so bail early.
    }
    // Initialisation code here.
    return self
}

Will Shipley explains this much better than I do.

Abizern
Thanks, that blog post was very helpful. And confusing. I understand it talks about Cocoa, not Cocoa Touch, so maybe doing this check is still valid for reasons mentioned by others in iPhone environment (out of memory situations)?
Karolis
If you are just starting out, it might be confusing. I brought it up as an example that there are other ways of writing even simple things as initialisers. Bookmark Wil's "Pimp My Code" series and go back to it after a few months; you'll find it useful for thinking about writing Cocoa/Obj-C code.
Abizern
Objective-C is the language. Cocoa and Cocoa Touch are frameworks. Although some patterns differ between the two, the principles of Objective-C (including the init pattern) apply to both.
Barry Wark
+7  A: 
Barry Wark
Fantastic answer!
Jarret Hardie
Such a well thougth out, filled with examples reply. Thank you, most of it is clear now. Accepted.
Karolis