Subclass a Delegate? - iphone

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 which 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.
Currently, I have create a separate delegate for each, but I am wondering if there is a better pattern for this? Maybe implement one delegate for ToolbarView, and list the delegate methods from DraggableToolbarView as optional? Or is there a way to subclass a delegate?
What is the best / cleanest way to accomplish this?

If you create a protocol for your delegate methods (always a good idea anyway), you can have another protocol adopt the first. That sets up an inheritance-like relationship:
#protocol ToolbarViewDelegate
// some methods
#end
#protocol DraggableToolbarViewDelegate <ToolBarViewDelegate>
// additional methods
#end

Yes, you can have inheriting protocols:
#protocol Proto1
#reqired
-(void) somethingHappened:(id) sender;
#optional
-(void) somethingElseHappened:(id) sender;
#end
#protocol Proto2<Proto1>
// this now contains all of the method signatures found in proto1, with the addition of new ones!
-(void) somethingSpecialHappened:(id) sender;
#end

I think you're doing it right.
Consider UITextView which is a subclass of UIScrollView. Each has its own delegate protocol that's responsible for reacting to a specific set of messages. As long as you think of visibility and dragging as separate concerns, allowing different objects to handle their delegation seems logical.

Related

Calling views from subclasses

I have an iPhone app primarily made of two views, let's call them fullScreen and cardViews (the cardViews are presented as subViews of the full screen views). I've handled all of the animations in presenting the card Views by having a masterCardViewClass and a masterFullScreenViewClass. All specific cardViews are subclasses of the masterCardView, all specific fullScreenViews are subclasses of the masterFullScreenView.
I present a cardView with a method from the masterFullScreenViewClass. I dismiss the cardView with a delegate method from the masterCardView. However, I'm having a problem calling a method to present a cardView from another cardView. All cardView presenting methods are contained in the masterFullScreenViewController class.
How do I access these methods without copying a pasting them locally where I need them.
One way of doing it is by using protocols.
In a nutshell, your masterCardView class would implement a protocol method that presents a cardView (for the sake of simplicity, let's say that you invoke cardViews with a certain index):
masterCardView.h:
#protocol CardPresenterDelegate <NSObject>
- (void)presentCardViewWithIndex:(int)index;
#end
#interface MasterCardView:UIViewController <CardPresenterDelegate>
...
masterCardView.m:
- (void)presentCardViewWithIndex:(int)index
{
// Code for presenting a cardView
}
You would also need to create a delegate (weak) property in your cardView:
cardView.h
#property (weak) id<CardPresenterDelegate> cardPresenterDelegate;
And then by accessing that property in your cardView, you can tell the masterCardView to do something for you:
cardView.m
[self.cardPresenterDelegate presentCardViewWithIndex:5];
Oh, and, don't forget to set the delegate property on your cardViews when creating them in your masterCardView:
back in masterCardView.m:
cardView.cardPresenterDelegate = self;

Objective-C -- Subclass of delegate in subclass

This is a fairly complicated inheritance hierarchy, so bear with me (I've tried to simplify things rather than state the exact case I am using which is even more complex):-
Let's say I create a subclass of UITextField called TextField which is my own custom enhanced general-purpose textfield. Now, in order to provide this enhanced functionality, in the init method of TextField, I set super.delegate = self so that all the delegate methods from UITextField are sent to TextField. TextField implements the UITextFieldDelegate protocol and receives those delegate methods to do something interesting.
However, in turn, I want to make it so that TextField has it's own delegate. So I create a new protocol called TextFieldDelegate (note the lack of UI-prefix!) and give TextField an ivar id<TextFieldDelegate> __weak delegate with corresponding property so that other classes can receive delegate methods from TextField.
I hope you're still with me, because I haven't done anything too complex so far. But let's say that now, I create another custom subclass of TextField, let's call it PasswordTextField (in real life, one probably wouldn't need to create a subclass just to implement a password functionality, but let's assume that there is some fairly sophisticated implementation that would require this).
Let's also assume that I want to make it so that PasswordTextField (which like TextField has a delegate property) is able to send an enhanced set of delegate methods. For example, maybe it can send a method passwordIsSecure which is sent once a password has reached a required level of complexity. Now since this behaviour that wouldn't be found in the regular TextField, I create a new protocol: PasswordTextFieldDelegate <TextFieldDelegate> which defines the new delegate methods for PasswordTextField and inherits all of the delegate methods sent by TextField.
The problem is: how do I do implement this in PasswordTextField? Things that don't work:
Inheritance
I cannot simply inherit the delegate from TextField, because TextField's delegate conforms only to TextFieldDelegate and not PasswordTextFieldDelegate, so I can't send methods like [delegate passwordIsSecure] because TextFieldDelegate has no such method.
Overriding ivar
I could try declaring an ivar in PasswordTextField called delegate, but the compiler complains that this is a duplicate declaration, because of course there is already an ivar called delegate in the superclass, so this doesn't work either*.
Modifying the superclass
I could go back to the TextField class and redefine the delegate to implement both TextFieldDelegate and PasswordTextFieldDelegate, but this seems messy and tells TextField that it can send PasswordTextFieldDelegate methods, which of course, it can't!
I haven't tried this one, simply because it seems to break every sensible coding rule in the book.
In summary, there must be some way of doing this such that a subclass of a class can have it's own delegate that's a sub-delegate of the superclass's delegate and for all of this to fit together nicely, but I just can't figure it out! Any ideas?
(* As a side issue, I don't understand why the compiler complains when PasswordTextField declares a "duplicate" ivar named delegate, but doesn't complain when TextField declares an ivar named delegate which is presumably a duplicate of UITextField's property called delegate!)
UITextField delegate ivar is named _delegate, not delegate. Hence why you get away with declaring it again in TextField, but not in PasswordTextField.
As for your delegate inheritance problem. I'm not sure ObjectiveC supports what you want.
You may just have to type your delegate 'id', instead of 'id<TextFieldDelegate>'. Then you could override setDelegate and ensure that the delegate passed in conformsToProtocol. However, you would lose your compile time checks here and only have the runtime check of conformsToProtocol
So, there! works.. and manages to have the compile-time warnings as well..
SimpleParent.h
#protocol Parentprotocol <NSObject>
#end
#interface SimpleParent : NSObject {
id<Parentprotocol> obj;
}
#property (retain) id<Parentprotocol> obj;
#end
SimpleParent.m
#import "SimpleParent.h"
#implementation SimpleParent
#synthesize obj;
#end
SimpleChild.h
#import <Foundation/Foundation.h>
#import "SimpleParent.h"
#protocol SimpleChildProtocol <Parentprotocol>
#end
#interface SimpleChild : NSObject
#property (assign) id<SimpleChildProtocol> obj;
#end
SimpleChild.m
#import "SimpleChild.h"
#implementation SimpleChild
#synthesize obj;
#end
It is a quite confusing question, so forgive me if I'm missing the point, but it seems like your three different inheritance levels each have different requirements from their delegate, ergo each delegate would have to conform to a different protocol, so would it be a solution to hold each level's delegate as a differently named ivar, and as a different reference?
For example, your base class would have its delegate, which you have decided will be assigned to the first inheriting subclass. This has it's own delegate, called level1delegate, and the next level down has another delegate, called level2delegate. You could of course set all three of these to the same object if that object conformed to all three protocols.
Basically, there's no rule that says a delegate has to be called "delegate", so don't tear yourself apart trying not to break it.

How to access variables of a ViewController in a subclass?

I guess this is basic, but I can't get my head around this.
I used to have only one ViewController in which all my variables were defined, e.g. an UITextView named myTextView. I also had methods in this ViewController for handling events that relate to myTextView, such as - ()hideKeyboard { // do something with myTextView or - (void)keyboardWillShow:(NSNotification *)notification { // do something with myTextView.
As my program became bigger and bigger, I thought about using subclasses, especially for other views. So I started a subclass, eg. mySubClass.h and mySubClass.m, in which I had another UITextView (for argument's sake myOtherTextView). In order to incorporate mySubClass, I #imported it into my ViewController and added a #class mySubClass; and could then produce instances of this class so as to use it in my App.
So far so good. As you can imagine, all the nice methods I defined in my ViewController for what should happen when an UITextView is edited (such as hiding keyboard etc.) didn't work for the UITextView in mySubClass.
It was then suggested to me that I should make another class in which I had all the keyboard events and subclass my ViewController and mySubView to it:
#interface ViewController : MyKeyboardEventsViewController
Now, the problem I am seeing is that I won't be able to access all the views, textviews, textfields etc. that I have created in my ViewController (e.g. myTextView which I mentioned earlier).
How can I achieve that all the variables that I have defined in my ViewController will also be available for MyKeyboardEventsViewController? Or is there another way to handle this?
Basically, I don't get how MyKeyboardEventsViewController will be able to access variables in my ViewController which it will need (e.g. the UITextView in question, or the accessoryView which will pop up etc. etc.).
Any suggestions would be very much welcome.
Example:
Class A contains a ivar UITextField textField
Class B subclasses Class A and thus it already contains ivar textField
Note: it's not the other way around. Class A does not "see" what ever is created in Class B.
When ever you subclass a class you give your new class the same ivars end methods of that subclassed class.
I hope this is what you were asking for.
EDIT
So for your example I would do the follwing:
Create a class "MyUIKeybordEventResponder"
Implement all the responder methods like - (BOOL)textFieldShouldReturn:(UITextField *)textField
Subclass your ViewController from "MyUIKeybordEventResponder"
Note method textFieldSHouldReturn has a parameter UITextField so it knows which textfield was pressed. So in a way it receives your textField from the subclass.
If I'm understanding this correctly, you have a UIViewController with MyKeyboardEventsViewController as an instance variable and you want to communicate between the two? If that is the case, one option would be to create a protocol.
#protocol MyKeyboardDelegate
- (void)closeAccessoryView;
#end
(Note - make whatever methods in the protocol that you need, this is simply an example)
In your MyKeyboardEventsViewController you then include the protocol file, and create an ivar
id <MyKeyboardDelegate> delegate;
Also make it a property and synthesize it.
Whatever class that is going to create the keyboardviewcontroller should delcare themselves as conforming to the protocol.
#interface MyViewController : UIViewController <MyKeyboardDelegate>
...
#end
When you create the MyKeyboardEventsViewController, set the delegate.
MyKeyboardEventsViewController *eventsVC = [[MyKeyboardEventsViewController alloc] init];
[eventsVC setDelegate:self];
Now just implement the delegate method and perform whatever action that is necessary.

Making a custom UISegmentControl(sort of)

I've got this mock up:
As you can see, it's a sort of navigation-menu. It's functionality should be the same as a segmented control, and i am going to change the tableView based on the item active.
What would be the easiest way to implement this?
I have started makin my UIView-subclass, but found out that i had to then make a delegate, watch for tap-events and stuff.
Is this the best way to do it? Should i subclass UISegmentedControl?
Any other advice?
Please, point me in the right direction. I feel confident in Obj-c, but making these kinds of stuff makes my mind goes crazy.
Conceptually, UISegmentedControl seems like a good choice for this, but I don't think it's quite flexible enough to create the effect you're going for here.
Have you considered putting three UIButton controls inside a custom view? You can customize the images for each button using setBackgroundImage:forState: to get the border style in your mockup. Set the selected property of the pressed button to YES, and UIButton will handle the drawing for you.
You can set up an action method to detect which button was pressed by calling
[button addTarget:self action:#selector(nameOfMethodToHandleButtonPress) forControlEvents:UIControlEventTouchUpInside])]
A delegate is just any class that conforms to a protocol you create. So you would create a delegate protocol in your header like this:
#class MyControl; // this is a forward reference to your class, as this must come before the class #interface definition in the header file
#protocol MyControlDelegate <NSObject>
#optional
- (void)myControl:(MyControl *)control didSelectButton:(int)buttonIndex; // replace this method with whatever makes sense for your control
#end
And the delegate is just a property in your MyControl class:
#property (nonatomic, assign) id <MyControlDelegate> delegate; // you use 'assign' instead of 'retain' to prevent retain cycles
And in your button press handlers, for example:
- (void)methodThatHandlesButtonPress { // this is the method you set up in the first code example with addTarget:action:forCotnrolEvents:
if ([self.delegate respondsToSelector:#selector(myControl:didSelectButton:)])
[self.delegate myControl:self didSelectButton:0]; // replace as appropriate
}
Now, you just have to have the view controller that contains your control adopt the protocol:
#interface MyViewController : UIViewController <MyControlDelegate> { // etc...
And implement the method:
- (void)myControl:(MyControl *)control didSelectButton:(int)buttonIndex {
// handle the button press as appropriate
}

iPhone: Switching Views From Outside Root Controller

I am using a UINavigationController to switch between views. What I would like is for each view to have the ability to control when it is swapped out for another view by having buttons within the view. All of the samples I've seen thus far have placed buttons on a toolbar, which is located on the root view containing the Switch View Controller rather than the views, them self. Is it possible to do what I want? I can't figure how to wire up the connection back to the UINavigationController.
I'm having a difficult time wording this, so please feel free to let me know if you need additional clarification.
Read about delegates. Delegates are a common method to signal stuff from objects to their "parents" or any other objects.
You should have a "delegate" property (can really be called anything, this is just a convention) on your child views. You can have buttons in your child views.
You declare the delegate like this:
interface ChildView : UIViewController {
id delegate;
}
#property (assign) id delegate;
implementation ChildView
#synthesize delegate;
Then, when you set up your child views inside your UINavigationController, you do:
ChildView *childView = [[ChildView alloc] init...]
childView.delegate = self;
Inside your child view, you have a button method:
- (IBAction) didPressButton:(id)sender {
[self.delegate didPressButtonToSwapView];
}
Inside your UINavigationController, you have a method:
- (void) didPressButtonToSwapView {
[self popViewController]; // use the right names, I made these up :)
[self pushAnotherViewController];
}
You should also read about protocols which would make the above code more robust and would help you make sure you only call the right methods on delegate, but I did not want to complicate this example.
EDIT: yes, the cleanest way to get rid of the warning is to use a protocol. Just put this in a separate .h file:
#protocol SwitchingDelegate
- (void) didPressButtonToSwapView;
#end
Include this .h in the UINavController header, and say the UINavController implements the protocol:
#interface MyNav: UINavController <SwitchingDelegate> { ...
Implement the method in the implementation (you don't need anything more in the interface).
In your ChildView, say that the delegate must implement the protocol: change all the declarations to:
id<SwitchingDelegate> delegate;
The compiler then helps you by checking whether the delegate objects really implement the protocol. You should not get any warnings when you have completed all of this correctly.