I am curious about conforming a class to UITextFieldDelegate, in the past I have always added it to enable access to methods defined within the protocol. However this last time I forgot to add it, only realising later that it was missing. My question is why does it work with or without, I thought it was needed to correctly access the protocol methods?
#interface MyController : UIViewController <UITextFieldDelegate> {
UITextField *text_001;
}
#property(nonatomic, retain) IBOutlet UITextField *text_001;
#end
OR:
#interface MyController : UIViewController {
UITextField *text_001;
}
#property(nonatomic, retain) IBOutlet UITextField *text_001;
#end
WITH:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
NSLog(#"Return: ... ");
[textField resignFirstResponder];
return YES;
}
Cheers Gary
Delegate declarations are really just there as compiler hints; obviously, you still have to implement the underlying methods. However, the main purpose is to let the compiler double check you when assigning them. If you try to manually (in code, as opposed to IB) assign a delegate which wasn't declared as such, you'll frequently get a compiler warning.
Since Objective-C uses duck-typing for most stuff (if it walks like a duck and quacks like a duck; if it responds to -textFieldShouldReturn:, etc), you're pretty safe.
Related
I am working in iPhone app with 5 screens. I want to refresh the values in the screen 4th in UITabBarController. I have added #protocol in AppDelegate but it is not calling. This is the first time am using #protocol could you please help me to solve this issue,
In AppDelegate.h
#protocol ReloadViewControllerDelegate <NSObject>
-(void) refreshViewController:(NSString *)result;
#end
id refreshViewControllerDelegate;
#property (nonatomic, retain) id refreshViewControllerDelegate;
and i have synthesized.
In AppDelegare.m
#synthesize refreshViewControllerDelegate;
if ([refreshViewControllerDelegate conformsToProtocol:#protocol(ReloadViewControllerDelegate)])
{
[refreshViewControllerDelegate performSelectorOnMainThread:#selector(refreshViewController:) withObject:#"YES" waitUntilDone:NO];
}// Control not come inside of if Condition.... From here i want to update the fourthViewController..
But control not go inside of the if condition. Could you please guide me where am doing wrong?
In my 4th ViewController.h
#import "AppDelegate"
#interface fourthViewController : UIViewController <ReloadViewControllerDelegate>
In my 4th ViewController.m
-(void) refreshViewController:(NSString *)result
{
NSLog(#"Result : %#", result);
}
Can anyone please help me to do this? Thanks in advance.
You need to declare your delegate like this:
#property (nonatomic, weak) IBOutlet id<ReloadViewControllerDelegate> delegate;
The id will work, but by using the <>, you can make sure that the delegate you assign is actually implementing the protocol, you might still have to make sure it responds to selector but that is only if some methods are declared as
#optional
make sure you synthesize it and most important make sure you set it, and it is not nil.
You're getting a warning because you are typing your delegate as an id. An id is a generic type, which means the compiler has no idea of what methods or properties might be available. In order to remove your warning, declare your delegate to be an NSObject:
#property (nonatomic, retain) NSObject <ReloadViewControllerDelegate> *refreshViewControllerDelegate;
By declaring as an NSObject, the compiler now knows about all the methods NSObject has, which will then allow you to call:
-performSelectorOnMainThread:withObject:waitUntilDone:
on your delegate without warnings. Good luck!
Try this:
#protocol ReloadViewControllerDelegate <NSObject>
-(void) refreshViewController:(NSString *)result;
#end
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (weak) id <ReloadViewControllerDelegate>refreshViewControllerDelegate;
#end
In AppDelegate.m
#implementation AppDelegate
#synthesize window, refreshViewControllerDelegate;
...
here Tab4ViewController is name of class.
if ([Tab4ViewController conformsToProtocol:#protocol(ReloadViewControllerDelegate)])
{
[refreshViewControllerDelegate performSelectorOnMainThread:#selector(refreshViewController:) withObject:#"YES" waitUntilDone:NO];
}
...
#end
#import "AppDelegate.h"
#interface Tab4ViewController<ReloadViewControllerDelegate>
...
#end
#implementation Tab4ViewController
...
appDelegate.refreshViewControllerDelegate = self;
...
#end
You are calling this code:
if ([refreshViewControllerDelegate conformsToProtocol:#protocol(ReloadViewControllerDelegate)])
But refreshViewControllerDelegate is this:
id refreshViewControllerDelegate;
conformsToProtocol checks to see if the object declares that it conforms to the protocol, which yours does not. If you want to specify conformity to a protocol you need to:
id<ReloadViewControllerDelegate> refreshViewControllerDelegate;
EDIT
OK, on the performSelectorOnMainThread problem... That method is provided in a category for NSThread, and is not declared in the NSObject protocol. So, if you want to call that, then you need to declare your type as NSObject, which conforms to your protocol.
NSObject<ReloadViewControllerDelegate> refreshViewControllerDelegate;
EDIT
OK, it looks like this is not a simple question about using a protocol, but a full tutorial. Since SO isn't the place for such, I'll try to give a brief one...
A protocol is an interface declaration.
#protocol ReloadChatViewControllerDelegate <NSObject>
- (void)refreshViewController:(NSString *)result;
#end
That says there is a new protocol in town, with the name ReloadChatViewControllerDelegate and it also conforms to the NSObject protocol. Any class that adopts the new protocol must provide an implementation of refreshViewController. You can make a protocol method optional, by putting in an #optional section.
#protocol ReloadChatViewControllerDelegate <NSObject>
- (void)refreshViewController:(NSString *)result;
#optional
- (void)optRefresh;
#end
Now, let's leave the adoption of the protocol for later. Say you are writing generic code, and you just want to know if the object you are given conforms to the protocol, and if so, invoke a method on it. Something like...
#interface Bar : NSObject
#property (nonatomic, weak) NSObject<ReloadChatViewControllerDelegate> *refreshViewControllerDelegate;
- (void)blarg;
#end
Now, the Bar class is providing a delegate property, so that it can be give some object that will help it do some work. However, that delegate object must at least be an NSObject, and conform to the ReloadChatViewControllerDelegate protocol.
Now, ObjC (and C) is quite permissive, so you can force an object to be any type you want, but then you deserve the crash you get. Now, when blarg is called, the delegate is notified to do some work.
Since the property type of the delegate already says it conforms to the given protocol, there is no need to check for conformity. We can just call the delegate method. Note that we must see if the object implements any optional protocol methods.
#implementation Bar
#synthesize refreshViewControllerDelegate = _refreshViewControllerDelegate;
- (void)blarg {
// Do something, then invoke the delegate
[self.refreshViewControllerDelegate
performSelectorOnMainThread:#selector(refreshViewController:)
withObject:#"YES"
waitUntilDone:NO];
if ([self.refreshViewControllerDelegate respondsToSelector:#selector(optRefresh)]) {
[self.refreshViewControllerDelegate optRefresh];
}
}
#end
However, if you want to be generic, and accept any object as a delegate (maybe you want to make it optional that the delegate conforms to some given protocol), then you can accept a plain id and then check to see it it conforms. In that case, you could declare your delegate as just an id (or some other type).
#property (nonatomic, weak) id refreshViewControllerDelegate;
Now, in your code, you need to check for conformity.
- (void)blarg {
// Do something, then invoke the delegate
if ([self.refreshViewControllerDelegate
conformsToProtocol:#protocol(ReloadChatViewControllerDelegate)]) {
[self.refreshViewControllerDelegate
performSelectorOnMainThread:#selector(refreshViewController:)
withObject:#"YES" waitUntilDone:NO];
if ([self.refreshViewControllerDelegate
respondsToSelector:#selector(optRefresh)]) {
[self.refreshViewControllerDelegate optRefresh];
}
}
}
OK, now you have a protocol defined, and you have code that calls methods on the protocol. Two caveats.
First, the delegate has to be set to an object. nil will respond false for any method, so it will of course not conform, nor do anything when sent any message.
Second, you have to make sure that your delegate declares conformity to the protocol. Just implementing the methods is not conformity. If a class does not explicitly specify that is conforms to a protocol, then conformsToProtocol will return false, even if it implements the methods of the protocol.
So, let's specify some class that will act as our delegate by conforming to the protocol.
#interface Foo : NSObject<ReloadChatViewControllerDelegate>
- (void)refreshViewController:(NSString *)result;
#end
#implementation Foo
- (void)refreshViewController:(NSString *)result {
NSLog(#"Look, ma, I'm refreshed with %#", result);
}
#end
It conforms to the protocol, provides an implementation for the mandatory method, and omits the optional one.
Now, if you ran this code, you should see that marvelous code in all its splendor.
Foo *foo = [[Foo alloc] init];
Bar *bar = [[Bar alloc] init];
bar.refreshViewControllerDelegate = foo;
[bar blarg];
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.
#interface TheViewController : UIViewController
{
IBOutlet UITableView *table;
}
#property (nonatomic,retain) IBOutlet UITableView *table;
or just like this:
#interface TheViewController : UIViewController
{
}
#property (nonatomic,retain) IBOutlet UITableView *table;
Is it ok like the second one?
And what is the difference ?
And which is recommended ?
Is it ok like the second one?
The two syntaxes are correct, generally speaking.
And what is the difference ?
The second one will also declare the ivar for you, but will only work correctly newer Objective C runtime systems.
And which is recommended ?
good question... I think they are pretty equivalent, provided you can restrict yourself to the newer ObjC runtime systems. For more hints at possible downsides of not declaring ivars explicitly, please have a look at this S.O. post.
In Objective-C 2.0, synthesized properties will automatically create the corresponding ivars as required. So both syntaxes are correct..This article will make it clear for you..
These two are not quite equivalent even in the ObjC 2.0 environment because of the IBOutlet. That has to be declared on the property. They'd be equivalent like this:
#interface TheViewController : UIViewController
{
IBOutlet UITableView *table;
}
#property (nonatomic,retain) UITableView *table;
#interface TheViewController : UIViewController
{
}
#property (nonatomic,retain) IBOutlet UITableView *table;
Notice the added IBOutlet in the property definition.
Generally they're equivalent in Objective-C 2.0 environment, but the debugger, for example, won't see the generated ivar as this object's member in the variables view and you'll have to ask for the value by using gdb's command line po command using the accessor method (not the short-form dot notation though).
I have a viewController (lets call it vcA) and this viewController has a NSArray property declared and synthesized.
NSArray *myProperty;
...
#property (nonatomic, retain) NSArray *myProperty;
and then synthesized on .m
this vcA is a delegate for another viewController, vcB.
Inside vcB I do:
NSArray *getMyPropertyFromDelegate = (NSArray *)[delegate myProperty];
and I receive an error saying warning: Semantic Issue: Instance method '-myProperty' not found (return type defaults to 'id')
I know I can silent this warning changing the line to
NSArray *getMyPropertyFromDelegate = (NSArray *)[(vca*)delegate myProperty];
and importing vcA.h, but I am trying to make vcB as independent as possible, because the delegate can change.
How do I do that working just with the delegate property?
thanks
I suggest you write a custom protocol.
Make vca view controller conforming to the protocol, and in vcB, declare the delegate property :
#property(retain) id <MyProtocol> delegate;
This means the delegate can be any type, as long as it conforms to MyProtocol.
Here is an example.
// MyProtocol.h
#protocol MyProtocol <NSObject>
#property(retain) NSArray *myProperty;
#end
// vca.h
#interface vca : XXXX <MyProtocol> {
....
}
#property(retain) NSArray *myProperty;
// vca.m
#synthesize myProperty; // or provide a getter
According to your comments to Vince's solution, I would say you need to learn a little about protocols as they are (almost?) always used with the concept of delegate.
You can start with http://iosdevelopertips.com/objective-c/the-basics-of-protocols-and-delegates.html
Nice simple code, rich in comments.
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProtocols.html for the official Apple documentation.
So I'm still very new to this whole objective C think and I ran into a problem I'm not sure the root cause for.
My h file looks basically like this :
#interface DrinkDetailViewController : UIViewController<UITextFieldDelegate>
{
UITextField* nameTextField;
UITextField* activeView;
}
#property (nonatomic,retain) IBOutlet UITextField* nameTextField;
In my m file i'm implementing the delegate function :
-(BOOL) textFieldShouldBeginEditing:(UITextField*) textField
{
activeView = textField;
return YES;
}
The thing is that if i'm declaring activeView to be a property as well (meaning adding property, synthesize and the all deal), then when i'm leaving the view (it's a navigation based project) my app crashes. However, if I live it as a non property everything seems to work fine. Why is that ???
because it's a property you need to call it this way:
self.activeView = textField;
That way the correct memory management rules will be applied and also the KVO notifications will be done for you.
are you synthesing activeView in your implementation file:
#synthesize activeView;