How should I subclass NSWindow initialization in Objective-C - objective-c

i want to create a subclass of NSWindow. this subclass needs to initialize some member variables before they are used. what is the best way to capture initialization in objective c? what i find is that init rarely gets called in a way that allows me to do this. NSWindow has a couple of initialization vectors that i would need to override. do i need to override each of them?

Each class should have one so-called designated initializer. This is the init method that all other init methods call. That's the one to override. The documentation usually tells you which one the designated initializer is. In the case of NSWindow, it is:
initWithContentRect:styleMask:backing:defer:
This method is the designated initializer for the NSWindow class.
In addition to the designated initializer, you should also override -initWithCoder: if the class you subclass implements the NSCoding protocol. -initWithCoder: is the initializer that is used when an instance is instantiated from an archive (such as a NIB file).
See The Designated Initializer in Apple's "The Objective-C Programming Language".

Have you tried overriding the designated initialiser
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation screen:(NSScreen *)screen
Documentation

Related

NSWindowController initialization warning

I am developing a document-based app. I am using a dedicated window controller for the document window, and calling the -[NSDocument makeWindowControllers] method.
My window controller is initialized like this:
- (instancetype) init
{
if (self = [super initWithWindowNibName:#"Document" owner:self]) {
}
return self;
}
Here, #"Document" is the .xib file containing the main document window that was created with the project.
The rationale here is that, this window controller is always initialized with this type of window, so the parameter is both hard-coded and hidden away inside the implementation of -init (while also conveniently setting the window owner to self).
So, the side that instantiates the window controller (in my case, the document class) doesn't need to worry about which nib to use and can just call -init.
The problem is, I am breaking the designated initializer chain and Xcode complains with these warnings:
Semantic Issue Method override for the designated initializer of the
superclass '-initWithCoder:' not found.
Semantic Issue Designated initializer missing a 'super' call to a
designated initializer of the super class.
Semantic Issue Method override for the designated initializer of the
superclass '-initWithWindow:' not found.
Semantic Issue Designated initializer invoked a non-designated
initializer.
I would switch the call to -initWithWindowNibName:owner: with one to -initWithWindow: (and after that, set the owner manually, I guess?); but I don't know how to create an NSWindow directly from a nib (or if this is the right thing to do).
EDIT: I just discovered that the warnings are being triggered only because I labeled -init as NS_DESIGNATED_INITIALIZER in my interface. I can remove that label and the warnings go away, but -init is my de-facto designated initializer so I would rather keep it.

Objective C: init and awakeFromNib

I've recently studied some Cocoa based open source projects. I saw that a lot of programs have all initializing code in awakeFromNib and rarely use the designated initializer. I am used to do it that way:
in the overridden designated initializer: do all non-Nib stuff
in awakeFromNib: do all Nib-related stuff
Is this approach wrong?
Yes, it's correct, all nib-related stuff should be done in awakeFromNib method. At the moment when it's called you already have initialized and loaded view from nib, so you already may configure and use it.
As concerned to initializers, please, check this question: iOS: UIView subclass init or initWithFrame:?
The designated initializer is the one that all the other initializers must call. UIView and subclasses are a little unusual in that they've actually got two such initializers: -initWithFrame: and -initWithCoder:, depending on how the view is created. You should override -initWithFrame: if you're instantiating the view in code, and -initWithCoder: if you're loading it from a nib. Or, you could put your code in third method and override both those initializers such that they call your third method. In fact, that's often the recommended strategy.

why must i inherit NSobject instead of NSapplication to implement delegate method on GNUSTEP?

I've seen several Obj-C tutorials. The delegate classes all inherit from NSObject. For example, the applicationDidFinishLaunching delegate method, in some tutorials, it inherited from NSObject but NSApplication to implement it. The reason I don't think it should inherited from NSObject is that I didn't find any delegate protocol declaration in it, but I found that delegate protocol declaration in NSApplication. My Objective-C toy environment is GnuSep.
Here is some code:
#interface browserController : NSObject //here. inheriting from NSObject,but NSObject don'have any protocols declaration about applicationDidFinishLaunching.
{
NSBrowser *browser;
}
#end
#implementation browserController
- (void)menuAction:menuItem
{
..............................
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSWindow *win;
ActiveBrowserDelegate * abd;
WindowDelegate *wd;
NSRect wf = {{100, 100}, {600, 500}};
NSRect bf = {{10, 10}, {580, 350}};
.............................
}
It is called informal protocol (though GNUstep declared it anyway as GSAppDelegateProtocol for documentation purpose) NSApplication will simply check it at runtime if your delegate object will respond to the message, (using -respondsToSelector:) A delegate can be a view, a string, a proxy, anything as long as you make it responds to the selector. You don't need to make your delegate implement every method in such protocol since all verifications would be done at runtime. To make it looks cleaner you could just redeclare -applicationDidFinishLaunching: in #interface though you don't really need to, just make one in the #implementaiton is enough.
A delegate may inherit from anything appropriate. It is usually supposed to implement a certain protocol.
A protocol is a way of implementing a formal communication interface between two classes.
However, it is most unlikly that a delegate will inherit from its communication partner class.
With other words: Protocols are often used to overcome the unavailability of multiple inheritance. (Pretty much like interfaces in Java)
Example: A UIViewController subclass' instance controls a view that contains a UITableView. Rather than subclassing the UITableView for the implementation of its look or data, there are two delegates assigned to the table view object. One delegate serves as provider for custom layout (provides items such as the header view) and another (?) delegate provides the data that is being displayed.
Now, this delegate could be any object, inheriting from NSObject and implementing the two protocols. This object cold then be instanciated by the view controller and assigned to the table.
However, it is common practice that the view controller itself serves as delgate for the table(s) that it controls. That is a good pattern but strictly spoken not required. It could be any object.
Now the custom view contoller inherits from UITableViewController (which already implements the protocols and inherits from ViewController) and serves as delgate for the table view. The table view itself could be any subclass of UITableView. (Although this is a bad example here because subclassing UITableView is normally not advisable)
If the delegate does not need to inherit from any class and just implements the protocol, then it shold at least inherit from the cocoa base class NSObject. That ensures that it inherits all the usual capabilites and behaviour of any object. (init method, copy method, description method etc.) That may be required to work properly with other classes of the framework such as beeing used as an object within an NSArray, NSLog etc.

overriding undeclared methods in subclass

I have a class with some methods neither declared in .h file nor in any category, I want to override these methods in the subclass to change the behavior slightly. I am thinking of simply redefining those methods in subclass. Is it a good idea? would it even work?
Ideally the subclass needs to know what the methods are if it wants to override the method and still call super.
One way of doing this is by having a separate header file which both the super class and subclass implementations both import.
// MyClass_protected.h
- (void)someMethodThatYouWantSubclassesToBeAbleToOverride;
Then
// MyClass.m
#import "MyClass_protected.h"
// MySubClass.m
#import "MyClass_protected.h"
It'll 'work' in that the compiler allows it. The class that defines these methods probably assumes they do particular things when called, which your implementation needs to respect when overriding them to avoid introducing bugs in the use of the class's interface.
You can override private methods in a base class but the problem is that you can't call [super someMethod]. If you wish to completely replace the original method then this isn't an issue.
Otherwise you need to let the derived class know about the methods in the parent class.

why does initializing subclasses require calling the super class's same init function?

I have heard that when you have a subclass, you are supposed to initialize the superclass with the same init function from within the subclass's init. What I mean is that the subclass's init should call [super init] and the subclass's initWithFrame should call [super initWithFrame]. Why is this? Why does calling the super's init from a subclass's initWithFrame result in an infinite loop?
If this is required, then does this mean I can't create a new init function within a subclass such as initWithPoint and have that call super's init or initWithFrame simply because the super class doesn't have initWithPoint? I guess the heart of the question here is simply why it's improper to call a different super class, something that's confusing me possibly because of my c++ background?
When you create a subclass, if you implement an initializer, then you must be sure to call the superclass's designated initializer(s), and you must provide at least one designated initializer of your own, though this can just be your override of the superclass's.
As part of initializing your subclass, you must call one of the superclass's designated initializers.
A class's documentation should nominate its designated initializers. If not, the designated initializer is generally assumed to be the most specific initializer (the one taking the most arguments) provided by the superclass.
For further details, see "The Objective-C Programming Language: Allocating and Initializing Objects." [Note: As of December 2013, this content no longer appears to be available via Apple's doc center. What was a language reference has been replaced by more task-oriented tutorials and conceptual documentation.]
As to your specific questions:
Why is this? So that the superclass has a chance to initialize its state. You can then go ahead and initialize the state you add above and beyond what the superclass provides.
Why does calling the super's init from a subclass's initWithFrame result in an infinite loop? Because, for NSView, -init is not the designated initializer, though it is NSObject's. So NSView overrides it to call its designated initializer, -initWithFrame:. If you've called -init from your -initWithFrame:, you now have -initWithFrame: calling -init calling -initWithFrame: calling -init: calling…
Does this mean…? No, because this is not required. You must understand the actual documentation, not hearsay.
Why is this? Why does calling the super's init from a subclass's initWithFrame result in an infinite loop?
If the -init in super is implemented as
-(id)init {
return [self initWithFrame:CGRectZero];
}
then the call graph will loop around:
[subclass initWithFrame:]
| ^
v |
[super init]
as self always uses the current class ("subclass").
If this is required, then does this mean I can't create a new init function within a subclass such as initWithPoint and have that call super's init or initWithFrame simply because the super class doesn't have initWithPoint?
No this is not required. What is preferred is to call super's most specialized initializer, so there's no chance super's -initXXX calls back the subclass's -initYYY.
Why does calling the super's init from a subclass's initWithFrame result in an infinite loop?
Coming from a C++ background as you say you do, the main problem is probably that you are used to the C++ method calling paradigm. In Objective-C, you do not call functions of objects. It's not even technically completely correct to say you invoke methods. In Objective-C, you send messages to objects and the object decides what to do with them. What it normally does is look up a method in its class and invoke that. The consequence of that is that you cannot control which version of a method in a class hierarchy gets invoked by a message. It's always the method belonging to the class of the object you send the message to (except in one case). It's as if C++ had no non virtual functions, not even the constructors.
The one exception to this is when you send a message to super. In that case, the method on your class is bypassed. This can lead to infinite loops as you have found out. The reason is because we don't call functions, we send messages. So if methodA in class SubKlass sends [super methodB] the implementation of methodB in Klass will be invoked. If it then sends [self methodA] self is still an instance of SubKlass, it hasn't magically transformed into an instance of Klass, so methodA in SubKlass will be invoked.
This is why the rules for initialisers seem so convoluted. Only the designated initialiser is guaranteed not to send one of the other initialisers so you can only safely send the designated initialiser to super in your initialiser.
from a c++ perspective:
I have heard that when you have a subclass, you are supposed to initialize the superclass with the same init function from within the subclass's init. What I mean is that the subclass's init should call [super init] and the subclass's initWithFrame should call [super initWithFrame].
that's not true. it's merely common. you are free to call any superclass initializer that is documented as a valid initializer.
it may help to view it like this:
look at the superclass' initalizers and determine which are supported.
sometimes there is a designated initializer
sometimes there are new initializers (e.g., one which may add an argument to the super-superclass)
sometimes there are intializers inherited from the super-superclass
for designated initializers: consider it protected
for new initializer: consider it protected
for inherited initializers: typically consider private when the superclass declares new initializers, otherwise protected
Why does calling the super's init from a subclass's initWithFrame result in an infinite loop?
such is the effect (undefined behavior) of calling an intializer which you should not call.
If this is required, then does this mean I can't create a new init function within a subclass such as initWithPoint and have that call super's init or initWithFrame simply because the super class doesn't have initWithPoint?
this is fine as long as you call through one of the supported superclass initializers.
I guess the heart of the question here is simply why it's improper to call a different super class, something that's confusing me possibly because of my c++ background?
objc doesn't support hiding/visibility for initializers. once it's in a superclass' interface, it's there (and you're able to make bad choices where the compiler can't help you) - you're expected to determine the visibility graph for initializers and write your subclass accordingly. objc is lacking language features that you're accustomed to having in c++.
I don't know where you heard it from, but AFAIK it's not required. You can choose to init your subclass with whatever you want, provided that you call an init method of the superclass. Any init method will work.
However, if you also have the same init function in your superclass, I think the better thing to do is to call that function, then add your own customization. It's not required, it's just good practice to do so, because that init function may provide some initializations and settings that you may forget to add.