Let’s try to clear away some of the irrelevant stuff:
> On Dec 26, 2014, at 11:54 , N!K <[email protected]> wrote:
>
> 1) I added:
>
> -(id)init
> {
> self = [ super init ];
> if( self ){
> NSLog(@"\n\n init"); }
> return self;
> }
>
> -(id)initWithCoder:(NSCoder*)coder
> {
> self = [ super initWithCoder:coder ];
>
> if( self )
> NSLog(@"\n\n initWithCoder");
> return self;
> }
>
> Only initWithCoder: is reached; NSLog outputs from there and a breakpoint
> stops there.
>
> init and initWithFrame: are not reached. No NSLog outputs. No breakpoint
> stops there.
>
> —This raises a new question: Why isn’t ’init’ reached at all?—
This is a Cocoa matter. Every class can have multiple initializers (that is,
instance methods whose name starts with ‘init’). One or more of these
initializers is a “designated initializer”, that is, an initializer through
which control must pass when the object is created. If there are more than one,
control must pass through one and only one of them.
The designated initializer is an informal concept, so it has no syntactic
marker. (In Obj-C — it does in Swift.) Also, a particular method name might be
a designated initializer in one class, but not in another class. (A
non-designated initializer is called a “convenience” initializer, and by the
above rules any convenience initializer must invoke a designated initializer.)
In particular, the designated initializer(s) of a class may not be the same as
it superclass. The waters are muddied a bit more because initializers can be
inherited. That makes is possible that the designated initializer depends not
only of the class the method is defined in, but also the class of the object
being initialized.
It’s all a bit of a mess, but it works quite well in practice so long as you
don’t obsess about the informality of it all.
So, ‘init’ is the designated initializer of NSObject, but not of NSView.
NSView’s designated initializer is ‘initWithFrame:’. If you wrote code to send
‘init’ to a NSView object, I’d expect you’d end up at ‘initWithFrame:’ — in
class NSView, ‘init’ is a convenience initializer.
‘initWithCoder:’ is implemented in many classes, but you don’t know in general
whether it’s a[nother] designated initializer or a convenience initializer.
IOW, you don’t know, in terms of class machinery, whether -[NSView
initWithCoder:] is supposed to invoke -[NSView initWithFrame:] or not. However,
in this case, the resource loading guide suggests that one or other is invoked,
but not both, so I guess they’re both designated initializers.
> I need to know why initWithFrame stopped working, how to use initWithCoder:
> correctly, and what potential pitfalls are out there. There may be more than
> this one:
> WANNABEGEEK:“ Identity Inspector - User Defined Runtime Attributes
> In your implementation class you cannot use initWithCoder: otherwise your
> key-value path setting will not be picked up. You will have to do all your
> implementation within awakeFromNib.”
> Clearly I have some studying to pursue, after this fine start you have given
> me.
Be careful before putting your faith in information that comes from the
Internet. It may have been true once but false now. It may be somewhat useful
and technically inaccurate at the same time. This particular gem seems like an
example of the latter.
> 4) Apparently initWith Coder: is suitable. It worked. But I don’t yet know
> why. I don’t even know what the “coder" argument refers to, or what it should
> be.
> In looking up initWith Coder: I found it described in Stack Overflow as
> The NSCoder class is used to archive/unarchive (marshal/unmarshal,
> serialize/deserialize) of objects.
>
> This is a method to write objects on streams (like files, sockets) and being
> able to retrieve them later or in a different place.
>
> I would suggest you to read Archiving
>
> Since I didn’t plan to do any archiving at this point, I rejected it. Thanks
> for redirecting me.
*You* don’t do any unarchiving of views, but your app does, because it’s
loading a view hierarchy from a NIB file, which is a file full of archived
objects including your views. That’s *why* initWithCoder: is invoked, in
general.
If you’re still with me, you’ll see (I hope) that everything appears to be
working as it should, *except* that initWithCoder: is being invoked in a
situation where we’d expect to see initWithFrame:.
None of use who have weighed into this thread have an explanation (yet) of why
that is. We expect the NIB-loading machinery to produce an invocation of
initWithFrame:, but it apparently isn’t. I just looked at the documentation
again:
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html
<https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html>
and I notice it says this (edited down a bit):
> • By default, objects receive an initWithCoder: message.
>
> […]
>
> • Custom views in OS X receive an initWithFrame: message.
>
> Custom views are subclasses of NSView for which Xcode does not have an
> available implementation. […]
>
> When it encounters a custom view, Xcode encodes a special NSCustomView object
> into your nib file.
It’s certainly possible that in Xcode 6 and/or Yosemite, it's is a bit smarter
about knowing when it has “an available implementation”. It’s certainly
possible that it knows it has your custom view class in the project, and so
optimizes this so that it’s treated as a *known* view, therefore sending the
normal initWithCoder: instead of initWithFrame:. If that’s so, there’s nothing
wrong here, and our collective wisdom was just a bit out of date.
Or, there’s something a bit more subtle going on, which I don’t know how to
diagnose except by submitting a bug report (“my custom view gets the wrong
initializer invoked”) and see what comes back.
Finally, the continuation of the above documentation reads as follows:
> The custom view object includes the information it needs to build the real
> view subclass you specified. At load time, the NSCustomView object sends an
> alloc and initWithFrame: message to the real view class and then swaps the
> resulting view object in for itself. The net effect is that the real view
> object handles subsequent interactions during the nib-loading process.
If you think about it, this makes sense in terms of initializers. The
NSCustomView placeholder object is in fact unarchived from the NIB file, so it
gets initWithCoder:. The replacement object of your class is created directly,
so it gets initWithFrame:.
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Xcode-users mailing list ([email protected])
Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/xcode-users/archive%40mail-archive.com
This email sent to [email protected]