tags:

views:

187

answers:

5

Is it possible to create a class with no init method so as to force all callers to create the object with a factory method instead?

A: 

Sure. In Objective-C, there are no actual constructors. init-type methods are typically used to initialize a class, in the same vein as a constructor, but they're just a "normal" method (there's nothing special about them like there are with, e.g., Java constructors).

That said, unless your class does no initialization for its instances, you probably want to have some sort of init method.

mipadi
+1  A: 

NSObject implements an init method for you that does whatever it does. If your class has nothing to setup when it's instantiated then simply do not override the -(id)init method provided by NSObject. But you still call it when you create the instance.

Squeegy
+1  A: 

Depends. If you have your class inherit from NSObject, it will have the inherited init method (which does nothing to your instance variables). So in that sense, even if you really really wanted to not have an init method, you'd most likely still have one. So if your question was "Do I need to implement a trivial init method?", the answer is "no, you don't need to". However, if your question was "Do I need to call the init method if I didn't override it?", then the answer is "yes, you do". Whatever you do with NSObject subclasses, at some point you still need to call init after the object is created. Such is the way of life.

That being said, you most likely want an init method, unless your object initialization requires nothing more than zeroing your whole object.

Otherwise, if you choose to not inherit from NSObject or any of its subclasses and just inherit from nothing, which is clearly a bad idea because of how the NSObject class deals with everything the ObjC runtime needs to do and the requirements are quite high, then you'll potentially end up with no init method at all. But seriously, don't try this at home.

zneak
+2  A: 

If you really wanted to cause trouble for users of your class who use init, you can do:

@implementation MyClass

- (id) init
{
    // Still have to make sure the runtime has initialised everything for "self"
    self = [super init];
    if (!self) return nil;
    [self release]; // some say you should use [super dealloc]
    [super doesNotRecognizeSelector:_cmd];
    return nil;
}

@end

You invoke super's doesNotRecognizeSelector: because you might want to implement your own behaviour for unrecognised selectors for your class.

dreamlax
Why can't we just return nil?
Casebash
Oh, yeh if its been allocated we should release
Casebash
You can just return nil, and that's probably the better choice here.
Chuck
@Chuck: do you mean to just return nil and have no `[self release]` or do you mean to have just `return nil;` as the whole method?
dreamlax
I meant as opposed to sending `doesNotRecognizeSelector:`, which raises an exception and thus stops the method there.
Chuck
@Chuck: Just returning `nil` doesn't fit the requirements, he wants to stop people using this method. It even says in the docs for `doesNotRecognizeSelector:` to use it in `init` to prevent people calling it.
dreamlax
At the very least the release needs to go first. The release will never happen as is.
Chuck
@Chuck: Yeah good call.
dreamlax
+2  A: 

So basically, you want to make sure that your class is never initialized using -init, right? You can't do exactly what you want to do, but you can come close.

Since you inherit from NSObject, you have an init method and there's nothing you can do to prevent it from being called. That said, you could override init to this:

- (id)init
{
   [self dealloc];
   @throw [NSException exceptionWithName:@"MyExceptionName" reason:@"Reason" userInfo:nil];
   return nil;
}

This way, anytime someone calls your -init method, it kills the object, so practically speaking, your init method is pretty much un-callable.

Does objective-c have something like a not implemented exception?
Casebash
You actually don't need the return at the end - it will never be reached
Casebash
Objective-C is exception-unfriendly as it can cause objects to be leaked all over the place (since their `release` calls can be never reached). If you don't use the garbage-collected runtime, however sad that may sound, you're better off simply not using them.
zneak
zneak – exceptions are used regularly for programming errors. In a correct app, exceptions are not thrown at runtime. This is a programming error, so it's fine. Casebash – yes, call `[self doesNotRecognizeSelector:]`. This is in fact the recommended way to handle this init case. See [these docs][1].[1] http://developer.apple.com/mac/library/documentation/cocoa/reference/Foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/occ/instm/NSObject/doesNotRecognizeSelector:
Ken