Accessing NSObject's (superclass) version of allocWithZone while bypassing overriding (subclass) version of allocWithZone - objective-c

In iOS Programming Book from Big Nerd Ranch (3rd ed) they say on pg.194
..a knowledgeable programmer could still create an instance of BNRItemStore via allocWithZone:, which would bypass our sneaky alloc trap.To prevent this possibility, override allocWithZone: in BNRItemStore.m to return the single BNRItemStore instance.
+(id) allocWithZone:(NSZone *)zone
{
return [self sharedStore];
}
This statement seems confusing to me. Doesn't this following code not prove this wrong in a way-
#import <Foundation/Foundation.h>
#interface BNRItemStore : NSObject
+(BNRItemStore *)sharedStore;
+(id)retrieveObject;
#end
#implementation BNRItemStore
+(BNRItemStore *)sharedStore{
static BNRItemStore *sharedStore=nil;
if (!sharedStore){
NSLog(#"Test2");
sharedStore= [[super allocWithZone:nil] init];
}
NSLog(#"sharedStore-> %#",sharedStore);
return sharedStore;
}
+(id)allocWithZone:(NSZone *)zone{
NSLog(#"Test1");
return [self sharedStore];
}
+(id)alloc{
NSLog(#"Retrieving super object");
NSLog(#"%#", [super allocWithZone:nil]);//Bypassing the subclass version of allocWithZone.
return [super allocWithZone:nil];
}
#end
int main(){
[[BNRItemStore alloc] init]; //the alloc message triggers a call to the subclass (overriding) version of +(id)alloc method
}
The output is:
2013-10-18 18:24:40.132 BNRItemStore[381:707] Retrieving super object
2013-10-18 18:24:40.134 BNRItemStore[381:707] BNRItemStore:0x7f8c72c091e0
If the call [super allocWithZone:nil] inside of subclass 'alloc' method would have triggered a call to subclass allocWithZone,the console would be logging "Test1" and "Test2" and finally would lead to static pointer getting allocated. But this did not happen.
This means that if we directly call [NSObject allocWithZone:nil] or [super allocWithZone:nil], the message would not redirect to the overriding version (subclass version) of allocWithZone but will give direct access to NSAllocateObject() function which does the actual allocation.
The code of +(id)allocWithZone in NSObject must look somewhat like this-
+(id)allocWithZone:(NSZone *)zone{
return NSAllocateObject();
}
Had this implementation(NSObject's allocWithZone:) included something like [self allocWithZone], the message dispatch mechanism would have included the subclass version of allocWithZone which would then make us go through the "sneaky" trap involving a call to sharedStore method.Following is the case that I'm talking about. Now if this were the case the code would definitely have infinite-looped.Clearly this isn't the case.
+(id)allocWithZone:(NSZone *)zone{
if([self allocWithZone:zone]) //this would trigger a call to subclass ver. which would call sharedStore method which would then have [super allocWithZone:nil].Infinite Loop
return NSAllocateObject();
}
So can someone clear up this query about this so called "sneaky" trap. Was the trap meant for blocking anyone from instantiating separately .i.e not being able to use NSObject's allocWithZone except when inside of sharedStore method ? Pls clarify..

The first, most important lesson here is that you should not override +allocWithZone:. I know the BNR book describes it (and the BNR book is generally very good). You shouldn't do it. I know that Apple includes some example code that does it. You shouldn't do it. (And Apple notes in the explanation that it is rare to need this.) Singletons should be created with the dispatch_once pattern.
You don't give the initial code, but I suspect that their example code overrides alloc, but not allocWithZone:. They're simply saying that if the caller uses allocWithZone:, it won't go through alloc, so they've also overridden alloc to catch that. (Of course the right answer would be just to override allocWithZone: and not alloc. But you shouldn't be overriding these methods in any case.)
EDIT:
I believe you are misunderstanding what "our sneaky alloc trap" means here. The author is assuming the following code at this point in the text:
#interface BNRItemStore : NSObject
+(BNRItemStore *)sharedStore;
#end
#implementation BNRItemStore
+(BNRItemStore *)sharedStore{
static BNRItemStore *sharedStore=nil;
if (!sharedStore){
sharedStore = [[super allocWithZone:nil] init];
}
return sharedStore;
}
#end
That's it; no +alloc overrides at all. It then points out "to enforce the singleton status…you must ensure that another instance of BNRItemStore cannot be allocated." (*)
The author goes on to suggest that we might enforce the singleton status by overriding +alloc, but immediately notes that this is insufficient, since the caller can use +allocWithZone: instead. Since it is documented that [NSObject alloc] calls [self allocWithZone:], it is necessary and sufficient to override +allocWithZone: and unnecessary and insufficient to override +alloc.
What you've done in your code is demonstrate that you can modify BNRItemStore to call [super allocWithZone:] in +alloc. That is not the point. If you can modify BNRItemStore, you could also make it a non-singleton. The point is whether an outside caller (main() in your case) can bypass the singleton instantiation, which she cannot. (**)
(*) The point it doesn't make at this point, and probably should, is that it is generally a bad idea to "enforce the singleton status" by quietly returning a singleton when the callers asked you to allocate a new object. If you need to enforce the singleton status, it is better IMO to do so with an assertion in init, since the request for a second allocation represents a programming error. That said, there are times when "transparent" singletons of immutable objects can be useful for performance reasons, such as the special singletons NSNumber provides for certain common integers, and this technique is appropriate in those cases. (By "transparent," I mean that the singleton-ness is an implementation detail that the caller should never worry about. This presumes at a minimum that the object is immutable.)
(**) Actually she can if she is determined to do so. She could always call NSAllocateObject() herself, bypassing +alloc entirely, and then call -init. This would of course be insane, and there is no reason to "protect" her from herself in doing this. It is not the job of an SDK to protect itself from the caller. It is only the job of an SDK to protect a caller from likely mistakes. The caller is never the enemy.

i'm not sure if this quite answers your question or not, but "allocWithZone:" was used back in the day to be able to partition the memory allocated. apple has since moved away from this concept and expects everything to be allocated in the same heap space. "allocWithZone:" does not even function the way it used to, and apple specifically says not to use it.

Related

Using a Singleton as property of another class vs calling it in every method

I'm asking this for Objective-C because I use it there, but it might apply for all other languages:
-is it a bad thing to have a reference of a single to a Obj-C property?
-Would it be better to call the shared instance in every method?
More precise: I have a singleton class that I can call by using [MySingleton sharedInstance];
I need values of that singleton like 50 times in another class MySecondClass So I created a Obj-C property
#property (nonatomic, strong) MySingleton *mySingletonProperty;
and lazily initialize that property once in MySecondClass by calling
if(!self.mySingletonProperty)
{
self.mySingletonProperty = [MySingleton sharedInstance];
}
A friend of mine told me this would be a bad idea, and it would be better not to use a singleton to instanciate a property. The right way would be to call [MySingleton sharedInstance]; in every method of MySecondClass and assign it to a local variable.
Is that correct? And why? Thread safety is not an issue.
(Please don't discuss if it's a bad idea using a singleton in general here - thanks:-)
The argument I usually see against repeatedly calling [SingletonClass sharedSingleton] is message-passing (function call) overhead. In that case, stashing a reference to your singleton in a property has the same problem -- calling self.singleton all the time is the same number of function calls as calling [SingletonClass sharedSingleton].
That's not a great argument, though, because such overhead has negligible performance impact.
Instead, I'd be concerned about the semantic implications of using a property. While it's generally an assumption of the singleton pattern that there is only one instance of the singleton class over the lifetime of your app, nothing about the "standard" singleton interface guarantees that. If you don't own the singleton class, you may violate its design assumptions by retaining it over the lifetime of some other object with a strong property. If you do own that class, keeping a strong reference to it adds extra design constraints that may (however unlikely) cause problems for you later on.
In summary, I'd give the following advice. If you have code that looks like this:
- someMethod {
[[SingletonClass sharedSingleton] doSomething];
}
- someOtherMethod {
[[SingletonClass sharedSingleton] doSomethingElse];
}
There's nothing wrong with it. (If you really want to save yourself some typing, maybe a local preprocessor macro for [SingletonClass sharedSingleton] is in order.)
If you have code like this:
- someMethod {
[[SingletonClass sharedSingleton] doSomething];
[[SingletonClass sharedSingleton] doSomethingElse];
[[SingletonClass sharedSingleton] doSomeOtherThing];
[[SingletonClass sharedSingleton] doYetAnotherThing];
}
Then you can save yourself a bit of typing (and trivial performance cost) without semantic changes by stashing it in a local variable:
- someMethod {
SingletonClass *singleton = [SingletonClass sharedSingleton];
[singleton doSomething];
[singleton doSomethingElse];
[singleton doSomeOtherThing];
[singleton doYetAnotherThing];
}
If you still need a singleton there is nothing wrong with keeping a reference to it. But why do you keep the reference as a property? My advice is to create an internal variable:
#interface MySecondClass : NSObject {
// ...
MySingleton *mySingletonInstanse;
}
// ...
#end

Objective C - is init a bad place to implement a factory?

I implemented the old init-as-a-factory pattern, but in one particular case (but not others!) I get a warning from the analyser regarding memory leaks. And indeed, looking at the Cocoa Memory Management Policy rules, it is alloc, not init, which can return +1-retain-count objects.
So it appears that:
Releasing self and returning a new object from init is, strictly speaking, against the rules.
Many places on the internet promote this technique, and because of the tandem nature of alloc/init this does work.
The analyser sometimes complains about this, and sometimes doesn't.
So... have we been doing this wrong all along?
you can implemented init like this, which should release self to balance the retain count from alloc call.
- (id)initWithSomething:(id)something
{
[self release]; // don't need this line for ARC
self = nil;
return [[PrivateSubClass alloc] initWithSomething:something];
}
and it if very often to implement init as a factory method. e.g. NSArray, NSDictionary, NSString
As gaige said, it will be much more clearer if you post a piece of code rather than explanations.
Anyway, you can move your factory to the class method, so you will have no such problem at all. I mean something like this:
MyClass* instance = [MyClass instanceWithParameters:params];
#interface MyClass
+ (MyClass*) instanceWithParameters:(ParamType)params;
#end
Without knowing what is the code that is causing the analyzer's behavior it's hard to tell, but as a general rule, here's a couple of compiler-friendly ways to define init/factory methods.
Classic alloc/init
- (instancetype)initWithParameter:(id)parameter {
if(self = [super init]) {
_parameter = parameter;
}
return self;
}
Usage
MyCustomClass * myInstance = [[MyCustomClass alloc] initWithParameter:foo];
This will produce an instance with a +1 retain count. Under ARC this will be automatically managed properly since it follows the NARC rule (New, Alloc, Retain, Copy).
For the same reason, in pre-ARC environments it has to be explicitly released by the client.
Custom factory method
ARC
+ (instancetype)canIHazInstanceWithParameter:(id)parameter {
return [[self alloc] initWithParameter:parameter]; // assuming -initWithParameter: defined
}
Pre-ARC
+ (instancetype)canIHazInstanceWithParameter:(id)parameter {
return [[[self alloc] initWithParameter:parameter] autorelease]; // assuming -initWithParameter: defined
}
Usage
MyCustomClass * myInstance = [MyCustomClass canIHazInstanceWithParameter:foo];
Both in ARC and pre-ARC the method returns an autoreleased instance (this is clearly more explicit in the pre-ARC implementation), which doesn't have to be managed by the client.
Remarks
You may have noticed the instancetype keyword. That's a handy language extension introduced by Clang, that turns the compiler into a dear friend when implementing your own constructors/factory methods. I wrote an article on the subject, which may be relevant to you.
Whether factory methods are preferable to init methods is debatable. From a client perspective it does not make much difference under ARC, provided that you carefully follow the naming conventions, even though I personally tend to expose factory methods in the interface, while implementing custom init methods only internally (as I did in the examples above). It's more a matter of style than an actual practical concern.

Detected autorelease objects

I using Test Driven Development in Objective-C for iOS and Mac OS X development, and I want to be able to write tests that can verify that objects I create with class factory methods return autorelease objects.
How can someone write a test that verifies a provided object is autorelease?
In short, you can't. There is no way to know the autorelease state of an object.
In some cases, you can infer whether an object was placed in an autorelease pool. The idea is declaring a pointer to an object, instantiating it within an #autoreleasepool block, and then verifying that it had dealloc called after the end of the block.
Through whatever combination of swizzling or overriding dealloc you choose, you must first provide a way to verify that dealloc has been called. I wrote an NSObject category with the following interface and implementation, that provides a deallocationDelegate property that will receive a message of handleDeallocation: when the object is deallocated.
#interface NSObject (FunTimes)
#property (nonatomic, assign) id deallocationDelegate;
#end
#implementation NSObject (FunTimes)
+ (void)load
{
Class klass = [NSObject class];
SEL originalSelector = #selector(dealloc);
Method originalMethod = class_getInstanceMethod(klass, originalSelector);
SEL replacementSelector = #selector(funDealloc);
Method replacementMethod = class_getInstanceMethod(klass, replacementSelector);
if(class_addMethod(klass, originalSelector, method_getImplementation(replacementMethod), method_getTypeEncoding(replacementMethod)))
{
class_replaceMethod(klass, replacementSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}
else
{
method_exchangeImplementations(originalMethod, replacementMethod);
}
}
- (void)funDealloc
{
if (self.deallocationDelegate)
[self.deallocationDelegate performSelector:#selector(handleDeallocation:) withObject:self];
[self funDealloc];
}
static char myKey;
- (void)setDeallocationDelegate:(id)deallocationDelegate
{
objc_setAssociatedObject(self, &myKey, deallocationDelegate, OBJC_ASSOCIATION_ASSIGN);
}
- (id)deallocationDelegate
{
return objc_getAssociatedObject(self, &myKey);
}
#end
I ran some test code in my application delegate just to see if it works. I declared an NSMutableArray instance designed to hold NSValue instances derived from the pointers of objects calling -handleDeallocation, which I implement as shown:
- (void)handleDeallocation:(id)toDie
{
NSValue *pointerValue = [NSValue valueWithPointer:toDie];
[self.deallocatedPointerValues addObject:pointerValue];
}
Now, here's a snippet of what I ran. SomeClass is an NSObject subclass with no additional properties or methods.
self.deallocatedPointerValues = [NSMutableArray array];
SomeClass *arsc = nil;
#autoreleasepool {
arsc = [[[SomeClass alloc] init] autorelease];
arsc.deallocationDelegate = self;
NSValue *prePointerValue = [NSValue valueWithPointer:arsc];
BOOL preDeallocated = [self.deallocatedPointerValues containsObject:prePointerValue];
NSLog(#"PreDeallocated should be no is %d",preDeallocated);
}
NSValue *postPointerValue = [NSValue valueWithPointer:arsc];
BOOL postDeallocated = [self.deallocatedPointerValues containsObject:postPointerValue];
NSLog(#"Post deallocated should be yes is %d",postDeallocated);
In this case, it can be verified that the object pointed to by arsc (which stands for auto released SomeClass) has been deallocated due to ending the #autoreleasepool block.
There are several significant limitations to the this approach. One, this cannot work when other messages of retain may be sent to your object that is returned from your factory method. Also, and this should go without saying, swizzling dealloc should only be done in experimental settings, and I think some would argue that it shouldn't be swizzled in testing (obviously it shouldn't be swizzled in production!). Finally, and more significantly, this doesn't work well with Foundation objects such as NSString that have been optimized in ways that it's not always clear whether you are creating a new instance or not. So this is most appropriate, if at all, for your own custom objects.
As a final word, I don't think it's practical to do this really. I felt it was more work than it was worth and is so narrowly applicable as the make spending time learning instruments better to be a far better investment when it comes to memory management. And, of course, with ARC's ascendency, this approach is archaic from the start. Regardless, if you do have need to write such tests, and can work around the limitations here, feel free to adapt this code. I'd be curious to see how it pans out in an actual testing environment.
I commend your dedication to TDD. But memory management is an area where you simply have to follow well-established conventions: "When returning an object, it needs to take care of its own lifetime." My unit tests catch me when I accidentally over-release something, but they won't catch a leak. For that, I rely first on Analyze, then on running the Leaks instrument.

Creating a class with no init method (Objective-c)

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?
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.
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.
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.
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.
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.

Is it possible to make the -init method private in Objective-C?

I need to hide (make private) the -init method of my class in Objective-C.
How can I do that?
NS_UNAVAILABLE
- (instancetype)init NS_UNAVAILABLE;
This is a the short version of the unavailable attribute. It first appeared in macOS 10.7 and iOS 5. It is defined in NSObjCRuntime.h as #define NS_UNAVAILABLE UNAVAILABLE_ATTRIBUTE.
There is a version that disables the method only for Swift clients, not for ObjC code:
- (instancetype)init NS_SWIFT_UNAVAILABLE;
unavailable
Add the unavailable attribute to the header to generate a compiler error on any call to init.
-(instancetype) init __attribute__((unavailable("init not available")));
If you don't have a reason, just type __attribute__((unavailable)), or even __unavailable:
-(instancetype) __unavailable init;
doesNotRecognizeSelector:
Use doesNotRecognizeSelector: to raise a NSInvalidArgumentException. “The runtime system invokes this method whenever an object receives an aSelector message it can’t respond to or forward.”
- (instancetype) init {
[self release];
[super doesNotRecognizeSelector:_cmd];
return nil;
}
NSAssert
Use NSAssert to throw NSInternalInconsistencyException and show a message:
- (instancetype) init {
[self release];
NSAssert(false,#"unavailable, use initWithBlah: instead");
return nil;
}
raise:format:
Use raise:format: to throw your own exception:
- (instancetype) init {
[self release];
[NSException raise:NSGenericException
format:#"Disabled. Use +[[%# alloc] %#] instead",
NSStringFromClass([self class]),
NSStringFromSelector(#selector(initWithStateDictionary:))];
return nil;
}
[self release] is needed because the object was already allocated. When using ARC the compiler will call it for you. In any case, not something to worry when you are about to intentionally stop execution.
objc_designated_initializer
In case you intend to disable init to force the use of a designated initializer, there is an attribute for that:
-(instancetype)myOwnInit NS_DESIGNATED_INITIALIZER;
This generates a warning unless any other initializer method calls myOwnInit internally. Details will be published in Adopting Modern Objective-C after next Xcode release (I guess).
Apple has started using the following in their header files to disable the init constructor:
- (instancetype)init NS_UNAVAILABLE;
This correctly displays as a compiler error in Xcode. Specifically, this is set in several of their HealthKit header files (HKUnit is one of them).
Objective-C, like Smalltalk, has no concept of "private" versus "public" methods. Any message can be sent to any object at any time.
What you can do is throw an NSInternalInconsistencyException if your -init method is invoked:
- (id)init {
[self release];
#throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:#"-init is not a valid initializer for the class Foo"
userInfo:nil];
return nil;
}
The other alternative — which is probably far better in practice — is to make -init do something sensible for your class if at all possible.
If you're trying to do this because you're trying to "ensure" a singleton object is used, don't bother. Specifically, don't bother with the "override +allocWithZone:, -init, -retain, -release" method of creating singletons. It's virtually always unnecessary and is just adding complication for no real significant advantage.
Instead, just write your code such that your +sharedWhatever method is how you access a singleton, and document that as the way to get the singleton instance in your header. That should be all you need in the vast majority of cases.
You can declare any method to be not available using NS_UNAVAILABLE.
So you can put these lines below your #interface
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
Even better define a macro in your prefix header
#define NO_INIT \
- (instancetype)init NS_UNAVAILABLE; \
+ (instancetype)new NS_UNAVAILABLE;
and
#interface YourClass : NSObject
NO_INIT
// Your properties and messages
#end
That depends on what you mean by "make private". In Objective-C, calling a method on an object might better be described as sending a message to that object. There's nothing in the language that prohibits a client from calling any given method on an object; the best you can do is not declare the method in the header file. If a client nevertheless calls the "private" method with the right signature, it will still execute at runtime.
That said, the most common way to create a private method in Objective-C is to create a Category in the implementation file, and declare all of the "hidden" methods in there. Remember that this won't truly prevent calls to init from running, but the compiler will spit out warnings if anyone tries to do this.
MyClass.m
#interface MyClass (PrivateMethods)
- (NSString*) init;
#end
#implementation MyClass
- (NSString*) init
{
// code...
}
#end
There's a decent thread on MacRumors.com about this topic.
If you are talking about the default -init method then you can't. It's inherited from NSObject and every class will respond to it with no warnings.
You could create a new method, say -initMyClass, and put it in a private category like Matt suggests. Then define the default -init method to either raise an exception if it's called or (better) call your private -initMyClass with some default values.
One of the main reasons people seem to want to hide init is for singleton objects. If that's the case then you don't need to hide -init, just return the singleton object instead (or create it if it doesn't exist yet).
Put this in header file
- (id)init UNAVAILABLE_ATTRIBUTE;
well the problem why you can't make it "private/invisible" is cause the init method gets send to id (as alloc returns an id) not to YourClass
Note that from the point of the compiler (checker) an id could potencialy respond to anything ever typed (it can't check what really goes into the id at runtime), so you could hide init only when nothing nowhere would (publicly = in header) use a method init, than the compile would know, that there is no way for id to respond to init, since there is no init anywhere (in your source, all libs etc...)
so you cannot forbid the user to pass init and get smashed by the compiler... but what you can do, is to prevent the user from getting a real instance by calling a init
simply by implementing init, which returns nil and have an (private / invisible) initializer which name somebody else won't get (like initOnce, initWithSpecial ...)
static SomeClass * SInstance = nil;
- (id)init
{
// possibly throw smth. here
return nil;
}
- (id)initOnce
{
self = [super init];
if (self) {
return self;
}
return nil;
}
+ (SomeClass *) shared
{
if (nil == SInstance) {
SInstance = [[SomeClass alloc] initOnce];
}
return SInstance;
}
Note : that somebody could do this
SomeClass * c = [[SomeClass alloc] initOnce];
and it would in fact return a new instance, but if the initOnce would nowhere in our project be publicly (in header) declared, it would generate a warning (id might not respond ...) and anyway the person using this, would need to know exactly that the real initializer is the initOnce
we could prevent this even further, but there is no need
I have to mention that placing assertions and raising exceptions to hide methods in the subclass has a nasty trap for the well-intended.
I would recommend using __unavailable as Jano explained for his first example.
Methods can be overridden in subclasses. This means that if a method in the superclass uses a method that just raises an exception in the subclass, it probably won't work as intended. In other words, you've just broken what used to work. This is true with initialization methods as well. Here is an example of such rather common implementation:
- (SuperClass *)initWithParameters:(Type1 *)arg1 optional:(Type2 *)arg2
{
...bla bla...
return self;
}
- (SuperClass *)initWithLessParameters:(Type1 *)arg1
{
self = [self initWithParameters:arg1 optional:DEFAULT_ARG2];
return self;
}
Imagine what happens to -initWithLessParameters, if I do this in the subclass:
- (SubClass *)initWithParameters:(Type1 *)arg1 optional:(Type2 *)arg2
{
[self release];
[super doesNotRecognizeSelector:_cmd];
return nil;
}
This implies that you should tend to use private (hidden) methods, especially in initialization methods, unless you plan to have the methods overridden. But, this is another topic, since you don't always have full control in the implementation of the superclass. (This makes me question the use of __attribute((objc_designated_initializer)) as bad practice, although I haven't used it in depth.)
It also implies that you can use assertions and exceptions in methods that must be overridden in subclasses. (The "abstract" methods as in Creating an abstract class in Objective-C )
And, don't forget about the +new class method.