How to add a method to an existing protocol in Cocoa? - cocoa

I want to extend or add another method to an existing protocol. Although the protocol in particular is not important, this is what I am trying to do.
#protocol NSMatrixDelegate
- (void)myNewMethod:(id)sender;
#end
The compiler warns that I have a duplicate declaration of the same protocol. How would I do this properly?
Thanks.

You can't define categories for protocols. There are 2 ways around this:
use a new formal protocol
use an informal protocol and runtime checking
Formal Protocol
Defining a new formal protocol would look like this:
#protocol MyCustomMatrixDelegate <NSMatrixDelegate>
- (void) myNewMethod:(id)sender;
#end
Then you would make your custom class conform to <MyCustomMatrixDelegate> instead of <NSMatrixDelegate>. If you use this approach, there's something to be aware of: [self delegate] will likely be declared as id<NSMatrixDelegate>. This means that you can't do [[self delegate] myNewMethod:obj], because <NSMatrixDelegate> does not declare the myNewMethod: method.
The way around this is to retype the delegate object via casting. Maybe something like:
- (id<MyCustomMatrixDelegate>) customDelegate {
return (id<MyCustomMatrixDelegate>)[self delegate];
}
(However, you might want to do some type checking first, like:
if ([[self delegate] conformsToProtocol:#protocol(MyCustomMatrixDelegate)]) {
return (id<MyCustomMatrixDelegate>)[self delegate];
}
return nil;
)
And then you'd do:
[[self customDelegate] myNewMethod:obj];
Informal Protocol
This is really a fancy name for a category on NSObject:
#interface NSObject (MyCustomMatrixDelegate)
- (void) myNewMethod:(id)sender;
#end
Then you just don't implement the method. In your class that would send the method, you'd do:
if ([[self delegate] respondsToSelector:#selector(myNewMethod:)]) {
[[self delegate] myNewMethod:someSenderValue];
}

Related

How to send a message to the Master Class of a class?

Quick Question:
I am creating an object from the MainWindowController:
about = [[About alloc]init];
In the Class About I do my Init:
-(id)init{
if(!_viewAbout){
[NSBundle loadNibNamed:#"About" owner:self];
[NSApp beginSheet:self.viewAbout modalForWindow:*?????* modalDelegate:self didEndSelector:NULL contextInfo:NULL];
}
return self;
}
My problem is that the Window is created in the MainWindowController. My question is how to call/send a message to the creator of the class if the class itself doesn't know the master class?
If I understand you correctly, most classes have self.superclass and just super, like
[super someMethod....
or
[self.superclass blegh....
Or are you asking for the class that creates another class ? If that is the case, you need to declare the creator class inside the other one, some (id) variable would do the trick.
But the most popular design pattern on the mac is the delegate pattern, and once you start using that you will love it. Declaring a delegate is usually the way Cocoa and UIKit do things, but other programming languages might not. Obj-C doesn't have any magic variables like python f.ex. has. Either you have a delegate or you have a declared variable which you would set right after the init/alloc stuff.
Also your (init) call doesn't look right. Usually it looks like :
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Here you could declare your setting.
}
return self;
}
But my opinion is that if you are declaring a singular pattern, you would call a specific method in your class, like you do with so many classes on the iOS/Cocoa, like :
[someclass DefaultClass]
This would be your init class where you would do init, unless the class had been declared before and then you would just return the object.

Xcode override all methods

I want override all methods of a subclass automatically on xcode, for example I have a class extended of UiViewControler, how I override all methods of UiViewController on xcode to be more or less well:
- (id) init
{
return [super init];
}
My intention with this is to log all methods to see when they are called, then my methods will be more or less well
- (id) init
{
[self log];
return [super init];
}
where log is as follow method:
-(void) log
{
NSLog(#"%#",[(NSString *) (NSArray *) [NSThread callStackSymbols][1] componentsSeparatedByString:#"-["][1]);
}
thanks a lot!
In this case you don't have to do anything. If you don't provide an implementation, then the superclass's implementation will be used.
Edited after the question was edited
If you put the log statement in the superclass's implementation then it doesn't matter what you do with your own initialiser.
Why?
One of the many conventions in Cocoa is that each class has a designated initialiser. All the other designated initialisers then call this initialiser. And when you subclass the class, then you create a new designated initialiser for the new class, and as part of the initialisation - this calls the superclass's designated initialiser.
Which is why you see NSObject subclass initialisers calling [super init], because NSObject's designated initialiser is init.
So, just call your logging method in the designated initialiser of your class, and as long as you follow the above convention, this initialiser will always be called by a subclass, and so your logging method will always be called.

NSKeyedArchiver: distinguishing between different instances of the same class

I'm implementing support for Lion's "Resume" feature in my OS X app.
I have a custom subclass of NSViewController in which I implemented the method
encodeRestorableStateWithCoder: as:
#implementation MyClass (Restoration)
-(void)encodeRestorableStateWithCoder:(NSCoder*)coder {
[coder encodeObject:_dataMember forKey:#"object_key"]; // I get the warning below when this line is executed for the second time
}
- (void)restoreStateWithCoder:(NSCoder *)coder {
_dataMember = [coder decodeObjectForKey:#"object_key"];
}
#end
However, since I have multiple instances of MyClass, different values are saved into the same key ("object_key") and I get the following warning from Cocoa:
NSKeyedArchiver warning: replacing existing value for key
'object_key'; probable duplication of encoding keys in class hierarchy
What is the best practice to overcome this problem?
Edit: I found here that each instance automatically has its own namespace to avoid collisions, so the problem might be in the way I'm manually calling encodeRestorableStateWithCoder to different instances with the same NSCoder object without telling it that these are different instances. However, I still can't figure out how to do that properly.
Thanks in advance!
To overcome this problem, it is possible to create a new NSMutableData where each of which is written by a separate (new) NSKeyArchiver, and store them all in an array which is stored in the original NSCoder object.
Here is an example for encoding the restorable state of subitems. The decoding part can be straight-forward given this code.
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
[super encodeRestorableStateWithCoder:coder];
// Encode subitems states:
NSArray* subitems = self.items;
NSMutableArray* states = [NSMutableArray arrayWithCapacity: subitems.count];
for (SubItemClass* item in subitems)
{
NSMutableData* state = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:state];
[item encodeRestorableStateWithCoder:archiver];
[archiver finishEncoding];
[states addObject:state];
}
[coder encodeObject:states forKey:#"subitems"];
}

How to override a small part of a method?

I have these methods in a class at the moment which seem to work fine. I would like to create a subclass which inherits these methods. The problem I have is that in the third method (shiftViewUpForKeyboard) I want the if statement to be a different UITextField (mirror being the current example).
I've read that to override a method in the subclass, you have to basically copy it exactly with the new coding, but if I want to just change that small section what is the best way to do it?
Thank you in advance.
- (void) viewWillAppear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(shiftViewUpForKeyboard:)
name: UIKeyboardWillShowNotification
object: nil];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(shiftViewDownAfterKeyboard)
name: UIKeyboardWillHideNotification
object: nil];
}
- (void) viewDidDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver: self
name: UIKeyboardWillShowNotification
object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: self
name: UIKeyboardWillHideNotification
object: nil];
}
- (void) shiftViewUpForKeyboard: (NSNotification*) theNotification;
{
if(mirror.isEditing == YES)
{
CGRect keyboardFrame;
NSDictionary* userInfo = theNotification.userInfo;
keyboardSlideDuration = [[userInfo objectForKey: UIKeyboardAnimationDurationUserInfoKey] floatValue];
keyboardFrame = [[userInfo objectForKey: UIKeyboardFrameBeginUserInfoKey] CGRectValue];
UIInterfaceOrientation theStatusBarOrientation = [[UIApplication sharedApplication] statusBarOrientation];
if UIInterfaceOrientationIsLandscape(theStatusBarOrientation)
keyboardShiftAmount = keyboardFrame.size.width;
else
keyboardShiftAmount = keyboardFrame.size.height;
[UIView beginAnimations: #"ShiftUp" context: nil];
[UIView setAnimationDuration: keyboardSlideDuration];
self.view.center = CGPointMake( self.view.center.x, self.view.center.y - keyboardShiftAmount);
[UIView commitAnimations];
viewShiftedForKeyboard = TRUE;
}
}
In any case if you don't want to copy the full method in the subclass, and adding your little customization, the only other possible approach I see is to change the original class. To do it I can suggest two possibilities:
1)
You could create in the original class a method called:
-(UITextField *)keyboardShiftTextField
and then in this class replace the mirror.isEditing code with:
[[self keyboardShiftTextField] isEditing]
In such case the only difference between the two classes will be in the implementation of the new method, that for the original class will be:-(UITextField *)keyboardShiftTextField {
return mirror;
}
while in the subclass this return the right text field.
2)
A second approach is more elegant as it requires the definition of the delegate pattern. This requires some overhead in term of code but we'll provide you more flexibility. Besides if the only reason to make the subclass is just to override this third method, then using the delegate pattern you can avoid creating the subclass at all, as the "custom" work will be done by the delegate. If the number of methods to override is more than one, you can still use this mechanism by moving into the protocol section all the parts that need customization. This is a quite common technique for Obj-C and Cocoa, which limits the need for some classes in many cases. Typically you use a subclass when you want to provide a different functionality, but in your case you're not providing a different functionality, but just a customization for the same functionality (the view shift up).
The usual approach would be the http://en.wikipedia.org/wiki/Template_method_pattern: pull out just the bit of the method that varies between classes, make that a separate method, and override that in subclasses.
[EDITED to add ...] An alternative approach -- I can't tell whether it would work well here without seeing more of your code -- would be to make the thing that varies a parameter that's passed into the method (or select it on the basis of a parameter passed into the method, or something else of the kind). (You'd typically then use other mechanisms rather than inheritance+polymorphism to get the effect you want, of multiple things with similar behaviour: they'd be instances of the same class but fed with different data.)

Methods in super that will be subclassed anyway (Cocoa)

Sorry if this is a repost but I couldn't quite search for it because I can't explain it in a few words. I have a super class with lots of methods but they will always (not all of them) be subclassed. From the super I need to run those methods. I could either leave the methods in super empty or I could just not type them in super but call them anyway like so [self myMethod] and it will call my subclassed method even if it doesn't exist in super. This works but Xcode gives me an error though. 'superclass' may not respond to '-subclassmethod'
What should I do so I won't get the warnings?
I prefer to define the unimplemented methods in the superclass like this:
#interface GLObject : NSObject {}
- (id)someSubclassProvidedMethod;
#end
#implementation GLObject
- (id)someSubclassProvidedMethod {
[self doesNotRecognizeSelector: _cmd];
}
#end
It's almost entirely redundant, because the Objective-C runtime would eventually call -doesNotRecognizeSelector: if I didn't define the method at all. But because I do define it, it's in the class's interface which both keeps the compiler happy and provides me with some documentation.
Rather than the superclass, you could declare the methods in a protocol, what is called a "interface" in other languages.
#protocol MyProtocol
-(id)myMethodWith:(id)arg;
#end
Change the type declaration of the variables to declare that the object conforms to the protocol.
-(id)doStuffWith:(SuperClass <MyProtocol> *)aThing and:(id)another {
return [aThing myMethodWith:another]
}
Note that you won't be able to pass an instance of your SuperClass to doStuffWith:and:, since it won't implement MyProtocol, but it sounds like that's what you want.
My solution was a little weird, but here it is:
#protocol JSDog <NSObject>
- (void)yipe;
#end
#interface JSDog : NSObject
#end
#implementation JSDog
+ (void)initialize {
if ([self isSubclassOfClass:[JSDog class]] && ![self conformsToProtocol:#protocol(JSDog)]) {
NSAssert(false, #"Subclasses of JSDog must conform to <JSDog>.");
}
}
#end
Having a protocol with the same name as a class is precedented in NSObject. Because methods in a formal protocol a by default #required, you will be protected on both ends: in compile-time, if your JSDog subclass purports to conform to <JSDog>, but doesn't implement -yipe, you will receive an error; at runtime, if your subclass does not claim to conform with <JSDog>, you will receive a warning when the subclass is instantiated.
I lately like using NSAssert for this task:
- (BOOL)proceedForVersion:(int)versionInteger
{
NSAssert(false, #"This method needs to be overridden in a subclass of iMBApertureAbstractParser");
return NO;
}

Resources