Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.objective-c > #226

Re: A question on designated initializers

From Don Bruder <dakidd@sonic.net>
Newsgroups comp.lang.objective-c
Subject Re: A question on designated initializers
Date 2015-11-24 07:38 -0800
Organization Chaotic Creations Unlimited
Message-ID <n32058$rkn$2@dont-email.me> (permalink)
References <n2tcmc$t64$1@news.albasani.net> <n2u08d$7vs$1@dont-email.me> <n30iuo$c4b$1@news.albasani.net>

Show all headers | View raw


In article <n30iuo$c4b$1@news.albasani.net>,
 Jon Rossen <jonr17@comcast.net> wrote:

> On 11/22/2015 7:15 PM, Don Bruder wrote:
> > In article <n2tcmc$t64$1@news.albasani.net>,
> >   Jon Rossen <jonr17@comcast.net> wrote:
> 
> >> But how is this helpful?  In my mind it's not helpful for a few
> >> different reasons.  Reason 1: In the override to init you've hardwired
> >> the width and height to be 0.  That's what NSObject's init would do, so
> >> it's not doing anything new or better. Reason 2:  Even if you put
> >> different values in there say, 1 and 2 or whatever values you thought
> >> you might need a newly created Rectangle object to have, they are still
> >> hardwired values, buried inside the newly created init method.  How is
> >> this helpful at all?  You may want to have a bunch of rectangles of all
> >> different dimensions.  At that point you'd have to change their
> >> dimensions with the proper accessor method.  If so, why even both with
> >> this newly created init when you can just use NSObject's init and use
> >> the accessor method to tweak the height and width you want each
> >> Rectangle object to be?
> >>
> >> Am I correct that the trivial nature of this example sort of gets in the
> >> way of truly understanding the benefit or need of all of this?
> >> thanks,
> >> jonR
> >
> > In a nutshell, the "designated initializer" is *THE* initializer for a
> > class that handles *ALL* possibilities for initialization that are
> > available - Everything else is convenience methods.
> >
> > Ferinstance:
> >
> > Assume you've got a class with 5 instance variables, A, B, C, D, and E
> >
> > Your "designated initializer" should then look something like this:
> >
> > -(MyClass *)initWithA:(id)a andB:(id)b andC:(id)c andD:(id)d andE:(id)e
> > {
> >   // I'm ignoring the various checking and calls to super's init for
> >   // brevity, since you seem to understand the chaining mechanism.
> >   // Now stuff the a,b,c,d, and e instance variables with the appropriate
> >   // values that were passed in - either by direct assignment, or via
> >   // accessor methods, as you please - then return self.
> > }
> >
> > Now, assuming there's some reason you only need to init an instance
> > with, ferinstance, a, while all the other instance vars can be left at
> > default values, you could write:
> >
> > -(MyClass *)initWithJustA:(id)a
> > { // (beware line-wrapping for post...)
> >     return [InitWithA:a andB:defaultBValue andC:defaultCValue
> > andD:defaultDValue andE:defaultEValue];
> > }
> >
> > Likewise, if you need to init A and B, but C, D, and E can be left at
> > default, you'd write:
> >
> > -(MyClass *)initWithA:(id)a andB:(id)b
> > { // (beware line-wrapping for post...)
> >     return [initWithA:a andB:b andC:defaultCValue andD:defaultDValue
> > andE:defaultEValue];
> > }
> >
> > and so on for each combination of initializations that make sense for
> > your code.
> >
> > And finally, for an instance of the class that can be left with all of
> > the vars at default values, you could write:
> >
> > -(MyClass *)init
> > {
> >     return [InitWithA:defaultAValue andB:defaultBValue andC:defaultCValue
> > andD:defaultDValue andE:defaultEValue];
> > }
> >
> > Notice how the "plain" init calls the designated initializer with
> > default values for each and every instance variable?
> >
> > Further note that in the "not designated" initializers, you *DON'T* do
> > the [super init] checks and calls - You've written the "designated"
> > initializer so that it handles doing that. So long as you call the
> > designated initializer to do the actual initialization, that stuff gets
> > handled "automagically"
> >
> > The whole point of the "designated initializer" is that an instance of a
> > class - any class - is expected to be "ready to use" immediately after
> > being initialized. Using a designated initializer makes certain that any
> > setup an instance needs done gets done, with nothing being forgotten.
> >
> Don, Thanks so much for your response with all of this info; I really 
> appreciate it.  It is the perfect combination of theory and practical 
> info.  You are right, I sort of understand the chaining mechanism in how 
> things unfold in the class hierarchy.  The construct that you 
> illustrated here with the default values used by the 'convenience' init 
> methods is something I came across earlier today coincidentally, but 
> your explanation was much more specific, to the point and not obfuscated 
> by vague implications.  I have a few more questions:
> 
> 1. Just a workflow question:  Re: the 'convenience' init methods that 
> may be helpful to get objects accompany the designated one:  Is it 
> typical for a developer when building a class to add the 'convenience' 
> init methods later on or sort of on an 'as needed' basis depending?  I'm 
> not asking this as to what's good or bad, but am assuming it just 
> depends on the situation and in your experience how does this usually 
> play out?

I can't speak for anyone but myself, so YMMV...
Personally, I code a "designated" initializer that takes appropriate 
inputs and uses them to handle *EVERYTHING*, to start with, then a 
"naked init" ("-(MyClass *)init") method that passes some reasonable 
defaults into the designated initializer. Often, but nowhere near 
always, that's all that's needed. (Or more accurately, it's *ALWAYS* all 
that's *NEEDED*, but it's only occasionally all that's *WANTED*, if you 
understand the distinction) If, as the project progresses, and I notice 
a need for them, I might add more convenience initializers. The decision 
to add more convenience initializers or not is totally dependent on the 
needs of the specific project - In one project, I might code the 
designated initializer, the cover for "init", and several variations, as 
needed. In another, I might not code anything except the designated 
initializer, and a cover for "plain" init so that any subclasses I (or 
someone else...) might cook up later will chain back up the line 
properly when hit with a "[super init]". Either way, if somebody 
subclasses from your class, they come in with the expectation that doing 
"[super init]" will do the right thing (by calling the root object's 
init method - perhaps directly, or perhaps through a very long and 
complex chain of calls, but it'll happen eventually)

> 
> 2. Ok, hopefully this question won't open up a can of worms.  What about 
> sub-classes?  I guess this is a two part question:
>   a) If there's a sub-class that doesn't particularly need it's own 
> class designated initializer, it could just use it's super's designated 
> initializer, correct?  If so, is this a common design pattern?

At least in theory, yes, that's correct. As for how common it is... 
<shrug> No clue - I've never actually taken the time to think about it. 

(minor nitpick: "it's" is a contraction meaning "it is" - You're looking 
for the possessive form: "its" - "that which belongs to it". Ain't it 
wonderful how consistent the english language is? :) )

> b) If the sub-class *does* need a designated initializer, I suppose it 
> could do an override of the super's version and that would be ok. 
> However, I would think that any additional initialization would have to 
> be done via assessor methods as the method names would have to be the 
> same.

Sounds right... I THINK - Assuming you're asking what I think you are.

If you're expecting to be subclassing off your subclass, then write your 
"first level" subclass - let's call it MyClass - like so:
(I'm assuming you're on a Mac, so you'll probably be subclassing it from 
NSObject)

Your .h file has (at least - perhaps MUCH more) in it:
---cut---
#import <Cocoa/Cocoa.h>

@interface MyClass : NSObject 
{
   // MyClass specific vars
   NSDictionary *myClassVars;
}
// And some method declarations
-(MyClass *)designatedInitializer:(id)anyNeededParams;
-(MyClass *)init;
// More stuff will likely live here in a useful program.
@end
---cut---

And in your .m file:
---cut---
#import "MyClass.h"
@implementation MyClass

-(MyClass *)designatedInitializer:(id)anyNeededParams
{
   self = [super init]; // Invoke NSObject's init
   
   // Do MyClass-specific init

   // and return what self has become.
   return self;
}

-(MyClass *)init
{
   // I'll assume defaultParams is set appropriately elsewhere
   return [self designatedInitializer:defaultParams];
}

// Any other methods MyClass needs follow
@end
---cut---

Notice that all init does is call the instance's designated initializer 
with default params. Which in turn calls [super init] (NSObject's, in 
this case)  before using the parameters it gets passed. You get the rest 
of your MyClass going, ship the project, and make a few bucks.

Time passes, and a project you just got handed wants something very 
nearly identical to MyClass, but with a couple little additions and 
tweaks. You decide to subclass from MyClass to make a new class of 
object -  The MySubclass

You toss together a quick .h file:
---cut---
#import "MyClass.h"
@interface MySublass : MyClass
{
   // MySublass specific vars
   NSDictionary *SubclassVar;
}
// And don't forget the method declarations
-(MyClass *)designatedInitializer:(id)anyNeededParams;
-(MyClass *)init;

@end
---cut---

And the .m file
---cut---
#import "MySubclass.h"
-(MySubclass *)designatedInitializer:(id)anyNeededParams
{
   self = [super init]; // Invokes MyClass' init
   
   // Do MySubclass-specific init work

   // and return what self has become.
   return self;
}

-(MySubclass *)init
{
   // I'll assume defaultMySubclassParams is set appropriately somewhere
   return [self designatedInitializer:defaultMySubclassParams];
}

// Any other methods MySubclass needs follow

@end
---cut---

You'll notice how close to identical the code is for both cases - The 
critical consideration is that you ALWAYS want your class' "init" to 
chain back to the root object, whether directly or indirectly.

> c) At each step down the hierarchy through sub-classes, the 'plain' init 
> would have to be overridden and it would have to return the current 
> class' designated initializer, correct?  In other words, you'd have to 
> re-write init for each sub-class where there is a new designated 
> initializer.

Basically, yes. See the snippets above.

-- 
Security provided by Mssrs Smith and/or Wesson. Brought to you by the letter Q

Back to comp.lang.objective-c | Previous | NextPrevious in thread | Next in thread | Find similar | Unroll thread


Thread

A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-22 13:39 -0800
  Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-22 14:48 -0800
    Re: A question on designated initializers Louis Wu <louiswu@ringworld.net> - 2015-11-22 16:26 -0800
      Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-22 17:24 -0800
        Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-23 02:39 +0100
  Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-23 01:18 +0100
    Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-22 16:49 -0800
      Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-23 02:02 +0100
        Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-27 17:19 -0800
          Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-28 13:22 +0100
            Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-28 17:37 -0800
              Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-29 03:45 +0100
  Re: A question on designated initializers Don Bruder <dakidd@sonic.net> - 2015-11-22 19:15 -0800
    Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-23 18:44 -0800
      Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-24 04:58 +0100
        Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-24 16:42 -0800
          Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-25 02:00 +0100
        Re: A question on designated initializers Greg Parker <gparker@apple.com> - 2015-11-25 01:25 -0800
      Re: A question on designated initializers Don Bruder <dakidd@sonic.net> - 2015-11-24 07:38 -0800
        Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-24 15:54 -0800
          Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-25 01:49 +0100
            Re: A question on designated initializers Don Bruder <dakidd@sonic.net> - 2015-11-24 18:51 -0800
              Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-25 04:41 +0100
                Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-25 00:25 -0800
                Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-25 14:16 +0100
                Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-25 17:30 -0800
                Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-26 03:03 +0100
                Re: A question on designated initializers Don Bruder <dakidd@sonic.net> - 2015-11-25 09:08 -0800
                Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-25 18:41 +0100
                Re: A question on designated initializers Don Bruder <dakidd@sonic.net> - 2015-12-02 14:37 -0800
                Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-12-03 00:58 +0100
          Re: A question on designated initializers Don Bruder <dakidd@sonic.net> - 2015-11-24 18:29 -0800

csiph-web