I'm trying to make my own version of UITableViewController in a UIViewController (for more customization). So in my superclass, I'm implementing both the delegate and datasource and setting the UITableView object delegate and datasource properties to "this". Only problem is I get a compiler warning complaining that I haven't implemented the mandatory dataSource and delegate methods. I'd like to be able to implement these methods when I subclass my custom UITableViewController.
Is there a neat way to make these warnings go away, or is the only way for me to put empty versions of the mandatory delegate methods, and then override them in the subclass? Is this bad practice? Anyone have any insight on how Apple accomplishes this with there UITableViewController class?
I use this pattern for “abstract” methods:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
[self doesNotRecognizeSelector:_cmd];
abort();
}
The _cmd variable is the selector of the current method. It's automatically provided, just like self.
You have to call abort() because the compiler knows that abort() doesn't return, but it doesn't know that about doesNotRecognizeSelector:.
At least in iOS 5, the UITableViewController methods aren't empty, because UITableViewController supports loading predefined (static) rows from a storyboard.
Related
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.
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.
I need to set my root UIViewController as the delegate for one of its modal child UIViewControllers (runwayAnalysisViewController). I implemented a delegate protocol which my root UIViewController adopts.
[runwayAnalysisViewController setSettingsDelegate: self];
(self being the parent UIViewController)
Unfortunately, I am receiving the classic error, "runwayAnalysisViewController may not respond to "-setSettingsDelegate: method."
the delegate is declared as such in the RunwayAnalysisViewController class:
id <SettingsRequestDelegate> settingsDelegate;
-thence:
#property(nonatomic, assign) id <SettingsRequestDelegate> settingsDelegate;
it is synthesized in the .m file as well.
I have tried synthesizing the accessor & mutator methods for the delegate as well as manually writing the same but to no avail.
(other attempt, methods declared in interface and implemented as shown:)
-(void)setSettingsDelegate:(id)aDelegate {
settingsDelegate = aDelegate;
}
-(id)settingsDelegate {
return settingsDelegate;
}
Strangely enough, while this warning persists, I implemented the single method of this delegate as follows:
#pragma mark - SettingsRequestDelegate Methods
-(void)userDidRequestSettingsAccess:(id)sender {
NSLog(#"User did request settings access");
}
I am able to get a successful message sent from the delegate to the parent UIViewController! Any help would be appreciated.
Are you importing your child controller's *.h file at the beginning of the *.m file of the parent view controller?
(and is the #property line you mention contained in that *.h file?)
You need to declare that your root UIViewController conforms to SettingsRequestDelegate in its header file. So where you currently may have:
#interface RootViewController: UIViewController
You'll instead want:
#interface RootViewController: UIViewController <SettingsRequestDelegate>
It's just a warning because in Objective-C all method call dispatches are resolved dynamically and which methods an object responds to can be changed at runtime (albeit not in a very syntactically pretty way). So even though the compiler thinks at compile time that you've probably made a mistake, it isn't really in a position to be certain.
All you're doing with formal protocols is trying to give the compiler something useful to go on for giving you helpful warnings. They weren't in early versions of Objective-C at all and some informal protocols (ie, the delegate has to have certain methods but you document them only in the API documentation — the compiler is completely out of the loop) survived even into early versions of iOS.
I made a custom UITableView subclass and implemented this:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// scrolled...
}
Now, what I think is that UITableView may also love to get this message for some obvious reasons. However, when I don't forward that to super, for some reason, everything still works fine. Must I forward that guy to super? I mean...it's a delegate method implementation, but as far as I'm aware of, this would still override anything implemented in UITableView, or not?
Edit: I see...the delegate could be anyone. Never mind about this. BUT: What I have such a thing in a superclass, and make a subclass. How would I even know that the superclass does implement that method and I must forward it to super?
Short answer: no.
Those methods are defined in the UIScrollViewDelegate Protocol.
They are meant to be implemented in a delegate, which maybe only has NSObject as parent.
It does not override anything, as it's a delegate method.
The UIScrollView just does it's stuff, and calls the delegate method if a delegate is set.
This is a delegate method which means it gets called by your instance of UITableView for your convenience.
The scrolling happens and the UITableView internal code will call.
if ([delegate respondsTo:#selector(scrollViewDidScroll:)]) {
[delegate performSelector:#selector(scrollViewDidScroll:) withObject:[self scrollView]];
}
And so you use this method to implement additional functionality, for example activating a control when the tableView has scrolled a certain amount.
Hope this helps!
for example we use this method in the tableview
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 16;
}
i want to learn we don't call this method in anywhere but application reads this value how is it being? there are a lot of methods like this we did not call.
Your object has been set as the data source of the UITableView somewhere. Most likely, by making a connection in InterfaceBuilder, though it is straightforward to do so in code by setting the dataSource property of the UITableView:
- (void) setUpMyJunkMan
{
myTableView.dataSource = self;
}
Once you have set your object as the data source, the table view will invoke the method as needed to determine what it needs to draw or how it needs to respond to events.
Your object is required to implement the UITableViewDataSource protocol (though, if you connected the data source via InterfaceBuilder, there may not be a complaint if you don't -- it is more of a compile time validation than a runtime one).
If you look at the declaration of UITableViewDataSource, you'll see that a number of methods are #optional. The rest are #required; you must implement them to fulfill the contract of the protocol.
This is the key difference between data sources and delegates. Delegates can optionally implement any of the declared methods. Data sources create a much more formal relationship between the two objects wherein some of the methods must be implemented.
An easy way see why a method is being called - set a breakpoint, run in debug mode, and then look at the stack trace.
For this particular case - It's being called automatically by the framework when it renders the table view.
I think you really need to take a look at The Table View Programming Guide so that you have a good understanding of what methods you need to override (and not override) when using Table Views. If you are extending the TableViewController class the framework does a lot of the heavy lifting and you barely have to write any code.
numberOfSectionsInTableView: is being called by the table view.
You implement numberOfSectionsInTableView: as part of the UITableViewDataSource protocol. Each UITableView is given a dataSource. Normally, UITableView will be constructed by a UITableViewController which will set itself as the view's dataSource.
When the view is shown, it calls numberOfSectionsInTableView: on its dataSource.
This is explained in the Table View Programming Guide for iPhone OS.
This is part of a Delegate Interface.
At some point in your application (possibly in your UIBuilder) you have specified that the object that contains the method is actually the delegated object. This means that when you want to adjust the behaviour (in this case of a UITableView) you can without actually extending UITableView but mearly changing the delegate methods.
basically the UITableView class will look somehting like this.
- (void) AMethodinUiTableView
{
int colums =[self.delegate numberOfSectionsInTableView:self];
}
for more info i would check out delgate programing and selectors.