5

It seems that in code example of a book, the init is always defined so that it is careful to check whether self is able to exist.

-(id) init {

    self = [super init];
    if (self) {
        // initialize
    }
    return self;
}

However, upon return, none of the code at all checks whether the object is able to exist. But should it be checked, and how can it be handled? If the object can't exist, does that mean the system is seriously out of memory, and even popping up an error message will also be impossible?

Lorenzo B
  • 33,216
  • 24
  • 116
  • 190
nonopolarity
  • 146,324
  • 131
  • 460
  • 740
  • This is actually a pretty good question. I know I never check if I get something out of the result of this kind of function, I just assume that the alloc/init worked (unless working with something that takes &error, which represents something that has a chance of failing). A very interesting question indeed. – RonLugge Apr 27 '12 at 22:31
  • possible duplicate of [In Objective-C why should I check if self = \[super init\] is not nil?](http://stackoverflow.com/questions/1287950/in-objective-c-why-should-i-check-if-self-super-init-is-not-nil) – omz Apr 27 '12 at 22:33

2 Answers2

4

However, upon return, none of the code at all checks whether the object is able to exist. But should it be checked, and how can it be handled?

Typically, error handling is ignored by the subclasses when nil is returned. Error handling is generally left to the caller when nil is returned. As demonstrated in the idiomatic -init:

- (id)init {
  self = [super init];
  if (self) {
    // initialize
  }
  return self;
}

As well, if the base reallocates self in init, then self is reassigned (self = [super init];). works great.

If you fail to assign self to the result of super's initializer or if you fail to check for nil, then you may be holding on to a dangling/deallocated pointer (EXC_BAD_ACCESS), and you may not initialize your ivars properly (you would effectively assign them to another region if an EXC_BAD_ACCESS were not encountered).

The two cases in more detail:

Fail to assign self

- (id)init {
  [super init];
  if (self) {
    // self was not reassigned. if super returned an object other
    // than self, then our ivar would be freed, reused, or sitting
    // in an autorelease pool, and the returned instance's ivar
    // would not be assigned -- we wouldn't know the address.
    ivar = 1;
  }
  return self;
}

Fail to check for nil

- (id)init {
  self = [super init];
  // super returned nil. ivar is an invalid region:
  ivar = 1;
  return self;
}

and yes, I have seen both of these.


If the object can't exist, does that mean the system is seriously out of memory, and even popping up an error message will also be impossible?

Not at all. Many initializers return nil to say "cannot do in this context", or if there is a simple parameter error.

justin
  • 104,054
  • 14
  • 179
  • 226
  • Sorry, I don't understand how you would have a dangling pointer if you don't check for nil. If you don't check for nil, then you would effectively be sending messages to nil if a nil were to come and they would be ignored. – borrrden Apr 28 '12 at 02:14
  • Ah, I see that its actually the 2nd part (reassigning self) that you are talking about. Nevermind ^^; – borrrden Apr 28 '12 at 02:27
  • @borrrden i see you saw the update i made for you :) yes, messaging *could* be safe, if self were nil and you were to message in your initializer. however, initialization and dealloc are special partially constructed states. people argue for both sides, but direct initialization is generally the safer way to initialize an object, rather than using accessors in init/dealloc. Fail to check for nil is also a risk, as demonstrated. – justin Apr 28 '12 at 02:32
  • Just to be clear to you and everyone, I use the check for nil and reassign pattern, but (as I assume most people have not) I never thought about why...thanks for the explanation! +1 – borrrden Apr 28 '12 at 02:55
3

does that mean the system is seriously out of memory

No. A failure to allocate memory would generally cause +alloc to fail, not -init.

In reality, it's very uncommon for an init method with no arguments to fail. Generally init methods can return nil if you've passed invalid arguments, for example NSString's -initWithContentsOfFile: can return nil if it's failed to load the contents of the file path that it was supposed to be initialized with.

It's perhaps something you want to check for if you're aware of a significant possibility for failure of the init, otherwise, you should just get on with using the object.

joerick
  • 16,078
  • 4
  • 53
  • 57
  • Also, on iOS, if the system is seriously out of memory then you will be jettisoned. – Lily Ballard Apr 27 '12 at 22:39
  • @KevinBallard, yeah, the app will be killed before a memory allocation fails. And on OS X, there's such a huge virtual memory space in 64 bit that it's pretty well infeasible that an app would run out of memory. – joerick Apr 27 '12 at 22:41
  • iOS will use whatever Flash memory left as Virtual memory? (such as if 16GB iPhone has 3GB free)... however, my iPhone is so full of songs due to automatic download that only 20MB is free now. – nonopolarity Apr 27 '12 at 22:50
  • @動靜能量 iOS doesn't use virtual memory. If your app uses more memory than it is allowed the OS will terminate the app. – joerick Apr 27 '12 at 22:55
  • 3
    @動靜能量 Incorrect. While iOS does have virtual memory, it doesn't have *swap*, which means memory cannot get paged out to disk. If you run out of RAM, your app will be terminated. – Lily Ballard Apr 27 '12 at 23:02