awakeFromNib vs. initWithFrame

Mikuro

Crotchety UI Nitpicker
What's the proper way to create initialization code in a class that is always (and only) run once?

I'm creating a custom view class, and the relationship between awakeFromNib and initWithFrame: has me a little confused. There are three ways to create an instance, and each has different behavior.

1. If I create an NSScrollView in Interface Builder by selecting some controls in a window, choosing "Make subviews of > Scroll view", and then change its custom class to my subclass, then only awakeFromNib is called.
2. If I create a Custom View in Interface Builder and assign it any custom class, then initWithFrame fires, and then awakeFromNib ALSO fires.
3. Naturally, when I create an instance through code, only initWithFrame fires.

So how should I manage my initialization code in such a way that it'll work properly all three ways I mentioned above? Clearly I need to call my initialization code in both initWithFrame and awakeFromNib, but I don't want it to fire TWICE, as would happen in case #2.

The first thought I had was to simply create an instance variable, "BOOL didAlreadyInitialize", set it whenever I called my initialization code, and check that it was not set before calling my code again. But.....then there's the problem of how I initialize that instance variable. I can't count on it being false when the object is created, can I?

It seems like such a simple problem, but I'm having a little trouble coming up with a simple solution. What am I missing?
 
initWithFrame is the normal initialization methods for NSView's and all subclasses. awakeFromNib is called when the Nib file is loaded. Generally, you want to stay clear of awakeFromNib unless you're dealing with windows in which you're the owner of it. awakeFromNib is also used if you want to initialize UI components, which don't get loaded until the nib is loaded, which gets loaded with the class gets loaded.

For #1 above, have you checked to see if initWithCoder: is called? Interface Builder creates the objects in your nib by deserializing them, and so it uses NSCoder to do that.

And with your "didAlreadyInitialize" variable, you could always set it as an int, and then have -1 = not yes or no, 0 = no, and 1 = yes :)
 
kainjow said:
For #1 above, have you checked to see if initWithCoder: is called? Interface Builder creates the objects in your nib by deserializing them, and so it uses NSCoder to do that.
Ohhhhh! No, I hadn't considered that. I think that solves the problem. I simply need to call my initialization code from both initWithCoder and initWithFrame, and forget about awakeFromNib entirely. It all makes sense now. :D

Now that I think about it, I guess I should override the vanilla 'init' method, too. I doubt anyone would use it, but ya never know.

Thanks!
 
Back
Top