Overriding properties which conform to protocols - objective-c

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?

Related

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

Does simply conforming to an Objective-C protocol do anything?

CocoaPlant defines a protocol CPCoreDataTraits, analogous to UITexInputTraits like so:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#protocol CPCoreDataTraits <NSFetchedResultsControllerDelegate>
#optional
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
#end
If I only want to synthesize the managedObjectContext property for one of my view controllers,
#implementation MyViewController
#synthesize managedObjectContext;
#end
i.e., I don't want to synthesize the fetchedResultsController property or implement any of the NSFetchedResultsControllerDelegate methods, should I still conform to the CPCoreDataTraits protocol, like so?
#interface MyViewController : UIViewController <CPCoreDataTraits>
#end
I.e., as long as I don't synthesize the fetchedResultsController property or implement any of the NSFetechedResultsControllerDelegate methods, then will the end result be exactly as if I had just declared the managedObjectContext property normally, like so?
#interface MyViewController : UIViewController
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#end
As you can see in the protocol declaration, the implementation by your class of the two properties is optional because these two properties have been declared under the #optional statement.
This means that any other class that will use any object conforming to this protocol, must check the effective implementation of an optional method or property before using it.
In the example, any class that wants to access the fetchedResultsController property has to check for the existence of the getter and/or setter methods, e.g. using the:
[myController respondsToSelector:#selector(fetchedResultsController)];
[myController respondsToSelector:#selector(setFetchedResultsController:)];
If the calling method doesn't do this preliminary check and your protocol implementation doesn't support any of these methods (because optional) then the app will raise an exception.
So your approach is correct, the only difference in the two examples is that if you don't use the notation than any call to conformsToProtocol: on your object will return NO.

Custom delegate

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.

Subclassing - uiviewcontrollers: where could I find some examples?

I'm a little bit confused about the custom UiViewController inheritance.
For example if I have:
#interface MyViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
IBOutlet UITableView *tableView;
id <MyDelegate> aDelegate;
AnObject *myObject;
}
#property (nonatomic, assign) id <MyDelegate> aDelegate;
#property (nonatomic, retain) AnObject *myObject;
#end
A subclass of MyViewController "inherits" the protocol declaration? that is, can or not it override the methods in them, setting the delegate and datasource properly without redeclaring in its interface?
And what about property and their possible deallocation?
I would some examples, links...
Firstly, a protocol is simply a promise that a class implements required and (optionally) optional methods. That's all it is. You can override these in subclasses and such however you want.
The data source and delegate of the table view are set to self, and self implements the UITableViewDataSource and UITableViewDelegate protocols.
In your sub-class, self is the sub-class. Overriding the protocol methods in the sub-class will work perfectly fine. The table view is the one defined in the parent class.
In short, the answer is yes. If you want more information I suggest you read up on how #protocol works.