I have a class which implements many delegate methods. How to group the delegate methods into different classes by the protocol they belongs to and use them in the original class?
Rather than creating many classes, a simpler solution is to divide the class into different categories:
#interface MyViewController : UIViewController {
...
}
...
#end
#interface MyViewController (TableStuff) <UITableViewDataSource, UITableViewDelegate>
// methods related to table stuff
#end
#interface MyViewController (SearchStuff) <UISearchBarDelegate>
// methods related to table stuff
#end
Since categories just add methods to the existing class, you could use the any methods declared in a category in the "original" class.
Related
I have a class called ToolbarView which is a subclass of UIView and basically creates a UIView that has a disappearing / reappearing UIToolbar on top. I also have a subclass of ToolbarView called DraggableToolbarView enables the user to drag the view around the screen.
I need to create a delegate for ToolbarView so it can notify another object / class of when the toolbar reappears and disappears. I also need to create a delegate for DraggableToolbarView so I can notify another object / class when the view is dragged. DraggableToolbarViews delegate will also need to notify another object / class of when the toolbar reappears and disappears.
So I decided to implement ToolbarViewDelegate, and have DraggableToolbarViewDelegate inherit from it and have its own method like following:
ToolbarView.h
#import <UIKit/UIKit.h>
#protocol ToolbarViewDelegate;
#interface ToolbarView : UIView <UIGestureRecognizerDelegate>
{
id <ToolbarViewDelegate> _toolbarViewDelegate;
}
#property(nonatomic, assign) id <ToolbarViewDelegate> toolbarViewDelegate;
#end
ToolbarView.m
#import "ToolbarView.h"
#import "ToolbarViewDelegate.h"
...
- (void) showBars
{
...
if (self.toolbarViewDelegate)
{
[self.toolbarViewDelegate toolbarViewWillShowToolbar:self];
}
...
}
- (void) hideBars
{
...
if (self.toolbarViewDelegate)
{
[self.toolbarViewDelegate toolbarViewWillHideToolbar:self];
}
...
}
ToolbarViewDelegate.h
#class ToolbarView;
#protocol ToolbarViewDelegate
#required
- (void) toolBarViewWillShowToolbar:(ToolbarView *)toolbarView;
- (void) toolBarViewWillHideToolbar:(ToolbarView *)toolbarView;
#end
DraggableToolbarView.h
#import "ToolbarView.h"
#protocol DraggableToolbarViewDelegate;
#interface DraggableToolbarView : ToolbarView
{
id <DraggableToolbarViewDelegate> _draggableToolbarViewDelegate;
}
#property(nonatomic, assign) id <DraggableToolbarViewDelegate> draggableToolbarViewDelegate;
#end
DraggableToolbarView.m
#import "DraggableToolbarView.h"
#import "DraggableToolbarViewDelegate.h"
...
- (void)drag:(UIPanGestureRecognizer *)sender
{
...
if (self.draggableToolbarViewDelegate)
{
[self.draggableToolbarViewDelegate draggableToolbarViewWillDrag:self];
}
...
}
...
DraggableToolbarViewDelegate.h
#import "ToolbarViewDelegate.h"
#class DraggableToolbarView;
#protocol DraggableToolbarViewDelegate <ToolbarViewDelegate>
#required
- (void) draggableToolbarViewWillDrag:(DraggableToolbarView *)draggableToolbarView;
#end
SomeViewController.h
#import <UIKit/UIKit.h>
#import "ToolbarViewDelegate.h"
#import "DraggableToolbarViewDelegate.h"
#interface SomeViewController : UIViewController <ToolbarViewDelegate, DraggableToolbarViewDelegate>
{
}
#end
SomeViewController.m
#import "DraggableToolbarView.h"
...
- (void) toolbarViewWillShowToolbar:(ToolbarView*)toolbarView
{
//NSLog(#"Toolbar Showed");
}
- (void) toolbarViewWillHideToolbar:(ToolbarView*)toolbarView
{
//NSLog(#"Toolbar Hidden");
}
- (void) draggableToolbarViewWillDrag:(DraggableToolbarView*)draggableToolbarView
{
//NSLog(#"Dragged");
}
...
[draggableToolbarView setDraggableToolbarViewDelegate:self];
...
When I do this only the DraggableToolbarDelegate methods are responding. However when I also do [drabbleToolbarView setToolbarViewDelegate:self] it works. I've tried doing each delegate separately without inheritence and it works fine so I believe the problem isn't in any other part of the code.
Anyone might know why? I figured by making the protocols inherit, I wouldn't also have to set the ToolbarViewDelegate for a DraggableToolbar object.
UPDATE: Added a lot more code
In your code, any given DraggableToolbarView instance has two properties to connect to delegates, one called toolbarViewDelegate which it inherits from its superclass, and one called draggableToolbarViewDelegate which is defined in DraggableToolbarView itself. You've got to set both of those if you want the controller to get all the delegate messages.
What you're trying to do is possible, however. You need to use the same property name in both your view classes, so that there is only one delegate connection for any instance.
First, change the name of the delegate in the superclass. (Note that you don't need, and indeed shouldn't bother, to declare an ivar for the property -- it's created by #synthesize.)
#interface ToolbarView : UIView <UIGestureRecognizerDelegate>
#property (nonatomic, assign) id <ToolbarViewDelegate> delegate;
#end
You will use the same property name in the subclass.
#interface DraggableToolbarView : ToolbarView
#property (nonatomic, assign) id <DraggableToolbarViewDelegate> delegate;
#end
This is allowed as long as the name of the backing ivar in the subclass is different than that of the superclass, e.g.,
// In superclass
#synthesize delegate;
// In subclass
#synthesize delegate = delegate_;
Now change all the delegate messages in the two view classes to use this one property:
- (void)showBars
{
if (self.delegate)
{
[self.delegate ...
- (void)drag:(UIPanGestureRecognizer *)sender
{
//...
if (self.delegate)
{
[self.delegate ...
Now you can send setDelegate: to a DraggableToolbarView and it will use the same delegate for the dragging methods and the show/hide methods.
Finally, a terminology/explanatory note. In response to your previous question, Caleb used the correct term for "stacked" protocols, and Richard did not. Protocols don't inherit from each other, but one protocol can adopt the other. The relationship is similar, but distinct. When an object conforms to a protocol, it promises to implement the methods declared in that protocol. No implementation comes along with the protocol. The same is true of one protocol adopting the other -- the methods are just declared to exist in both. When you write:
#protocol DraggableToolbarViewDelegate <ToolbarViewDelegate>
you are saying that any object which promises to implement DraggableToolbarViewDelegate's methods will also implement the methods from ToolbarViewDelegate. That's all that it means. Again, no implementation comes along with that promise.
In this case, that means that a DraggableToolbarView can expect its delegate to implement the methods in ToolbarViewDelegate.
You have not given the entire code, but from whatever is out here,
Make sure that
Your ToolBarView and its subclasses have an id <ToolBarViewDelegate> delegate as a property.
Your DraggableToolbarViewDelegate extends NSObject protocol.
and your other ViewController object conforms to delegate protocol and not the toolbarview.
Once your controller gives implementation of delegates methods and conforms to the protocol, set the delegate of view's object to self and then use delegate property set in the view to call these protocol methods.
At the moment, the majority of my code is in the same viewcontroller, and i'd like to move some of it over to other areas. Such as moving the animations all over to somewhere else. But then how do i reference things which are in another class? And how do i reference back from that class to items in my viewcontroller class? Not going this has always disuaded me from doing it.
there is a couple of ways you can achieve that.
one way is the cocoa delegate #protocol way, the second way could be creating references to each object in the other class.
for the first way you can do something like this:
#class Class2;
#interface Class1 : NSObject {
Class2 *cls2Pointer;
}
#property Class2 *cls2Pointer;
#end
#class Class1;
#interface Class2 : NSObject {
Class1 *cls1Pointer;
}
#property Class1 *cls1Pointer;
#end
int main(){
Class1 cls1Obj = [[Class1 alloc] init];
Class2 cls2Obj = [[Class2 alloc] init];
[cls1Obj setCls2Pointer:cls2Obj];
[cls2Obj setCls1Pointer:cls1Obj];
}
the second way, is to declare a protocol in one/both of the classes to be able to pass arguments and call different methods on other objects:
#protocol Class1Delegate
- (void)class1:(Class1)obj MethodWithArg:(id)arg;
#end
#interface Class1 : NSObject {
id <Class1Delegate> delegate;
}
#end
#interface Class2 : NSObject <Class1Delegate>{
}
#end
#implementation Class2
- (void)class1:(Class1)obj MethodWithArg:(id)arg {
//do stuff when called from the 1st class
}
#end
You might like to look into this here - to create static classes in objective c and then reference them in a separate file by classname - as in the view controller quoted in the linked example.
Otherwise you can just create a new class within a separate .m file and then code it such that the calling method in another class will first create an instance of this new class and then invoke the necessary method on this instance.
Hope this helps.
Basically what you do is that you create one or more classes, move the code over to these classes and then create instances of these classes in your viewcontroller.
so if you had a method in your view controller
-(void)foo;
you would create a new class say C and move the method there.
then in your view controller you would create an instance variable of that class e.g.
C* myC;
then alloc/init and then call the foo method. This is not object oriented in the sense that foo is not really related to C in any way so method foo could have just been a static method not relating to the instance and as such called just like any other method but as [C foo] instead of [self foo] from the view controller.
the other more OOP method would be to move functionality that belongs to together into a separate class like animation in your example.
#interface MainViewController : UIViewController < FlipsideViewControllerDelegate >{
}
I am quite new to object oriented languages & especially obj.c.
I need to use addressbook framework within this class.Apple documentation suggests this code:
#interface ViewController : UIViewController < ABPeoplePickerNavigationControllerDelegate > {}
I was wondering how to use at the same time FlipSideControllerDelegate & ABPeoplePickerControllerDelegate.
In fact I really can't understand what i am doing:)
You can declare your class as conforming to both the FlipsideViewControllerDelegate and the ABPeoplePickerNavigationControllerDelegate protocols like this:
#interface MainViewController : UIViewController <FlipsideViewControllerDelegate,
ABPeoplePickerNavigationControllerDelegate> {}
Then implement the required methods in MainViewController's #implementation.
I have a large class, which I have divided into several different class extension files for readability.
#protocol MyProtocol
#required
-(void)required;
#end
#interface MyClass : NSObject <MyProtocol>
#end
#interface MyClass (RequiredExtension)
-(void)required;
#end
Is there a better way to do this, without the compiler warning?
warning: class 'MyClass' does not fully implement the 'MyProtocol' protocol
Use a category for each protocol implementation. I use this when I have complex viewControllers.
For example, I have a category that implements NSTextDelegate protocol.
So, MyComplexViewController+NSTextDelegate.h:
#import "MyComplexViewController.h"
#interface MyComplexViewController (NSTextDelegate) <NSTextDelegate>
#end
and MyComplexViewController+NSTextDelegate.m:
#import "MyComplexViewController+NSTextDelegate.h"
#implementation MyComplexViewController (NSTextDelegate)
- (BOOL)textShouldBeginEditing:(NSText *)textObject{
...
}
- (BOOL)textShouldEndEditing:(NSText *)textObject{
...
}
- (void)textDidBeginEditing:(NSNotification *)notification{
...
}
- (void)textDidEndEditing:(NSNotification *)notification{
...
}
- (void)textDidChange:(NSNotification *)notification{
....
}
#end
Then I take all the headers for the main class definition and the categories and combine them into one header which I then import where I need to use the class.
#interface MyClass : NSObject
#end
#interface MyClass (RequiredExtension) <MyProtocol>
-(void)required;
#end
Adopt the protocol in the category.
You don't need to change your style of coding. To get around the warning, it only need to implement "required" method of the protocol, not "optional"
If that's only for readability, you should use categories only. A protocol is not needed in such a case.
I am new at the area of iPhone. i am trying to build an iPhone app by using Cocos2d. I have used this type of classe like bellow-
#interface MenuScene : Scene {}
#end
#interface FlipView : UIImageView
{
CGPoint startTouchPosition;
NSString *dirString;
UIImageView *firstPieceView;
UIImageView *secondPieceView;
}
#end
#interface HelloController : UIViewController
#end
#interface MenuLayer: Layer{
Menu * menu;
NSString *dirString;
CGPoint startTouchPosition;
}
-(void) button1: (id)sender;
-(void) button2: (id)sender;
-(void) black_jack: (id)sender;
#end
and i want to inherit two classes(FlipView, HelloController ) to MenuLayerClass. but how can i do it. Actually what will be syntax. Pls reply any comment with code or syntax how i can do it.
You can't. As Clark says, Objective-C does not support multiple inherritance. This is because the designers believe that the advantages of multiple inherritance do not justify the complexity and bad design it encourages.
Instead, they have included something that will meet your needs. You can declare a 'protocol' using the #protocol directive. A protocol describes a set of methods a class responds to but cannot add data to an object.
To use a protocol, you include the protocol name in angle brackets after the super class.
e.g.
#protocol myProtocol
-(void)myProtocolMethod
#end
#interface myClass : NSObject <myProtocol>
{
int someData;
}
Will give an NSObject subclass that must also respond to (void)myProtocolMethod messages.
That said, I would agree with Clark that you should review your design - having a single object that is both FlipView, HelloController does not sound good. You should probably implement a FlipController and use a third class (the model) to synchronise state between the two controllers - or if your app is very simple, have a single class that acts as a delegate for both FlipView and UIController.
You cannot, as Objective-C does not have multiple inheritance. Additionally, it doesn't really make sense to have a single class be both a view and a view controller.