Subclassing - uiviewcontrollers: where could I find some examples? - objective-c

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.

Related

Custom delegate for NSWindow

I want to create a custom delegate for NSWindow.
CustomWindow is subclassed to get notified about NSWindowDelegate events.
Now I want to create delegate for this CustomWindow.
I tried following code:
CustomWindow.h
#class CustomWindow;
#protocol CustomWindowDelegate
- (void)method1:(CustomWindow *)sender userInfo:(NSMutableDictionary*) userInfo;
- (void)method2:(CustomWindow *)sender event:(NSEvent *)theEvent;
- (void)method3:(CustomWindow *)sender;
#end
#interface CustomWindow : NSWindow <NSWindowDelegate>
#property (nonatomic) id <CustomWindowDelegate> delegate;
#end
mainDocument.h
#import "CustomWindow.h"
#interface mainDocument : NSDocument
#property (assign) IBOutlet CustomWindow *mainWindow;
#end
mainDocument.m
#import "mainDocument.h"
#implementation mainDocument
- (void)method1:(CustomWindow *)sender userInfo:(NSMutableDictionary*) userInfo
{
...
...
}
- (void)method2:(CustomWindow *)sender event:(NSEvent *)theEvent
{
...
...
}
- (void)method3:(CustomWindow *)sender
{
...
...
}
#end
Its working as per expectations however its giving following warnings:
'retain (or strong)' attribute on property 'delegate' does not match the property inherited from 'NSWindow'
'atomic' attribute on property 'delegate' does not match the property inherited from 'NSWindow'
Property type 'id' is incompatible with type 'id _Nullable' inherited from 'NSWindow'
Auto property synthesis will not synthesize property 'delegate'; it will be implemented by its superclass, use #dynamic to acknowledge intention
How can I get rid of these warnings ?
Any helps are greatly appreciated.
NSWindow already has a delegate property and it uses its delegate for different purposes than you're using yours for. The errors are conflicts between your declaration of your delegate property with the declaration of the inherited property.
The simplest solution is for you to rename your property to customDelegate or something like that. Also, the general convention is for delegate properties to be weak, so you should probably declare yours as weak, too.
In general, one could combine a new delegate protocol with NSWindowDelegate and re-use the existing delegate property. In your case, though, since you've declared CustomWindow to conform to NSWindowDelegate, it seems like you're planning on making the window object its own delegate. So, that would conflict with this approach. But, for completeness, if you were going to do that you'd declare your protocol as an extension of NSWindowDelegate:
#protocol CustomWindowDelegate <NSWindowDelegate>
Your property declaration would have to have the same attributes as NSWindow's declaration of its delegate property. So:
#property (nullable, assign) id<CustomWindowDelegate> delegate;
Finally, since you're relying on NSWindow to actually provide the storage and accessor methods of the property, you'd fix the last warning by putting this in the #implementation of CustomWindow:
#dynamic delegate;

How to access a read-only propertly (re-defined readwrite in class continuation) from a derived class

I am in the following scenario:
I have define a class with a property to access the activeController that i made read-only
#interface BaseViewController : UIViewController
#property (nonatomic, weak, readonly) UIViewController *activeController;
#end
In the class continuation i have define the property as readwrite as i want to be able to set the active controller only within the class:
#interface BaseViewController ()
#property (nonatomic, weak, readwrite) UIViewController *activeController;
#end
How do i make the readwrite property accessible from a derived class?
#interface ChildViewController : BaseViewController
#end
The compiler only see the property defined as read-only in the derived class and i want to be able to make use of property within my derived class and set the activeview controller in the derived class.
It's better not to expose publicly an instance variable unless you really need to.
The standard pattern for making some additional parts of the class accessible to subclasses is making a separate header file, e.g. BaseViewController+Private with the declaration of readwrite. This file can then be included by 'insiders', that is class and it's subclasses.
You need to change the header file for BaseViewController to
#interface BaseViewController : UIViewController
{
__weak UIViewController *_activeController;
}
#property (nonatomic, weak, readonly) UIViewController *activeController;
which will allow you to us the following class continuation in the both the base and the child
#interface ChildViewController ()
#property (nonatomic, weak, readwrite) UIViewController *activeController;
#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.

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.

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?