Custom delegate - objective-c

I want to know how can I use a custom delegate?

Maybe an example will help you:
#import <UIKit/UIKit.h>
#protocol VSKeypadViewDelegate
#required
-(int)numberOfRows;
-(int)numberOfColumns;
-(NSString*)titleForButtonOnRow:(int)row andColumn:(int)column;
-(id)valueForButtonOnRow:(int)row andColumn:(int)column;
-(CGSize)sizeForButtonOnRow:(int)row andColumn:(int)column;
-(void)receivedValue:(id)value;
-(CGPoint)keypadOrigin;
#optional
-(NSArray *)additionalButtonsForKeypad;
//-(UIColor *)keypadBackgroundColor;
//-(UIColor *)keyBackgroundColorForRow:(int)row andColumn:(int)Column;
-(UIImage *)backgroundImageForState:(UIControlState)state forKeyAtRow:(int)row andColumn:(int)column;
-(BOOL)isButtonEnabledAtRow:(int)row andColumn:(int)column;
#end
#interface VSKeypadView : UIView {
id<VSKeypadViewDelegate> delegate;
NSArray *keypadButtons;
}
+ (VSKeypadView *)keypadViewWithFrame:(CGRect)r;
- (id)initWithFrame:(CGRect)r ;
-(void)fireKeypadButton:(id)sender;
#property(nonatomic, assign) id<VSKeypadViewDelegate> delegate;
#end
This is a keypad I wrote.
The VSKeyPadView derives from UIView and has a delegate ivar of type id<VSKeypadViewDelegate>, that means, that the object set to delegate is expected to conform to the protocol VSKeypadViewDelegate. That protocol has some required and some optional method. That means, that it is your responsibility to write those method — what ever makes sense for you.
You will find this code running in an example application at github.

Related

Call NSObject method from NSTextField Subclass?

I'm having trouble calling an external method from a NSTextField Subclass. I have a NSTextField subclass that I'm monitoring text with and when textDidChange I'm calling an external method that is of a NSObject class. For some reason my method doesn't get called. I'm hoping someone could explain why. My code is below. Thanks.
EDIT: Fixed code to what drewag suggested.
MyTextField.h
#import <Cocoa/Cocoa.h>
#class ObjectController;
#interface MyTextField : NSTextField <NSTextFieldDelegate> {
ObjectController *objectController;
}
#property (strong, nonatomic) ObjectController *objectController;
#end
MyTextField.m
#import "MyTextField.h"
#import "ObjectController.h"
#implementation MyTextField
#synthesize objectController;
- (void)textDidChange:(NSNotification *)notification{
[objectController methodFromOtherClass];
}
#end
ObjectController.h
#import <Foundation/Foundation.h>
#interface ObjectController : NSObject {
}
- (void)methodFromOtherClass;
#end
ObjectController.m
#import "ObjectController.h"
#implementation ObjectController
- (void) methodFromOtherClass {
NSLog(#"Testing");
}
There are two likely scenarios causing this issue:
objectController is nil when textDidChange: is called
textDidChange: is not actually being called because you didn't connect it up correctly.
I don't think anyone can help you beyond that since you did not post your connection code nor where you are setting objectController.
Probably forgot to assign the delegate to self or whatever object that implements the textDidChange? Happens to me a lot.
I fixed the issue by creating an instance of ObjectController instead of the above process.
ObjectController *objectController = [ObjectController new];
[objectController methodFromOtherClass];

do you need to import .h files when using delegates?

-(IBAction)ok
{
//send message to the delegate with the new settings
[self.delegate setHeight:_height Width:_width Mines:_mines];
[self.delegate dismissViewControllerAnimated:YES completion:nil];
}
the first message to the delegate wouldn't work until i imported ViewController.h, but the second one worked without the import.
if i add -(void)setHeight:(int)h Width:(int)w Mines:(int)m; as required in the optionsViewController protocol will that mean that i no longer have to import the root .h file.
i intend to use delegation to send messages in other parts of the program so i want to make sure i am using it correctly and not importing things when i don't need to.
Thank you.
if i add -(void)setHeight:(int)h Width:(int)w Mines:(int)m; as required in the optionsViewController protocol will that mean that i no longer have to import the root .h file.
Yes! You could also add it as #optional and it would work (remember to check if the delegate -respondsToSelector: in that case). The whole idea is that your object regularly knows nothing about the delegate object - except that it conforms to the protocol (ie implements the #required and possibly the #optional methods).
Added for clarification (on my phone, which is a pain in the butt):
//OptionsViewController.h
//this object does NOT have to import
//the calling viewControllers .h file
//which is what I think the OP does
#protocol optionsViewControllerProtocol;
#interface OptionsViewController : UIViewController
#property (nonatomic, assign) id<optionsViewControllerProtocol> delegate; //should be id, could be UIViewController too, if absolutely necessary (better design to make it id)
#end
#protocol optionsViewControllerProtocol <NSObject>
#required
-(void) setHeight: (NSInteger) height;
#end
//viewController.h
#import "optionsViewController.h" //necessary to get the protocols definitions
#interface OptionsViewController: UIViewController <optionsViewControllerProtocol>
//.....
If you define your delegate property to be of class UIViewController*, then the compiler will recognize the dismissViewControllerAnimated:completion: method without you needing to import anything, since that's a standard method for that class.
For a custom method, i.e. setHeight:Width:Mines:, you absolutely need to import the header file, or have it imported somewhere up the import chain.
Example: You have MyProtocol.h, and you want SomeClass to have a delegate property that conforms to that protocol. If you #import "MyProtocol.h" in SomeClass.h, you don't need to re-import it in SomeClass.m.
// SomeClass.h
#import "MyProtocol.h"
#interface SomeClass : NSObject
#property (weak, nonatomic) id<MyProtocol> delegate;
#end
//SomeClass.m
#import "SomeClass.h"
#implementation SomeClass
- (void)someMethod
{
[self.delegate myProtocolMethod];
}
#end

How to properly subclass a delegate property in Objective-C?

In subclassing a class, I want to also subclass a delegate of the parent class given that the subclass now has additional functionality. What's the best way to go about doing this? If I just declare another delegate property in the subclass with the same name I would get a warning "Property type 'id' is incompatible with type 'id' inherited from 'ParentClass'
Given this example that produces the warning:
// Class A
#protocol ClassADelegete;
#interface ClassA : NSObject
#property (nonatomic, weak) id<ClassADelegete> delegate;
#end
#protocol ClassADelegete <NSObject>
- (void)classADidSomethingInteresting:(ClassA *)classA;
#end
// Class B
#protocol ClassBDelegete;
#interface ClassB : ClassA
#property (nonatomic, weak) id<ClassBDelegete> delegate; // Warning here
#end
#protocol ClassBDelegete <ClassADelegete>
- (void)classBDidSomethingElse:(ClassB *)classB;
#end
Two solutions that remove the warning are.
1) In the subclass, place the protocol definition before the class definition. This is what UITableViewDelegate in UITableView.h does:
// Class B
#class ClassB;
#protocol ClassBDelegete <ClassADelegete>
- (void)classBDidSomethingElse:(ClassB *)classB;
#end
#interface ClassB : ClassA
#property (nonatomic, weak) id<ClassBDelegete> delegate;
#end
2) In the subclass, add the original protocol alongside the new one:
// Class B
#protocol ClassBDelegete;
#interface ClassB : ClassA
#property (nonatomic, weak) id<ClassADelegete, ClassBDelegete> delegate;
#end
#protocol ClassBDelegete <ClassADelegete>
- (void)classBDidSomethingElse:(ClassB *)classB;
#end
I assume (1) works as Apple do it this way, Option (2) removes the warning but I haven't compiled and run anything setup this way.
Follow the example of NSTableView and NSOutlineView.
NSOutlineView is a subclass of NSTableView, and defines its own protocol for its dataSource and delegate.
NSTableView declares its delegate this way:
- (void)setDelegate:(id <NSTableViewDelegate>)delegate;
- (id <NSTableViewDelegate>)delegate;
and NSOutlineView:
- (void)setDelegate:(id <NSOutlineViewDelegate>)anObject;
- (id <NSOutlineViewDelegate>)delegate;
Apparently the compiler is more lenient with bare method declarations than it is with property declarations.
Unlike NSTable/OutlineView, you might want to make the subclass's protocol inherit from the base class's protocol, e.g.
#protocol SpecializedProtocol <BaseProtocol>
... it probably depends on the situation.

Syntax for resolving incompatible property type on inherited delegate

Some code I inherited has an annoying warning. It declares a protocol and then uses that to specify the delegate
#protocol MyTextFieldDelegate;
#interface MyTextField: UITextField
#property (nonatomic, assign) id<MyTextFieldDelegate> delegate;
#end
#protocol MyTextFieldDelegate <UITextFieldDelegate>
#optional
- (void)myTextFieldSomethingHappened:(MyTextField *)textField;
#end
Classes which use myTextField implement the MyTextFieldDelegate and are called it with this code:
if ([delegate respondsToSelector:#selector(myTextFieldSomethingHappened:)])
{
[delegate myTextFieldSomethingHappened:self];
}
This works, but creates the (legitimate) warning: warning: property type 'id' is incompatible with type 'id' inherited from 'UITextField'
Here are the solutions I've come up with:
Remove the property. This works but I get the warning '-myTextFieldSomethingHappened:' not found in protocol(s)
Drop the protocol entirely. No warnings, but you also lose the semantic warnings if you forget to implement the protocol in the delegate.
Is there a way to define the delegate property such that the compiler is happy?
try:
#property (nonatomic, assign) id<UITextFieldDelegate,MyTextFieldDelegate> delegate;
UITextField has also got property named delegate, but it has another type. Just rename your delegate property to something else.
Found the answer in UITableView.h.
The UIScrollView has property name delegate, and the UITableView has the same name property.
#protocol UITableViewDelegate<NSObject, UIScrollViewDelegate>
// Your code
......
#end
The original problem is that there is no information about MyTextFieldDelegate's inheritance during declaration of delegate property. It's caused by forward declaration of protocol (#protocol MyTextFieldDelegate;).
I've faced the same problem but with protocol declaration in the other .h file. In my case solution was just to #import appropriate header.
In your case you just need to swap the order of declaration:
#class MyTextField;
#protocol MyTextFieldDelegate <UITextFieldDelegate>
#optional
- (void)myTextFieldSomethingHappened:(MyTextField *)textField;
#end
#interface MyTextField : UITextField
#property (nonatomic, assign) id <MyTextFieldDelegate> delegate;
#end

Overriding properties which conform to protocols

I seem to be getting a new error when using LLVM Compiler 2.0, which I haven't had before.
I have a protocol called DTGridViewDelegate defined as:
#protocol DTGridViewDelegate <UIScrollViewDelegate>
I have a property called delegate on DTGridView (a subclass of UIScrollView, which itself has a delegate property). This is defined as:
#property (nonatomic, assign) IBOutlet id<DTGridViewDelegate> delegate;
Now the message I get is:
DTGridView.h:116:63: error: property type 'id<DTGridViewDelegate>' is incompatible with type 'id<UIScrollViewDelegate>' inherited from 'UIScrollView'
Because I had said that the DTGridViewDelegate conforms to UIScrollViewDelegate, I thought that this would be ok to override this property in this way, and indeed this is the first compiler to suggest there is a problem.
I have fixed the error by declaring the property as such:
#property (nonatomic, assign) IBOutlet id<DTGridViewDelegate, UIScrollViewDelegate> delegate;
I am wondering whether this is a compiler issue?
Your setup looks like the same one used in the case of UITableView inheriting from UIScrollView. The UITableViewDelegate protocol inherits from UIScrollViewDelegate protocol.
I set up the following which compiles fine:
// .h
#protocol ParentClassDelegate
-(NSString *) aDelegateMethod;
#end
#interface ParentClass : NSObject {
id delegate;
}
#property(nonatomic, assign) IBOutlet id <ParentClassDelegate> delegate;
#end
//.m
#implementation ParentClass
#synthesize delegate;
-(id) delegate{
return #"Parent delegate";
}//-------------------------------------(id) delegate------------------------------------
-(void) setDelegate:(id)someObj{
delegate=someObj;
}//-------------------------------------(id) setDelegate------------------------------------
#end
//.h
#protocol ChildClassDelegate <ParentClassDelegate>
-(NSArray *) anotherDelegateMethod;
#end
#interface ChildClass : ParentClass{
}
#property(nonatomic, retain) IBOutlet id <ChildClassDelegate> delegate;
#end
//.m
#implementation ChildClass
//#synthesize delegate;
-(id) delegate{
return #"childDelegate";
}//-------------------------------------(id) delegate------------------------------------
-(void) setDelegate:(id)someObj{
delegate=someObj;
}//-------------------------------------(id) setDelegate------------------------------------
#end
Not sure what is causing your problem. I would note that in the header the UITableViewDelegate protocol looks like:
#protocol UITableViewDelegate<NSObject, UIScrollViewDelegate>
... so maybe the compiler likes things more explicit sometimes.
I would suggest a clean and build. That solves a lot of problems.
Since there isn't a formal Objective-C language specification, it's impossible to say whether the compiler is behaving properly. All we can say is that Apple's gcc doesn't seem to have a problem with the above scenario, though it's conceptually unsound as it can break Liskov substitution, since delegate is covariant from UIScrollView to DTGridView (though covariance is just as much a problem). What would happen if you passed a DTGridView to code expecting a UIScrollView, which then proceeded to set delegate to an object that conformed to UIScrollViewDelegate but not DTGridViewDelegate?