9

If I have an NSObject subclass which either has no -init method or simply does nothing in -init, is there any difference between an instance created these two ways:

MyClass *instance = [MyClass alloc];
MyClass *instance = [[MyClass alloc] init];

By "does nothing in -init" I mean

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

Since NSObject's -init method itself does nothing, I can't see there being any difference, but of course the advice is that you must call -init to properly prepare an object.

Here's the snippet from NSObject's -init method which got me wondering about this:

The init method defined in the NSObject class does no initialization; it simply returns self.

nevan king
  • 112,709
  • 45
  • 203
  • 241
  • You're free to not implement it if it does nothing. Still, the superclass' implementation of `init` will be called, following the classic OOP principles of inheritance. – Cyrille Mar 26 '14 at 13:47
  • 2
    How do you know that NSObject's -init does nothing? How do you know it does nothing in iOS 8 and MacOS X 10.10? How do you know your class won't get derived from something else, or that you never add anything to the init method? And why would you want to write code that smells bad to save a few nanoseconds of time? – gnasher729 Mar 26 '14 at 13:50
  • 3
    tip: if you are calling alloc/init you can shortcut it by going `[MyClass new]` – Fonix Mar 26 '14 at 13:50
  • 2
    @gnasher729 from the docs: "The init method defined in the NSObject class does no initialization". I don't want to write code like this, just to understand. – nevan king Mar 26 '14 at 13:50
  • Given that `NSObject init` does nothing and your class directly extends `NSObject`, the question I would have is, does leaving off the call to `init` affect any other standard instance initialization? Normally, all ivars of an object get initialized to the appropriate form of `0`. Is this a function of `alloc` or `init`? – rmaddy Mar 26 '14 at 16:21
  • @rmaddy: It's `alloc` that zeroes the new instance's ivars. – jscs Mar 26 '14 at 18:55
  • @JoshCaswell I figured that was the case. It's a simple matter of a `memset`. – rmaddy Mar 26 '14 at 19:30

5 Answers5

9

If I have an NSObject subclass which either has no -init method or simply does nothing in -init, is there any difference between an instance created these two ways:

MyClass *instance = [MyClass alloc];
MyClass *instance = [[MyClass alloc] init];

Technically, there is no difference.

But that doesn't mean you should use a bare +alloc to ever create an instance for a variety of reasons.

First, it is the principal of the thing. Objective-C coding standards say +alloc should always be followed by -init.

Secondly, it is all about consistency and code maintenance. What happens when you refactor MyClass to be a subclass of some class where the designated initializer is actually critical? A nasty, hard to figure out, bug is what happens.

Of relevance, note that the use of +new has been all but deprecated for a similar reason. It makes refactoring tedious (dammit! gotta break apart THIS call site, too!) and the convenience factor is exceedingly minimal.

bbum
  • 162,346
  • 23
  • 271
  • 359
  • Thanks for the answer. So there's no extra "magic" in `NSObject`'s `-init`, and all the functionality (setting ivars to defaults etc) comes from `NSObject` subclasses? – nevan king Mar 27 '14 at 21:54
  • At this time, that is correct. No special behavior. That might change some day (but likely won't). – bbum Mar 28 '14 at 00:55
6

No, it's not and you're not doing nothing, you're calling [super init] and that does a lot to initialize your superclasses up until NSObject.

Maurício Linhares
  • 39,901
  • 14
  • 121
  • 158
  • 1
    But if my superclass is `NSObject` (which does no initialization), isn't `[super init]` doing nothing? – nevan king Mar 26 '14 at 13:49
  • 1
    And how come you know `[NSObject init]` isn't doing anything? You can't assume your superclass isn't doing anything, you should just always make the call, even if they're not doing anything now because it could do stuff in the future. – Maurício Linhares Mar 27 '14 at 15:00
  • I know I *should*, but I want to know why. Really I'm just trying to understand more. About `-init`, the docs state: "The init method defined in the NSObject class does no initialization; it simply returns self." – nevan king Mar 27 '14 at 15:51
  • 1
    Why should you do it? Because you should take exceptional steps only when exceptional circumstances require them. Filling your code with "haha, I'm so clever" steps for no benefit is the quickest way to ensure it collapses under its own mass, and god help anybody else that tries to make sense of it. Alternatively: being a direct sub of `NSObject` is an implementation specific detail of your class. Doing nothing additional in `init` is an implementation specific detail of your class. Other classes should not make assumptions about implementations. So use `[[MyClass alloc] init]`. – Tommy Mar 27 '14 at 16:17
  • @Tommy You're misunderstanding my question. I'm not looking for coding tricks, just to understand more about what `-init` does in `NSObject`. – nevan king Mar 27 '14 at 17:20
  • @nevanking I'm also acting incredibly impolitely but putting that aside: if `NSObject` says that its `init` does nothing then you can rely on that. But since this isn't Eiffel there's ambiguity as to whether such obiter comments technically form part of the object contract. In my experience Apple rarely changes that stuff and usually documents it correctly but you're safest saying just that it's probably a no op right now and will likely be one forever but that the guarantees are very soft. So, yeah, just call it. – Tommy Mar 27 '14 at 17:35
3

You can do it in theory. When you want to create an instance, you can do it simply using the alloc method, so this code is perfectly accepted:

NSObject *someObject = [NSObject alloc];

What creates the instance is the alloc method, so you have created an instance of NSObject.

But if you want to use it you have to initialize it, since the NSObject init method is used by a class to make sure its properties have suitable initial values at creation (Apple documentation). The most important thing done by the init method is to create the self variable, so if you want to use the instance created with the alloc method, you have to init it.

- (id)init {
    self = [super init];

    if (self) {
        // initialize instance variables here
    }

    return self;
}

Without the initialization method you have only an unusable instance.

Marco Pace
  • 3,820
  • 19
  • 38
1

alloc allocates a place in memory for the instance of the object to be stored. If you’re using a local variable it is allocated on the stack, while objects (ivars etc) are allocated on the heap.

init initialises the instance of the object and points it to the allocated memory space - this is why you must always call init after alloc.

e.g.

MyClass *instance = [[MyClass alloc] init];

In your instance your init implementation is empty so it can be removed and you can let the superclass handle it. You would override init to set some state on the object itself.

You might want to take some time to read the Apple Documentation on this if you want to brush up.

Oliver Atkinson
  • 7,970
  • 32
  • 43
  • 1
    `init` doesn't create the instance -- `alloc` does that. `init` _initializes_ the instance that is passed into it. – jscs Mar 26 '14 at 18:54
-1

Calling MyClass *instance = [MyClass alloc]; - will leave you with an invalid object. You need to allocate and initialize every object you create.

If you do it this way, all objects until MYClass will be initialised. MyClass won't though.

Robert J. Clegg
  • 7,231
  • 9
  • 47
  • 99
  • 2
    As a practical matter, yes, you must call `init`, but strictly speaking the return value of `alloc` is an actual instance. In the simplest case: `NSObject * o = [NSObject alloc]; NSLog(@"%@", [o valueForKey:@"description"]);` (Unnecessarily convoluted calling of `description` just to demonstrate that everything "works" on that instance.) – jscs Mar 26 '14 at 19:02