I understand how to make a class conform to several protocols, but where and how do I define a protocol that will be called by several classes, i.e.
_delegate.doStuff
could appear in several classes.
In xcode,
File-> New File-> Objective-c Protocol
#protocol myProtocolName
- (void) doStuff;
#end
then in classes you want to implement this protocol
...
#import "myProtocol.h"
#interface aClass <myProtocolName>
...
You can add this to any number of classes.
Just make a new protocol definition -- usually in a nicely #import'able .h file. In Xcode, this is under File, New, "Objective-C Protocol".
Here's a fun little example of two protocols, and some required and optional methods and properties. Note that properties on protocols must be synthesized in classes that conform to the protocol if the property is #required (#required is the default, so it can be left out if there is not #optional section).
// AnimalMinionType.h
#protocol AnimalMinionType <NSObject>
#required
#property (nonatomic, getter = isHerbivore) BOOL herbivore;
- (NSString *)genus;
- (NSString *)species;
- (NSString *)nickname;
- (void)doPet;
#optional
- (NSString *)subspecies;
#end
// IdiotType.h
#protocol IdiotType <NSObject>
#optional
- (void)pet:(id<AnimalMinionType>)pet didScratch:(BOOL)scratchy;
#end
// FluffyCat.h
#interface FluffyCat : NSObject <AnimalType>
#end
// FluffyCat.m
#implementation FluffyCat
#synthesize herbivore;
- (NSString *)genus { return #"felis"; }
- (NSString *)species { return #"catus"; }
- (NSString *)nickname { return #"damn cat"; }
- (void)doPet:(id<IdiotType>)anyoneOrAnything
{
NSLog(#"meow");
if ([anyoneOrAnything respondsToSelector:#selector(pet:didScratch:)])
[anyoneOrAnything pet:self didScratch:#YES];
}
#end
// Owner.h
#interface Owner : NSObject <IdiotType>
#property id<AnimalMinionType> housepet;
#end
// Owner.m
#implementation Owner
- (id)init
{
self = [super init];
if (self)
{
self.housepet = [FluffyCat new];
[self.housepet setHerbivore:#NO];
}
return self;
}
- (NSString *)ohACuteAnimalWhatKindIsIt
{
return [NSString stringWithFormat:#"%# %#",[self.housepet genus], [self.housepet species]];
}
- (void)haveALongDayAtWorkAndJustNeedAFriend
{
if (self.housepet) [self.housepet doPet:self];
}
- (void)pet:(id<AnimalMinionType>)pet didScratch:(BOOL)scratchy
{
if ((scratchy) && (pet == self.housepet))
{
NSLog(#"I HATE THAT %#", [[self.housepet nickname] uppercaseString]);
self.housepet = nil;
}
}
#end
I hope that helps. :-)
Related
I've been following this example to help me build a delegate but unfortunately I've missed something so it is not working for me. How do I set up a simple delegate to communicate between two view controllers?
My code looks like this:
// HintsViewController.h
#import <UIKit/UIKit.h>
#protocol HintDelegateProtocol;
#interface HintsViewController : UIViewController
#property (weak, nonatomic) id<HintDelegateProtocol> hintDelegate;
-(IBAction)showFirstLetter:(id)sender
-(IBAction)showHint:(id)sender;
-(IBAction)showAnswer:(id)sender;
#end
#protocol HintDelegateProtocol <NSObject>
-(void)HintsViewController:(HintsViewController*)hintsViewController
showFirstLetter:(NSString*)firstLetter;
-(void)HintsViewController:(HintsViewController*)hintsViewController
showHint:(NSString*)hint;
-(void)HintsViewController:(HintsViewController*)hintsViewController
showAnswer:(NSString*)answer;
#end
//
// HintsViewController.m
#import "HintsViewController.h"
#implementation HintsViewController
#pragma mark -
#pragma mark IBActions
/* As per a suggestion below I changed the code here /*
- (IBAction)showHint:(id)sender
{
[self.hintDelegate HintsViewController:self showHint:#"Hint"];
}
- (IBAction)showFirstLetter:(id)sender
{
[self.hintDelegate HintsViewController:self showFirstLetter:#"FirstLetter"];
}
- (IBAction)showAnswer:(id)sender
{
[self.hintDelegate HintsViewController:self showAnswer:#"Answer"];
}
#end
And then in the a Controller class I have the following:
//
// GameLogicController.h
#import "HintsViewController.h"
#interface GameLogicController : NSObject < HintDelegateProtocol>
#end
And in the implementation I have the following:
// GameLogicController.m
-(void) nextRiddle
{
HintsViewController *hintsViewController = [[HintsViewController alloc] init];
hintsViewController.hintDelegate = self;
}
#pragma mark -
#pragma mark HintsFunctionality
-(void)HintsViewController:(HintsViewController*)hintsViewController
showFirstLetter:(NSString*)firstLetter
{
NSLog(#"Show First Letter called");
}
-(void)HintsViewController:(HintsViewController*)hintsViewController
showHint:(NSString*)hint
{
NSLog(#"show Hint called");
}
-(void)HintsViewController:(HintsViewController*)hintsViewController
showAnswer:(NSString*)answer
{
NSLog(#"Show answer called");
}
Using breakpoints I can see that the IBActions in the HintsViewController are being called, but putting a breakpoint in any of the delegate methods in the gameLogicController are never hit. So I have missed an important step in setting up the connection between the GameLogicController and the HintsViewController. Can anyone help me spot it?
Say you have two files: one is your ViewController, and other is your ConnectionManager Class.
Declare protocol and its methods in your ConnectionManager class, and define your protocol methods in the ViewController class. By setting the delegate of your ConnectionManager class in ViewController Class, you can call your Protocol method.
#protocol ConnManagerDelegate<NSObject>
- (void)didReceiveData:(NSDictionary *)data;
- (void)didFailWithError:(NSError*)error;
#end
#interface ConnectionManager : NSObject<NSURLConnectionDelegate>
#property(nonatomic,assign)id< ConnManagerDelegate > delegate;
And elseswhere in the same file .m, when your response comes just call
[Self.delegate didReceiveData:mDict];
In the ViewController file after you alloc init ConnectionManager class, set its delegate to self and define the protocol methods. It is these methods you will have your response from ConnectionManager class.
This is all Protocol Delegation pattern
I have class A, B and C with 2 methods in all 3 classes.
class A
- (void)onSuccess {
}
- (void)onFailure {
}
Then one CommonClass is there in which I’ll be doing some task. If class A is presenting CommonClass and after performing all the tasks I have to call either onSuccess() or onFailure() implemented in class A.
Which is the best way to do this, and how? In Java it's done by extend or abstract I guess.
You can create a protocol class like this. This has only a .h file
#protocol RequestProtocolDelegate <NSObject>
#optional
- (void)onSuccess;
- (void)onFailure;
#end
and to use it in your class like this
file .h
#include "RequestProtocolDelegate.h"
#interface CommonClass : NSObject <RequestProtocolDelegate> {
}
#end
file .m
- (void)onSuccess {
}
- (void)onFailure {
}
Now you can use in your CommonClass this protocol
If I understood you correctly then it should be done with delegation. For exam:
//CommonClass.h
#protocol CommonDelegate <NSObject>
// list protocol methods...
- (void)onSuccess;
- (void)onFailure;
#optional
#interface CommonClass : NSObject
#property (nonatomic, strong) id delegate;
-(void)Task;
#end
//CommonClass.m
#import "CommonClass.h"
#synthesize delegate;
-(void)Task
{
if(do smth task){
[delegate onSuccess];
}
else{
[delegate onFailure]
}
}
// ClassA.h
#import "CommonClass.h"
#interface ClassA : NSObject <CommonClassDelegate>
#end
// ClassA.m
-(void)init
{
CommonClass *common = [[CommonClass alloc] init];
common.delegate = self;
[common Task];
}
- (void)onSuccess
{
// do smth
}
- (void)onFailure
{
// do smth
}
... Do the same for class B and C
I have a protocol in one class:
#protocol DataStorageManager
- (void) saveFile;
#end
#interface DataManager : NSObject
{
id <DataStorageManager> delegate;
}
#property (nonatomic, assign) id<DataStorageManager> delegate;
//methods
#end
and its implementation:
#implementation DataManager
#synthesize delegate;
#end
and I have another class which is the adapter between the first and the third one:
#import "DataManager.h"
#import "DataPlistManager.h"
#interface DataAdapter : NSObject <DataStorageManager>
#property (nonatomic,strong) DataPlistManager *plistManager;
- (void) saveFile;
#end
and its implementation
#import "DataAdapter.h"
#implementation DataAdapter
-(id) initWithDataPlistManager:(DataPlistManager *) manager
{
self = [super init];
self.plistManager = manager;
return self;
}
- (void) saveFile
{
[self.plistManager savePlist];
}
#end
So when I in first method try to call my delegate method like this
[delegate saveFile];
Nothing happened. I don't understand what's wrong with the realization - it's a simple adapter pattern realization. So I need to use the delegate which will call the methods from the third class. Any help?
You are not setting the delegate property. You need to do this,
-(id) initWithDataPlistManager:(DataPlistManager *) manager
{
self = [super init];
self.plistManager = manager;
self.plistManager.delegate = self;
return self;
}
Also, in DataManager class remove the ivar declaration, just declaring property is sufficient, the ivar gets automatically created. Call the delegate method as below,
if([self.delegate respondsToSelector:#selector(saveFile)] {
[self.delegate saveFile];
}
Hope that helps!
In your case you forget to set your protocol delegate and also need to call protocol method
by self.delegate....
I just Give Basic Idea for how to Create Protocol
Also Read This Question
#DetailViewController.h
#import <UIKit/UIKit.h>
#protocol MasterDelegate <NSObject>
-(void) getButtonTitile:(NSString *)btnTitle;
#end
#interface DetailViewController : MasterViewController
#property (nonatomic, assign) id<MasterDelegate> customDelegate;
#DetailViewController.m
if([self.customDelegate respondsToSelector:#selector(getButtonTitile:)])
{
[self.customDelegate getButtonTitile:button.currentTitle];
}
#MasterViewController.m
create obj of DetailViewController
DetailViewController *obj = [[DetailViewController alloc] init];
obj.customDelegate = self;
[self.navigationController pushViewController:reportTypeVC animated:YES];
and add delegate method in MasterViewController.m for get button title.
#pragma mark -
#pragma mark - Custom Delegate Method
-(void) getButtonTitile:(NSString *)btnTitle;
{
NSLog(#"%#", btnTitle);
}
can't understand what's wrong in this case, so I cant use the delegate - there is an exception in self.plistManager.delegate = self; Property 'delegate' not found on object of type 'DataPlistManager *'
#import "DataManager.h"
#import "DataPlistManager.h"
#interface DataAdapter : NSObject <DataStorageManager>
#property (nonatomic,strong) DataPlistManager *plistManager;
- (void) saveFile;
#end
and its implementation
#import "DataAdapter.h"
#implementation DataAdapter
-(id) initWithDataPlistManager:(DataPlistManager *) manager
{
self = [super init];
self.plistManager = manager;
self.plistManager.delegate = self;
return self;
}
- (void) saveFile
{
[self.plistManager savePlist];
}
#end
Your DataPlistManager needs a property delegate:
#property (weak) id<DataStorageManager> delegate;
If you add #import "DataAdapter.h" in your "DataPlistManager.h" file then remove it and add it to "DataPlistManager.m" file, I don't know but some days ago i have same issue, and i solved it by using this trick :)
DataManager class contains delegate property so you should set your object as delegate of DataManager class and call method (send message) saveFile inside delegate class:
#implementation DataAdapter
- (void)someMethod) {
DataManager *dataManagerObject = [[DataManager alloc] init];
dataManagerObject.delegate = self;
}
#implementation DataManager
- (void)someDelegateMethod {
[self.delegate saveFile];
}
Are you sure you understand concept of delegation pattern?
https://developer.apple.com/library/ios/documentation/general/conceptual/CocoaEncyclopedia/DelegatesandDataSources/DelegatesandDataSources.html
I want to override an NSString property declared in a superclass. When I try to do it using the default ivar, which uses the the same name as the property but with an underscore, it's not recognised as a variable name. It looks something like this...
The interface of the superclass(I don't implement the getter or setter in this class):
//Animal.h
#interface Animal : NSObject
#property (strong, nonatomic) NSString *species;
#end
The implementation in the subclass:
//Human.m
#implementation
- (NSString *)species
{
//This is what I want to work but it doesn't and I don't know why
if(!_species) _species = #"Homo sapiens";
return _species;
}
#end
Only the superclass has access to the ivar _species. Your subclass should look like this:
- (NSString *)species {
NSString *value = [super species];
if (!value) {
self.species = #"Homo sapiens";
}
return [super species];
}
That sets the value to a default if it isn't currently set at all. Another option would be:
- (NSString *)species {
NSString *result = [super species];
if (!result) {
result = #"Home sapiens";
}
return result;
}
This doesn't update the value if there is no value. It simply returns a default as needed.
to access the superclass variables, they must be marked as #protected, access to such variables will be only inside the class and its heirs
#interface ObjectA : NSObject
{
#protected NSObject *_myProperty;
}
#property (nonatomic, strong, readonly) NSObject *myProperty;
#end
#interface ObjectB : ObjectA
#end
#implementation ObjectA
#synthesize myProperty = _myProperty;
#end
#implementation ObjectB
- (id)init
{
self = [super init];
if (self){
_myProperty = [NSObject new];
}
return self;
}
#end