Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to forbid the basic init method in a NSObject

I want to force user to use my own init method (for example -(id)initWithString:(NSString*)foo;) and not the basic [[myObject alloc]init];.

how can I do that?

like image 453
Anthony Avatar asked Jan 18 '12 09:01

Anthony


2 Answers

All other answers here are outdated. There is a way to do this properly now!

While it is easy to just crash at runtime when somebody calls your method, compile-time checking would be far preferable.

Fortunately, this has been possible in Objective-C for a while.

Using LLVM, you can declare any method as unavailable in a class like so

- (void)aMethod __attribute__((unavailable("This method is not available")));

This will make the compiler complain when trying to call aMethod. Great!

Since - (id)init is just an ordinary method, you can prohibit calling of the default (or any other) initializer in this way.

Note, though, that this will not insure against the method being called using the dynamic aspects of the language, for instance via [object performSelector:@selector(aMethod)] etc. In the case of init, you won't even get a warning, because the init method is defined in other classes, and the compiler doesn't know enough to give you an undeclared selector warning.

So, to ensure against this, make sure that the init method crashes when being called (see Adam's answer).

If you want to disallow - (id)init in a framework, make sure to also disallow + (id)new, as this will just forward to init.

Javi Soto has written a small macro to forbid using the designated initializer faster and easier and to give nicer messages. You can find it here.

like image 164
fzwo Avatar answered Oct 04 '22 07:10

fzwo


tl; dr

Swift:

private init() {}

Since all Swift classes include an internal init by default, you can change it to private to keep other classes from calling it.

Objective C:

Put this in your class's .h file.

- (instancetype)init NS_UNAVAILABLE;

This relies on an OS define that prevents the method named from being called.

like image 25
CodeBender Avatar answered Oct 04 '22 07:10

CodeBender