简体   繁体   中英

Some beginner Objective-C/iPhone questions

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. In Objective-C, it's possible to return an instance other than self from -init . Classes do this, for example, to enforce a singleton instance, or in the case of class clusters. NSNumber , for example, returns a subclass depending on the type of value passed to its initializer. So when you call [[NSNumber alloc] initWithLong:long_value] , NSNumber 's -initWithLong: initializer is called after NSNumber 's +alloc , but a subclass of NSNumber may be returned to the oringial caller. Thus the pattern

    self = [super init];

    which reassigns self to the value of [super init] so that self points to the actual instance that [super init] returned. If +alloc or the super's init method fails, the result of [super init] may be nil . To avoid, side effects in the case of a failed initialization, the pattern then becomes

     - (id) init { if(self = [super init]) { // do initialization of instance variables etc. } return self; } 

    Note that you must return self (or nil or an other instance) from the init method. You should assign self to [super init] and you may check for nil before doing more work.

  2. You may have to release the return value of a staic method. You should read the Cocoa memory management guide . The rule is generally quite simple: If the method you call has "new", "alloc", or "copy" in its signature, the result belongs to the caller and the caller must call -release on that instance or there will be a memory leak. Of course you should call -retain on anything else (ie not from an "alloc","new" or "copy" method) you want to keep a reference to and then call -release or -autorelease when you are done with that instance.

  3. str = @"Hi there!" , assuming str was declared as NSString *str; assigns the address of the string constant @"Hi there!" to the value of the @"Hi there!" to the value of the str variable. You do not need to retain or release string constants. variable. You do not need to retain or release string constants. str = [[NSString alloc] initWithString:@"Hi there!"]; allocates a new string instance. The value of allocates a new string instance. The value of str will be the address of this instance. Each call of will be the address of this instance. Each call of str = [[NSString alloc] initWithString:@"Hi there!"]; again will allocate a new instance. So after again will allocate a new instance. So after str2 = [[NSString alloc] initWithString:@"Hi there!"]; , str != str2 , while after str2 = @"Hi There!", str==str2 . See this answer as well.

  4. -autorelease adds the receiver to the current NSAutoreleasPool . When the pool is drained (usually at the end of the current run loop iteration, or when the pool is manually drained), the pool calls -release on all instances in the pool. If this -release drops the retain count to 0, the object is deallocated (and -dealloc called) just as with any other -release . Using an autorelease pool is generally frowned upon on the iPhone because it may cause you to accumulate many unused instances in the pool before it is drained at the end of the run loop iteration. If you can use -release instead of -autorelease , you generally should. Again, see the Cocoa memory management guide for more info.

  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.

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.

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.

  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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM