Weird memory issues, with ARC enabled - objective-c

I am having a very, very strange error, probably related to memory management (even though I'm using ARC).
I have a my AppDelegate, Foo, and SubFoo (which is a subclass of Foo).
Foo.h
#protocol FooDelegate <NSObject>
- (void)didReceiveDownloadRequest:(NSURLRequest *)downloadRequest;
#end
#interface Foo : NSObject {
__weak id <FooDelegate> delegate;
}
- (void)performRequest;
#property (nonatomic, weak) id <FooDelegate> delegate;
#property (nonatomic, retain) NSString *fileIdentifier;
Foo.m
#implementation Foo
#synthesize delegate, fileIdentifier;
- (id)init {
if ((self = [super init])) {
self.delegate = nil; // I tried leaving this line out, same result.
NSLog(#"I am %p.", self);
}
return self;
}
- (void)performRequest {
// Bah.
}
#end
SubFoo.h
#interface SubFoo : Foo {
WebView *aWebView;
}
SubFoo.m
- (void)performRequest {
if (self.fileIdentifier) {
aWebView = [[WebView alloc] init];
[aWebView setFrameLoadDelegate:self];
[[aWebView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"theURL"]];
}
}
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
NSLog(#"Finished loading.");
// ...
NSLog(#"Class Name: %#", NSStringFromClass([self class]));
NSLog(#"Memory Location of delegate: %p", self.delegate);
// ...
}
Sometimes, the class name on webView:didFinishLoadForFrame: returns a completely different class (instead of SubFoo, it returns random classes, like NSSet, NSArray, it even sometimes returns CFXPreferencesSearchListSource), other times it just crashes there with an EXC_BAD_ACCESS, and when it returns a random class on Class Name: it returns that [randomClassName delegate] is an unrecognized selector.
EDIT: When self gets set to another thing, it gets set RIGHT on webView:didFinishLoadForFrame:, and on performRequest it is ALWAYS SubFoo.
Any help here would be appreciated.

First, even though you are using ARC zeroing weak references in your project (#property (weak)), other projects and frameworks may not be (and are probably not) using zeroing weak references.
In other words, assume that all delegates in frameworks are __unsafe_unretained unless:
The delegate property is declared weak in a header
The documentation/header explicitly states otherwise
That said, let's talk about your example. Your object ownership chart looks something like this:
(Note: I'm not entirely sure which class in your project uses SubFoo. Based on common practice, I'm assuming that you have a class with a strong reference to SubFoo, and that class is also set up to be a SubFooDelegate)
Ultimately, your instance of SubFoo is losing its last strong reference and is deallocating. In a perfect ARC-enabled world, the WebView's pointer to SubFoo would nil out at this time. However, it's not a perfect world yet, and WebView's frameLoadDelegate is __unsafe_unretained. Due to run loop interaction, the WebView is outliving SubFoo. The web request completes, and a dead pointer is dereferenced.
To fix this, you need to call [aWebView setFrameLoadDelegate:nil]; in SubFoo's dealloc method. You also need to call it when you reassign aWebView, as you are losing track of the old aWebView:
SubFoo.m
#implementation SubFoo
- (void)dealloc {
[aWebView setFrameLoadDelegate:nil];
// Also nil out any other unsafe-unretained references
}
- (void)performRequest {
if (self.fileIdentifier) {
[aWebView setFrameLoadDelegate:nil]; // Protects us if performRequest is called twice. Is a no-op if aWebView is nil
aWebView = [[WebView alloc] init];
[aWebView setFrameLoadDelegate:self];
[[aWebView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"theURL"]];
}
}
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
// ...
}

Forget the self.delegate error for now, it is a red herring if [self class] is producing the wrong result! Your results suggest you are somehow clobbering self.
Breakpoint on webView:didFinishLoadForFrame: check the self value and step through.
Comment Followup
For self to be wrong on the first statement of an instance method is, let's say, unusual (but not impossible).
It is important when an object is set as another's delegate that you make sure the delegate object's lifetime is at least as long as the one it is acting as a delegate to. Introducing ARC can make previously working code fail as it may release the delegate earlier than the code did under MRC. When this happens the call to the delegate usually fails.
However your error does not fail on the call to the delegate; the call starts - you end up in webView:didFinishLoadForFrame: - and then you find self is invalid. To actually invoke an instance method usually requires a valid value for self as it is used to determine the method implementation to call. Hence it is usual for self to be valid at the start of a method!
But note the "usually"...
So despite you having successfully reach your method, your error might be down to not having a strong reference to your SubFoo instance, you pass it as a delegate to aWebView, and by the time webView:didFinishLoadForFrame: is called your SubFoo has gone.
Make sure you're keeping a strong ref to your SubFoo instance. If you just want to test (this is not a recommended general solution!) if this is your problem you can just assign it to a local static (static SubFoo *holdMe say declared inside performRequest) in performRequest, which will keep a strong reference around at least until the next call to performRequest. If this does prove to be the problem you then need to come up with a good way to maintain the reference that fits your design.

Here's the real problem: You're creating a SubFoo object within the context of a method. So after the method completes, SubFoo is being released (before its WebView has time to load).
To fix this, you'll need to assign the SubFoo object you're creating to something persistent, like a instance variable of the class you're creating it from. That way the object will persist beyond the scope of the method it was created in and all will work as expected.

As CRD mentioned, I would say an incorrect object/bad access returned is a sign of an object being released. Sometimes it's replaced by another object, sometimes it's not so you get the bad access exception. Regarding how this could happen to self, I would imagine that this is a concurrency weird case (object is being freed on another thread).
The best way to confirm this is to run your code in Instrument's NSZombie template, it'll show you as soon as you access a freed object. It also shows when it's been retained/released so you don't have to guess.

Regarding your above comment.
SubFoo *theClass = [[SubFoo alloc] init];
You must store theClass in a
#property (strong) SubFoo *mySubFoo;
If you declare it as such:
{
SubFoo *theClass = [[SubFoo alloc] init];
}
It gets released at the closing bracket. This part of the point of ARC when that variable moves out of scope, it gets released. If you want to let it float in the ether you could use
{
__weak SubFoo *theClass = [[SubFoo alloc] init];
}
and it won't get released, but this will lead to a memory leak unless you carefully manage all the weak references. In the case of it not being released at -performRequest I'm assuming the request looks like this:
{
SubFoo *theClass = [[SubFoo alloc] init];
[theClass performRequest];
}
wheras -webView:didFinishLoadForFrame: is called at some indiscriminate time in the future.

Related

Message sent to deallocated instance using ARC

I wouldn't normally ask questions like this, but I really cant get my head around it. I have a class 'GetTableInfoFromDatabase', which connects to my database and downloads some JSON. This works great from the first screen of my tab-bar application. I can call the getNewData method as much as I want to effectively refresh the data.
My problem arises when I try and create an instance of the 'GetTableInfoFromDatabase' class and call the very same method from another tab. I get the following error:
*** -[GetTableInfoFromDatabase respondsToSelector:]: message sent to deallocated instance 0x1d89e830
The funny thing is, i'm using ARC. The culprit (in my opinion) is ASIHTTPRequest. I have had to enable -fno-objc-arc to get the project to compile. This library is used in the GetTableInfoFromDatabase class.
Here is the class:
- (void) getEventDataWithSender:(id)sender{
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:#"-------.com/getdata.php"]];
[request setDelegate:self];
NSLog(#"Running!");
[request startAsynchronous];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.managedObjectContext = appDelegate.managedObjectContext;
}
And this is how i'm calling it:
GetTableInfoFromDatabase *getInfo = [[GetTableInfoFromDatabase alloc]init];
[getInfo getEventDataWithSender:self];
I've even changed the order of the tabs around, so the first tab to be displayed purely just calls this method, nothing else. Not even before the 'GetTableInfoFromDatabase' has been previously initialised by the class that initialised it first last time. Still crashes.
Has anyone got any ideas? This is so frustrating!
You need to assign that variable to a property if you plan on exposing it to other view controllers. ARC will, and should, immediately deallocate getInfo after this code executes:
GetTableInfoFromDatabase *getInfo = [[GetTableInfoFromDatabase alloc]init];
[getInfo getEventDataWithSender:self];
So if this line is included in say viewDidLoad: and nothing else refers to getInfo in that method, it will be immediately released. Why, because you haven't told the compiler that it should retain it.
So in the view controller that's exposing this class, on whatever tab it might be a child of... you would do something like this:
ViewController.h
#class GetTableInfoFromDatabase; // forward declaration
#interface ViewController : UIViewController
#property (strong, nonatomic) GetTableInfoFromDatabase *getInfo;
ViewController.m
#implementation ViewController
#synthesize getInfo = _getInfo;
- (void) viewDidLoad {
[super viewDidLoad];
self.getInfo = [[GetTableInfoFromDatabase alloc]init]; // assign your value to a property
[self.getInfo getEventDataWithSender:self];
}
So when you declare your property as Strong in your header, it will maintain a strong reference to it. #Synthesize getInfo = _getInfo means that it will create a getter and setter for self.getInfo around an instance variable named _getInfo. If you didn't want to expose it as a property, just an instance variable... you could do this:
ViewController.h
#class GetTableInfoFromDatabase; // forward declaration
#interface ViewController : UIViewController {
GetTableInfoFromDatabase _getInfo;
}
ViewController.m
#implementation ViewController
- (void) viewDidLoad {
[super viewDidLoad];
_getInfo = [[GetTableInfoFromDatabase alloc]init]; // assign your value to a property
[_getInfo getEventDataWithSender:self];
}
By default, the compiler will maintain a strong reference to that instance variable unless otherwise specified. You can have weak references as well, and all of those options are pretty well documented. So with ARC, or plain old memory management in general, you need to make an instance variable or property if you want it to hang around for a while.
Honestly... all ARC is doing for you is keeping you from having to call retain and release. Before ARC, setting that property would look like this:
GetTableInfoFromDatabase getInfo = [[GetTableInfoFromDatabase alloc]init];
self.getInfo = getInfo;
[getInfo release];
Now with ARC, the compiler just writes that code for you ;) Hope this helps!
[self.getInfo getEventDataWithSender:self];
Your GetTableInfoFromDatabase object is being deallocated, almost certainly because nothing is holding a strong reference to it. In your code above, getInfo is a local variable, so I would expect it to be released very shortly after this code, unless you are storing it somewhere.
Almost certainly, your dealloc in GetTableInfoFromDatabase does not clear the request's delegate. You should be holding the request in an ivar of GetTableInfoFromDatabase so that it can remove itself as delegate when it is deallocated.
As a side note, avoid prefacing ObjC methods with get. That has a special meaning in KVC (it means that the first parameter is supposed to be updated by reference). Typically the kind of method you have here would be prefaced with "fetch."

Objective-C: releasing the object from itself

I've stumbled upon an interesting situation when object could release itself and was wondering what is considered safe and right in this situation.
Imagine we have a class Foo:
#implementation Foo
+ (Foo *) foo {
return [[[Foo alloc] init] autorelease];
}
- (void)resign {
[FooHolder holder].foo = nil;
// here's where the things happen
}
#end
Another class is FooHolder (singleton with one property):
#interface FooHolder : NSObject {
Foo *foo;
}
#property (retain) Foo *foo;
+ (FooHolder *)holder;
#end
And somewhere in the code we do this (calling first stepOne and then stepTwo; autorelease pools are drained after stepOne finishes):
- (void)stepOne {
Foo *foo = [Foo foo];
[FooHolder holder].foo = foo;
}
- (void)stepTwo {
[[FooHolder holder].foo resign]
}
If I'm trying to access self in resign method, after the assignment, with NSZombieEnabled, I'm getting a warning that self is already deallocated. This gives me short WTF moment, but alright, I can live without accessing self at this part. What bothers me more, if object is already deallocated, who can guarantee that stack is not damaged, and we are proceeding normally with our local and instance variables? In general, is it a bad practice to allow self to be deallocated while in the method?
In general, is it a bad practice to allow self to be deallocated while in the method?
Yes because from the point that self is deallocated all of your ivars could also be deallocated.
I won't pretend to understand your design or your reasons for doing it but why do you not rearrange your resign method:
- (void)resign {
// here's where the things should happen
[FooHolder holder].foo = nil;
}
You should always release owned objects after there is any chance you will use them in the same way that you call [super dealloc]; at the end of -(void)dealloc
I would argue that you have a faulty design. In the instance method -resign you are effectively releasing a particular instance of foo held by the singleton. Why would any arbitrary instance of foo do that? Referencing what is effectively a global variable in the instance method makes the coupling too tight.
Whatever invokes -resign should be the thing that tells [FooHolder holder] that it has resigned the foo or will resign the foo. Alternatively, have a weak reference to a FooHolder in the foo and have the foo send it a message like -willResign:(Foo*) This effectively makes it a delegate of the foo. In -willResign: the FooHolder can check if it is the right foo and then retain and autorelease it before setting it to nil.

Assign the return object of the superclass to self

I have read many posts about this now but I do not still understand it. I would appriciate an answer rather than a link because I probably already have read it.
if (self = [super init]) {
}
return self;
When I am calling the [super init] I know I am calling the method on "self"(the objects address) but I am starting the "method-search" in the superclass. When this returns I assign the object type id to self...This is where I am getting lost.
Am I assigning "self" as an initialized object up to the point of the superclass to self..?
I understand that I am doing this check to stop the initializing if the superclass implementation of the initializer returns nil however I dont understand what I am assinging to self....I thought self was an address to the current object in memory.
Thanks in advance
The assignment has always seemed a bit hacky to me. Its main point is that the superclass might want to return some other instance than the one that was initially allocated:
id foo = [[Foo alloc] init];
#interface Foo : SuperFoo {…}
#implementation Foo
- (id) init
{
self = [super init];
if (!self)
…;
return self;
}
#interface SuperFoo : NSObject {…}
#implementation SuperFoo
- (id) init
{
[self release];
return [OtherClass alloc];
}
This is crazy indeed, but the fact is that [super init] might return an object different from the previous self. See Mike Ash’s blog post, that should make things super clear.
There are two reasons, why that assignment is important:
The designated initializer (di) of the superclass may return nil if initialization fails.
In this case, without the assignment of its return value to self, you would end up in a state that is completely unsafe — most likely, your superclass's di will have released the object pointed at by self in order to not leak memory.
If you went on using that instance and you're lucky you should see a crash in the not so distant future. If you're not that lucky, you're going to mess with some other object's internal state and lose or corrupt user-data before your program crashes.
There are quite a few classes in Cocoa(Touch) — the class-clusters like NSString and NSArray probably being the most prominent examples — that may return a different instance from their di.
The pointer you will receive from [NSString alloc] for example will almost definitely not be the same you'll obtain from a subsequent call to initWithFormat:#"Hello %#!", #"foo".
lets break this into smaller chunks:
1- when your calling [super init] your making your super class run its init function first so it can initialize your object that your inheriting, normally that would be NSObject or any superclass that you decided to extend.
the super init functions will return self at the end of that process, just like your doing in your init function
2- when you do the assignment: self = [super init] your actually assigning that return value from your super into your own.
3- the if around that assignments actually evaluates the success/failure of the super init call, cause if it failed you would have got a nil back and the assignments would have been nil to self. so evaluating nil will return false and you wont run your init code.
4- eventually you also return self (nil if failed / actuall object if it succeeded)
hope that clears it.

Should you set the delegate to nil in the class using the delegate or in the class itself

If class A is using class B and class A is class B's delegate, is it ok if the delegate is set to nil in class B's dealloc? I have seen code usually resetting the delegate to nil inside class A's dealloc but wasn't sure the real difference doing it one way or the other.
e.g. This is the usual way:
// somewhere in class A
- (void) someFunc {
self.b = [[B alloc] init];
self.b.delegate = self;
}
- (void) dealloc {
self.b.delegate = nil;
[self.b release];
}
Yes, you should set the classB's delegate property to nil in classA's dealloc.
It's not a memory management issue, because delegate properties should be marked assign, not retain, to avoid retain cycles (otherwise the dealloc will never be called). The issue is that otherwise classB might message classA after it has been released.
For example, if classB has a delagate call to say "being hidden", and classB is released just after classA, it would message the already dealloc'ed classA causing a crash.
And remember, you can't always guarentee the dealloc order, especial if they are autoreleased.
So yes, nil out the delegate property in classA's dealloc.
As far as I know, its best practice to (assign) a delegate, such that you avoid circular references on retain counts for situations just like this. If you've set up the property properly, ie:
#property (assign) id<BDelegate> delegate;
You shouldn't have to perform any memory management in the dealloc, as the retain count is not bumped when you call self.b.delegate = self; -- unlike using (retain) or (copy)
Make sense? It would be fine to set the delegate to nil, but whats the point?
First, a few observations...
You've forgotten to call [super dealloc] at the end of your own dealloc method.
Since 'a' created 'b', and if no other objects have retained 'b', there no point in nilling the delegate in the -dealloc, since 'b' is about to be destroyed anyhow. If it's possible that other objects have a reference to 'b' (meaning it might outlive 'a') then set the delegate to nil.
Object 'b' should be the one to take care of its delegate in its own -dealloc if necessary. (Generally, the delegator does not retain the delegate.)
Avoid using properties in -init... and -dealloc methods — Apple discourages this, and for good reason. (Not only could it have unexpected side effects, but can also cause nastier, crashier problems.)
Using properties (via the dot syntax) when you don't need to invisibly adds extra work. For instance, self.b.delegate = self is equivalent to [[self getB] setDelegate:self] — it's just syntactic sugar that makes it look like you're accessing the ivar directly, but you're actually not.
Using properties without understanding what they do can lead to trouble. If self.b retains the value (the property is set to "assign"), you have a memory leak on your hands.
Here's how I would probably write it:
- (void) someFunc {
b = [[B alloc] init];
b.delegate = self; // or [b setDelegate:self];
}
- (void) dealloc {
b.delegate = nil;
[b release];
[super dealloc];
}

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.