Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.objective-c > #226
| 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> |
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 | Next — Previous in thread | Next in thread | Find similar | Unroll 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