Simple iOS delegate/callback - ios

I have a simple ViewController. In the .m file I put
#import "Manager.h"
There is a button and when it is clicked the following code is executed:
Manager* manager = [[Manager alloc] init];
NSString* str = [manager doit];
NSLog(#"str = %#", str);
Manager is a subclass of NSObject.
In Manager.m I have this method:
- (NSString*)doit{
return #"did it";
}
Great. All this works as expected.
What I need is, if possible and if a good practice, to send/make Manager to understand, that from the method doit
another method in ViewController should be called. Some kind of callback/delegate. How do I accomplish this?
When I call
[manager doit];
I also want to inform that a method in ViewController should be executed.
I hope you understand what I mean otherwise I can write some more details. Thanks

Yes you could use delegate, Your implementation of the delegate in the Manager object should look like so:
#protocol managerDelegate <NSObject>
-(void)doSomthingAndGetThisString: (NSString *)stringText;
#end
#interface Manager : NSObject
#property (nonatomic,strong) id <managerDelegate>delegate;
#end
As you can see, the Manager object claims his delegate protocol in the header interface, So any class could sign on it, And if they do, they should preform the method "doSomthingAndGetThisString".
Whenever "Manager" object chooses to fire the delegate methods he will call it like so:
- (NSString*)doit{
//Call my delegate:
[self.delegate doSomthingAndGetThisString:#"Passing this stringt to my delegate"];
return #"did it";
}
ViewController:
ViewController needs to keep a property of the manager object:
#property (nonatomic,strong) Manager *myManager;
And Now when you allocate "myObject", ViewController should "sign" to preform the Delegate like so:
_myManager = [Manager new];
_myManager.delegate = self;
And of course have the method:
-(void)doSomthingAndGetThisString: (NSString *)stringText;
That will call whenever "Manager" object firs it.
Hope this helps

Related

In Objective C, can class A be a delegate to class B, while class B is being a delegate to class A?

EDITED TO INCLUDE CODE.
Is it possible in Objective C, to have class A be a delegate to class B, while class B is being a delegate to class A?
I have the first delegate (call it A to B) working fine. I then implement it the other way around and it can’t find the delegate method, with the classic warning:
Method 'audioCueHasMovedDelegateMethod' in protocol 'SoundpaperViewControllerDelegate' not implemented.
Before I take the time to upload the code, please let me know if this is possible and I’m just doing something wrong, or if it can’t work in the first place and I need to use another technique such as NSNotification. I’ve done my Googling but can’t find this issued addressed.
If this is legal in theory then I'll upload my code.
Thank you.
Is it possible, in Objective C, to have method A be delegate to method B, while method B is being a delate to method A?
I have the first delegate (call it A to B) working fine. I then implement it the other way around and it can’t find the delegate method, with the classic warning:
Method 'audioCueHasMovedDelegateMethod' in protocol 'SoundpaperViewControllerDelegate' not implemented.
Before I take the time to upload the code, please let me know if this is possible and I’m just doing something wrong, or if it can’t work in the first place and I need to use another technique such as NSNotification. I’ve done my Googling but can’t find this issued addressed.
Thank you.
THIS IS CLASS A:
Class A AudioOperations, this calls a method in Class B, SoundpaperViewController, called setupAudioPlayerControls. This is because the view controller is what talks to the screen (using Storyboards). While I want to separate the audio player into a separate class and separate files for cleanliness.
This works just fine
AudioOperations.h
. . .
#class AudioOperations;
#class SoundPaperViewController;
#protocol AudioOperationsDelegate <NSObject>
- (void) setupAudioPlayerControls; // THIS is called on Class B and works fine
#end
#interface AudioOperations : NSObject
#property (nonatomic, weak) IBOutlet id <AudioOperationsDelegate> delegate;
. . .
#end
Simplified AudioOperations.mm
#interface AudioOperations () <AVAudioPlayerDelegate>
#end
- (void) audioPlayback // simplified to show what is important
{
NSLog(#"Entering audioPlayback");
self.audioPlayer.delegate = self;
NSLog(#"calling setupaudioplayercontrols from audioPlayback");
[self.delegate setupAudioPlayerControls]; // delegated to soundpaperviewcontroller and works just fine
NSLog(#"Exiting audioPlayback");
}
. . . (various other code)
- (void) audioCueHasMovedDelegateMethod // THIS IS THE method that should be called from Class B but can’t be found (where the warning comes from)
{
// User has released the cue while inside the control - update the player…
NSLog(#"in delegate audioCueHasMoved");
[self.audioPlayer setCurrentTime: self.delegate.audioCueSlider.value];
if (self.audioPlayer.isPlaying == NO)
{
[self.audioPlayer play];
}
// … and go back to updating the control.
self.audioTimer = [NSTimer scheduledTimerWithTimeInterval: 0.1
target: self
selector: #selector(updateAudioTime:)
userInfo: nil
repeats: YES];
}
THIS IS CLASS B (again simplified)
SoundpaperViewController.h
. . .
#class LabelProcessor;
#class AudioOperations;
#class SpotterGraphicsView;
#protocol SoundpaperViewControllerDelegate <NSObject>
- (void) audioCueHasMovedDelegateMethod; // this is the method that should be called but isn’t found
#end
#interface SoundPaperViewController : UIViewController<QLPreviewControllerDataSource, QLPreviewControllerDelegate>
#property (nonatomic, weak) IBOutlet id <SoundpaperViewControllerDelegate> delegate;
. . .
#end
SoundpaperViewController.mm
. . . (bunch of #imports etc)
#interface SoundPaperViewController () <AVCaptureVideoDataOutputSampleBufferDelegate
,AVCaptureMetadataOutputObjectsDelegate
,LabelProcessorDelegate
,AudioOperationsDelegate
,SettingsObserver
,CEGuideArrowDelegate
,SoundpaperViewControllerDelegate // NOT SURE THIS IS RIGHT, but I’ve tried it with and without it
>
. . . (bunch of #properties, etc.)
#implementation SoundPaperViewController // WARNING IS HERE that the method audioCueHasMovedDelegateMethod can’t be found
- (id) initWithCoder: (NSCoder*) inDecoder
{
if ((self = [super initWithCoder: inDecoder]) != nil)
{
NSLog(#"new latestImageCond created NEW");
self.latestImageCondition = [NSCondition new];
NSLog(#"initWithCoder spvc thread: %#", [NSThread currentThread]);
}
self.delegate = self; // NOTE this
return self;
}
// This is the delegate method called from CLASS A (AudioOperations) and works just fine:
- (void) setupAudioPlayerControls
{
NSLog(#"setupAudioPlayerControls");
// hide the playbutton
[self.playButton setEnabled:NO];
[self.playButton setTintColor: [UIColor clearColor]]; // hides it
. . . etc.
}
As near as I can tell I’ve done everything identically in both classes (with the one exception that I’m not sure of whether to use this SoundpaperViewControllerDelegate in the interface.
Thank you for working through this mess of code. I’m sure I’m missing something obvious!
Yes, this can be done. Be sure each one has a weak reference to the other so that you don't end up with a retain cycle.
With the help of a friend I was able to get this to work. For those who might have a similar problem, it was a matter of getting the .h files set up correctly:
In the SoundpaperViewController.h:
#class LabelProcessor;
#class AudioOperations;
#class SoundPaperViewController;
#interface SoundPaperViewController : UIViewController < QLPreviewControllerDataSource, QLPreviewControllerDelegate> // note no audioOperationsDelegate in this line
- (void) setupAudioPlayerControls;
#property (nonatomic, strong) AudioOperations * SPVdelegate;
In the AudioOperations Class:
#class AudioOperations;
#class SoundPaperViewController;
#interface AudioOperations : NSObject // note no SoundpaperViewControllerDelegate here
#property (nonatomic, weak) SoundPaperViewController * audioDelegate;
- (void) audioCueHasMovedDelegateMethod;
And in the Soundpaper class .m file:
_myAudio = [[AudioOperations alloc] init];
_myAudio.audioDelegate = self;
self.SPVdelegate = _myAudio;
It was enlightening to me that I didn't need to include the delegate in the #interface (for instance #interface SoundpaperViewController ) Getting rid of that and simply declaring the #property was all that was needed.

Can I create my own delegate in iOS [duplicate]

I know how delegates work, and I know how I can use them.
But how do I create them?
An Objective-C delegate is an object that has been assigned to the delegate property another object. To create one, you define a class that implements the delegate methods you're interested in, and mark that class as implementing the delegate protocol.
For example, suppose you have a UIWebView. If you'd like to implement its delegate's webViewDidStartLoad: method, you could create a class like this:
#interface MyClass<UIWebViewDelegate>
// ...
#end
#implementation MyClass
- (void)webViewDidStartLoad:(UIWebView *)webView {
// ...
}
#end
Then you could create an instance of MyClass and assign it as the web view's delegate:
MyClass *instanceOfMyClass = [[MyClass alloc] init];
myWebView.delegate = instanceOfMyClass;
On the UIWebView side, it probably has code similar to this to see if the delegate responds to the webViewDidStartLoad: message using respondsToSelector: and send it if appropriate.
if([self.delegate respondsToSelector:#selector(webViewDidStartLoad:)]) {
[self.delegate webViewDidStartLoad:self];
}
The delegate property itself is typically declared weak (in ARC) or assign (pre-ARC) to avoid retain loops, since the delegate of an object often holds a strong reference to that object. (For example, a view controller is often the delegate of a view it contains.)
Making Delegates for Your Classes
To define your own delegates, you'll have to declare their methods somewhere, as discussed in the Apple Docs on protocols. You usually declare a formal protocol. The declaration, paraphrased from UIWebView.h, would look like this:
#protocol UIWebViewDelegate <NSObject>
#optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ... other methods here
#end
This is analogous to an interface or abstract base class, as it creates a special type for your delegate, UIWebViewDelegate in this case. Delegate implementors would have to adopt this protocol:
#interface MyClass <UIWebViewDelegate>
// ...
#end
And then implement the methods in the protocol. For methods declared in the protocol as #optional (like most delegate methods), you need to check with -respondsToSelector: before calling a particular method on it.
Naming
Delegate methods are typically named starting with the delegating class name, and take the delegating object as the first parameter. They also often use a will-, should-, or did- form. So, webViewDidStartLoad: (first parameter is the web view) rather than loadStarted (taking no parameters) for example.
Speed Optimizations
Instead of checking whether a delegate responds to a selector every time we want to message it, you can cache that information when delegates are set. One very clean way to do this is to use a bitfield, as follows:
#protocol SomethingDelegate <NSObject>
#optional
- (void)something:(id)something didFinishLoadingItem:(id)item;
- (void)something:(id)something didFailWithError:(NSError *)error;
#end
#interface Something : NSObject
#property (nonatomic, weak) id <SomethingDelegate> delegate;
#end
#implementation Something {
struct {
unsigned int didFinishLoadingItem:1;
unsigned int didFailWithError:1;
} delegateRespondsTo;
}
#synthesize delegate;
- (void)setDelegate:(id <SomethingDelegate>)aDelegate {
if (delegate != aDelegate) {
delegate = aDelegate;
delegateRespondsTo.didFinishLoadingItem = [delegate respondsToSelector:#selector(something:didFinishLoadingItem:)];
delegateRespondsTo.didFailWithError = [delegate respondsToSelector:#selector(something:didFailWithError:)];
}
}
#end
Then, in the body, we can check that our delegate handles messages by accessing our delegateRespondsTo struct, rather than by sending -respondsToSelector: over and over again.
Informal Delegates
Before protocols existed, it was common to use a category on NSObject to declare the methods a delegate could implement. For example, CALayer still does this:
#interface NSObject(CALayerDelegate)
- (void)displayLayer:(CALayer *)layer;
// ... other methods here
#end
This tells the compiler that any object might implement displayLayer:.
You would then use the same -respondsToSelector: approach as described above to call this method. Delegates implement this method and assign the delegate property, and that's it (there's no declaring you conform to a protocol). This method is common in Apple's libraries, but new code should use the more modern protocol approach above, since this approach pollutes NSObject (which makes autocomplete less useful) and makes it hard for the compiler to warn you about typos and similar errors.
The approved answer is great, but if you're looking for a 1 minute answer try this:
MyClass.h file should look like this (add delegate lines with comments!)
#import <BlaClass/BlaClass.h>
#class MyClass; //define class, so protocol can see MyClass
#protocol MyClassDelegate <NSObject> //define delegate protocol
- (void) myClassDelegateMethod: (MyClass *) sender; //define delegate method to be implemented within another class
#end //end protocol
#interface MyClass : NSObject {
}
#property (nonatomic, weak) id <MyClassDelegate> delegate; //define MyClassDelegate as delegate
#end
MyClass.m file should look like this
#import "MyClass.h"
#implementation MyClass
#synthesize delegate; //synthesise MyClassDelegate delegate
- (void) myMethodToDoStuff {
[self.delegate myClassDelegateMethod:self]; //this will call the method implemented in your other class
}
#end
To use your delegate in another class (UIViewController called MyVC in this case) MyVC.h:
#import "MyClass.h"
#interface MyVC:UIViewController <MyClassDelegate> { //make it a delegate for MyClassDelegate
}
MyVC.m:
myClass.delegate = self; //set its delegate to self somewhere
Implement delegate method
- (void) myClassDelegateMethod: (MyClass *) sender {
NSLog(#"Delegates are great!");
}
When using the formal protocol method for creating delegate support, I've found that you can ensure proper type checking (albeit, runtime, not compile time) by adding something like:
if (![delegate conformsToProtocol:#protocol(MyDelegate)]) {
[NSException raise:#"MyDelegate Exception"
format:#"Parameter does not conform to MyDelegate protocol at line %d", (int)__LINE__];
}
in your delegate accessor (setDelegate) code. This helps minimize mistakes.
Maybe this is more along the lines of what you are missing:
If you are coming from a C++ like viewpoint, delegates takes a little getting used to - but basically 'they just work'.
The way it works is that you set some object that you wrote as the delegate to NSWindow, but your object only has implementations (methods) for one or a few of the many possible delegate methods. So something happens, and NSWindow wants to call your object - it just uses Objective-c's respondsToSelector method to determine if your object wants that method called, and then calls it. This is how objective-c works - methods are looked up on demand.
It is totally trivial to do this with your own objects, there is nothing special going on, you could for instance have an NSArray of 27 objects, all different kinds of objects, only 18 some of them having the method -(void)setToBue; The other 9 don't. So to call setToBlue on all of 18 that need it done, something like this:
for (id anObject in myArray)
{
if ([anObject respondsToSelector:#selector(#"setToBlue")])
[anObject setToBlue];
}
The other thing about delegates is that they are not retained, so you always have to set the delegate to nil in your MyClass dealloc method.
Please! check below simple step by step tutorial to understand how Delegates works in iOS.
Delegate in iOS
I have created two ViewControllers (for sending data from one to another)
FirstViewController implement delegate (which provides data).
SecondViewController declare the delegate (which will receive data).
As a good practice recommended by Apple, it's good for the delegate (which is a protocol, by definition), to conform to NSObject protocol.
#protocol MyDelegate <NSObject>
...
#end
& to create optional methods within your delegate (i.e. methods which need not necessarily be implemented), you can use the #optional annotation like this :
#protocol MyDelegate <NSObject>
...
...
// Declaration for Methods that 'must' be implemented'
...
...
#optional
...
// Declaration for Methods that 'need not necessarily' be implemented by the class conforming to your delegate
...
#end
So when using methods that you have specified as optional, you need to (in your class) check with respondsToSelector if the view (that is conforming to your delegate) has actually implemented your optional method(s) or not.
I think all these answers make a lot of sense once you understand delegates. Personally I came from the land of C/C++ and before that procedural languages like Fortran etc so here is my 2 min take on finding similar analogues in C++ paradigm.
If I were to explain delegates to a C++/Java programmer I would say
What are delegates ?
These are static pointers to classes within another class. Once you assign a pointer, you can call functions/methods in that class. Hence some functions of your class are "delegated" (In C++ world - pointer to by a class object pointer) to another class.
What are protocols ?
Conceptually it serves as similar purpose as to the header file of the class you are assigning as a delegate class. A protocol is a explicit way of defining what methods needs to be implemented in the class who's pointer was set as a delegate within a class.
How can I do something similar in C++?
If you tried to do this in C++, you would by defining pointers to classes (objects) in the class definition and then wiring them up to other classes that will provide additional functions as delegates to your base class. But this wiring needs to be maitained within the code and will be clumsy and error prone. Objective C just assumes that programmers are not best at maintaining this decipline and provides compiler restrictions to enforce a clean implementation.
Swift version
A delegate is just a class that does some work for another class. Read the following code for a somewhat silly (but hopefully enlightening) Playground example that shows how this is done in Swift.
// A protocol is just a list of methods (and/or properties) that must
// be used by any class that adopts the protocol.
protocol OlderSiblingDelegate: class {
// This protocol only defines one required method
func getYourNiceOlderSiblingAGlassOfWater() -> String
}
class BossyBigBrother {
// The delegate is the BossyBigBrother's slave. This position can
// be assigned later to whoever is available (and conforms to the
// protocol).
weak var delegate: OlderSiblingDelegate?
func tellSomebodyToGetMeSomeWater() -> String? {
// The delegate is optional because there might not be anyone
// nearby to boss around.
return delegate?.getYourNiceOlderSiblingAGlassOfWater()
}
}
// PoorLittleSister conforms to the OlderSiblingDelegate protocol
class PoorLittleSister: OlderSiblingDelegate {
// This method is repquired by the protocol, but the protocol said
// nothing about how it needs to be implemented.
func getYourNiceOlderSiblingAGlassOfWater() -> String {
return "Go get it yourself!"
}
}
// initialize the classes
let bigBro = BossyBigBrother()
let lilSis = PoorLittleSister()
// Set the delegate
// bigBro could boss around anyone who conforms to the
// OlderSiblingDelegate protocol, but since lilSis is here,
// she is the unlucky choice.
bigBro.delegate = lilSis
// Because the delegate is set, there is a class to do bigBro's work for him.
// bigBro tells lilSis to get him some water.
if let replyFromLilSis = bigBro.tellSomebodyToGetMeSomeWater() {
print(replyFromLilSis) // "Go get it yourself!"
}
In actual practice, delegates are often used in the following situations
When a class needs to communicate some information to another class
When a class wants to allow another class to customize it
The classes don't need to know anything about each other beforehand except that the delegate class conforms to the required protocol.
I highly recommend reading the following two articles. They helped me understand delegates even better than the documentation did.
What is Delegation? – A Swift Developer’s Guide
How Delegation Works – A Swift Developer’s Guide
Ok, this is not really an answer to the question, but if you are looking up how to make your own delegate maybe something far simpler could be a better answer for you.
I hardly implement my delegates because I rarely need. I can have ONLY ONE delegate for a delegate object. So if you want your delegate for one way communication/passing data than you are much better of with notifications.
NSNotification can pass objects to more than one recipients and it is very easy to use.
It works like this:
MyClass.m file should look like this
#import "MyClass.h"
#implementation MyClass
- (void) myMethodToDoStuff {
//this will post a notification with myClassData (NSArray in this case) in its userInfo dict and self as an object
[[NSNotificationCenter defaultCenter] postNotificationName:#"myClassUpdatedData"
object:self
userInfo:[NSDictionary dictionaryWithObject:selectedLocation[#"myClassData"] forKey:#"myClassData"]];
}
#end
To use your notification in another classes:
Add class as an observer:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(otherClassUpdatedItsData:) name:#"myClassUpdatedData" object:nil];
Implement the selector:
- (void) otherClassUpdatedItsData:(NSNotification *)note {
NSLog(#"*** Other class updated its data ***");
MyClass *otherClass = [note object]; //the object itself, you can call back any selector if you want
NSArray *otherClassData = [note userInfo][#"myClassData"]; //get myClass data object and do whatever you want with it
}
Don't forget to remove your class as an observer if
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
lets say you have a class that you developed and want to declare a delegate property to be able to notify it when some event happens :
#class myClass;
#protocol myClassDelegate <NSObject>
-(void)myClass:(MyClass*)myObject requiredEventHandlerWithParameter:(ParamType*)param;
#optional
-(void)myClass:(MyClass*)myObject optionalEventHandlerWithParameter:(ParamType*)param;
#end
#interface MyClass : NSObject
#property(nonatomic,weak)id< MyClassDelegate> delegate;
#end
so you declare a protocol in MyClass header file (or a separate header file) , and declare the required/optional event handlers that your delegate must/should implement , then declare a property in MyClass of type (id< MyClassDelegate>) which means any objective c class that conforms to the protocol MyClassDelegate , you'll notice that the delegate property is declared as weak , this is very important to prevent retain cycle (most often the delegate retains the MyClass instance so if you declared the delegate as retain, both of them will retain each other and neither of them will ever be released).
you will notice also that the protocol methods passes the MyClass instance to the delegate as parameter , this is best practice in case the delegate want to call some methods on MyClass instance and also helps when the delegate declares itself as MyClassDelegate to multiple MyClass instances , like when you have multiple UITableView's instances in your ViewController and declares itself as a UITableViewDelegate to all of them.
and inside your MyClass you notify the delegate with declared events as follows :
if([_delegate respondsToSelector:#selector(myClass: requiredEventHandlerWithParameter:)])
{
[_delegate myClass:self requiredEventHandlerWithParameter:(ParamType*)param];
}
you first check if your delegate responds to the protocol method that you are about to call in case the delegate doesn't implement it and the app will crash then (even if the protocol method is required).
To create your own delegate, first you need to create a protocol and declare the necessary methods, without implementing. And then implement this protocol into your header class where you want to implement the delegate or delegate methods.
A protocol must be declared as below:
#protocol ServiceResponceDelegate <NSObject>
- (void) serviceDidFailWithRequestType:(NSString*)error;
- (void) serviceDidFinishedSucessfully:(NSString*)success;
#end
This is the service class where some task should be done. It shows how to define delegate and how to set the delegate. In the implementation class after the task is completed the delegate's the methods are called.
#interface ServiceClass : NSObject
{
id <ServiceResponceDelegate> _delegate;
}
- (void) setDelegate:(id)delegate;
- (void) someTask;
#end
#implementation ServiceClass
- (void) setDelegate:(id)delegate
{
_delegate = delegate;
}
- (void) someTask
{
/*
perform task
*/
if (!success)
{
[_delegate serviceDidFailWithRequestType:#”task failed”];
}
else
{
[_delegate serviceDidFinishedSucessfully:#”task success”];
}
}
#end
This is the main view class from where the service class is called by setting the delegate to itself. And also the protocol is implemented in the header class.
#interface viewController: UIViewController <ServiceResponceDelegate>
{
ServiceClass* _service;
}
- (void) go;
#end
#implementation viewController
//
//some methods
//
- (void) go
{
_service = [[ServiceClass alloc] init];
[_service setDelegate:self];
[_service someTask];
}
That's it, and by implementing delegate methods in this class, control will come back once the operation/task is done.
Here is a simple method to create delegates
Create Protocol in .h file. Make sure that is defined before the protocol using #class followed by the name of the UIViewController < As the protocol I am going to use is UIViewController class>.
Step : 1 : Create a new class Protocol named "YourViewController" which will be the subclass of UIViewController class and assign this class to the second ViewController.
Step : 2 : Go to the "YourViewController" file and modify it as below:
#import <UIKit/UIkit.h>
#class YourViewController;
#protocol YourViewController Delegate <NSObject>
#optional
-(void)defineDelegateMethodName: (YourViewController *) controller;
#required
-(BOOL)delegateMethodReturningBool: (YourViewController *) controller;
#end
#interface YourViewController : UIViewController
//Since the property for the protocol could be of any class, then it will be marked as a type of id.
#property (nonatomic, weak) id< YourViewController Delegate> delegate;
#end
The methods defined in the protocol behavior can be controlled with #optional and #required as part of the protocol definition.
Step : 3 :
Implementation of Delegate
#import "delegate.h"
#interface YourDelegateUser ()
<YourViewControllerDelegate>
#end
#implementation YourDelegateUser
- (void) variousFoo {
YourViewController *controller = [[YourViewController alloc] init];
controller.delegate = self;
}
-(void)defineDelegateMethodName: (YourViewController *) controller {
// handle the delegate being called here
}
-(BOOL)delegateMethodReturningBool: (YourViewController *) controller {
// handle the delegate being called here
return YES;
}
#end
//test whether the method has been defined before you call it
- (void) someMethodToCallDelegate {
if ([[self delegate] respondsToSelector:#selector(defineDelegateMethodName:)]) {
[self.delegate delegateMethodName:self];
}
}
Disclaimer: this is the Swift version of how to create a delegate.
So, what are delegates? …in software development, there are general reusable solution architectures that help to solve commonly occurring problems within a given context, these “templates”, so to speak, are best known as design patterns.
Delegates are a design pattern that allows one object to send messages to another object when a specific event happens.
Imagine an object A calls an object B to perform an action. Once the action is complete, object A should know that B has completed the task and take necessary action, this can be achieved with the help of delegates!
For a better explanation, I am going to show you how to create a custom delegate that passes data between classes, with Swift in a simple application,start by downloading or cloning this starter project and run it!
You can see an app with two classes, ViewController A and ViewController B. B has two views that on tap changes the background color of the ViewController, nothing too complicated right? well now let’s think in an easy way to also change the background color of class A when the views on class B are tapped.
The problem is that this views are part of class B and have no idea about class A, so we need to find a way to communicate between this two classes, and that’s where delegation shines.
I divided the implementation into 6 steps so you can use this as a cheat sheet when you need it.
step 1: Look for the pragma mark step 1 in ClassBVC file and add this
//MARK: step 1 Add Protocol here.
protocol ClassBVCDelegate: class {
func changeBackgroundColor(_ color: UIColor?)
}
The first step is to create a protocol, in this case, we will create the protocol in class B, inside the protocol you can create as many functions that you want based on the requirements of your implementation. In this case, we just have one simple function that accepts an optional UIColor as an argument.
Is a good practice to name your protocols adding the word delegate at the end of the class name, in this case, ClassBVCDelegate.
step 2: Look for the pragma mark step 2 in ClassVBC and add this
//MARK: step 2 Create a delegate property here.
weak var delegate: ClassBVCDelegate?
Here we just create a delegate property for the class, this property must adopt the protocol type, and it should be optional. Also, you should add the weak keyword before the property to avoid retain cycles and potential memory leaks, if you don’t know what that means don’t worry for now, just remember to add this keyword.
step 3: Look for the pragma mark step 3 inside the handleTap method in ClassBVC and add this
//MARK: step 3 Add the delegate method call here.
delegate?.changeBackgroundColor(tapGesture.view?.backgroundColor)
One thing that you should know, run the app and tap on any view, you won’t see any new behavior and that’s correct but the thing that I want to point out is that the app it’s not crashing when the delegate is called, and it’s because we create it as an optional value and that’s why it won’t crash even the delegated doesn’t exist yet. Let’s now go to ClassAVC file and make it, the delegated.
step 4: Look for the pragma mark step 4 inside the handleTap method in ClassAVC and add this next to your class type like this.
//MARK: step 4 conform the protocol here.
class ClassAVC: UIViewController, ClassBVCDelegate {
}
Now ClassAVC adopted the ClassBVCDelegate protocol, you can see that your compiler is giving you an error that says “Type ‘ClassAVC does not conform to protocol ‘ClassBVCDelegate’ and this only means that you didn’t use the methods of the protocol yet, imagine that when class A adopts the protocol is like signing a contract with class B and this contract says “Any class adopting me MUST use my functions!”
Quick note: If you come from an Objective-C background you are probably thinking that you can also shut up that error making that method optional, but for my surprise, and probably yours, Swift language does not support optional protocols, if you want to do it you can create an extension for your protocol or use the #objc keyword in your protocol implementation.
Personally, If I have to create a protocol with different optional methods I would prefer to break it into different protocols, that way I will follow the concept of giving one single responsibility to my objects, but it can vary based on the specific implementation.
here is a good article about optional methods.
step 5: Look for the pragma mark step 5 inside the prepare for segue method and add this
//MARK: step 5 create a reference of Class B and bind them through the `prepareforsegue` method.
if let nav = segue.destination as? UINavigationController, let classBVC = nav.topViewController as? ClassBVC {
classBVC.delegate = self
}
Here we are just creating an instance of ClassBVC and assign its delegate to self, but what is self here? well, self is the ClassAVC which has been delegated!
step 6: Finally, look for the pragma step 6 in ClassAVC and let’s use the functions of the protocol, start typing func changeBackgroundColor and you will see that it’s auto-completing it for you. You can add any implementation inside it, in this example, we will just change the background color, add this.
//MARK: step 6 finally use the method of the contract
func changeBackgroundColor(_ color: UIColor?) {
view.backgroundColor = color
}
Now run the app!
Delegates are everywhere and you probably use them without even notice, if you create a tableview in the past you used delegation, many classes of UIKIT works around them and many other frameworks too, they solve these main problems.
Avoid tight coupling of objects.
Modify behavior and appearance without the need to subclass objects.
Allow tasks to be handled off to any arbitrary object.
Congratulations, you just implement a custom delegate, I know that you are probably thinking, so much trouble just for this? well, delegation is a very important design pattern to understand if you want to become an iOS developer, and always keep in mind that they have one to one relationship between objects.
You can see the original tutorial here
Answer is actually answered, but I would like to give you a "cheat sheet" for creating a delegate:
DELEGATE SCRIPT
CLASS A - Where delegate is calling function
#protocol <#Protocol Name#> <NSObject>
-(void)delegateMethod;
#end
#interface <#Some ViewController#> : <#UIViewController#>
#property (nonatomic, assign) id <<#Protocol Name#>> delegate;
#end
#implementation <#Some ViewController#>
-(void)someMethod {
[self.delegate methodName];
}
#end
CLASS B - Where delegate is called
#interface <#Other ViewController#> (<#Delegate Name#>) {}
#end
#implementation <#Other ViewController#>
-(void)otherMethod {
CLASSA *classA = [[CLASSA alloc] init];
[classA setDelegate:self];
}
-delegateMethod() {
}
#end
ViewController.h
#protocol NameDelegate <NSObject>
-(void)delegateMEthod: (ArgType) arg;
#end
#property id <NameDelegate> delegate;
ViewController.m
[self.delegate delegateMEthod: argument];
MainViewController.m
ViewController viewController = [ViewController new];
viewController.delegate = self;
Method:
-(void)delegateMEthod: (ArgType) arg{
}
In my point of view create separate class for that delegate method and you can use where you want.
in my Custom DropDownClass.h
typedef enum
{
DDSTATE,
DDCITY
}DropDownType;
#protocol DropDownListDelegate <NSObject>
#required
- (void)dropDownDidSelectItemWithString:(NSString*)itemString DropDownType:(DropDownType)dropDownType;
#end
#interface DropDownViewController : UIViewController
{
BOOL isFiltered;
}
#property (nonatomic, assign) DropDownType dropDownType;
#property (weak) id <DropDownListDelegate> delegate;
#property (strong, nonatomic) NSMutableArray *array1DropDown;
#property (strong, nonatomic) NSMutableArray *array2DropDown;
after that in.m file create array with objects,
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
CGFloat rowHeight = 44.0f;
return rowHeight;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return isFiltered?[self.array1DropDown count]:[self.array2DropDown count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"TableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if (self.delegate) {
if (self.dropDownType == DDCITY) {
cell.textLabel.text = [self.array1DropDown objectAtIndex:indexPath.row];
}
else if (self.dropDownType == DDSTATE) {
cell.textLabel.text = [self.array2DropDown objectAtIndex:indexPath.row];
}
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self dismissViewControllerAnimated:YES completion:^{
if(self.delegate){
if(self.dropDownType == DDCITY){
[self.delegate dropDownDidSelectItemWithString:[self.array1DropDown objectAtIndex:indexPath.row] DropDownType:self.dropDownType];
}
else if (self.dropDownType == DDSTATE) {
[self.delegate dropDownDidSelectItemWithString:[self.array2DropDown objectAtIndex:indexPath.row] DropDownType:self.dropDownType];
}
}
}];
}
Here all are set for Custom delegate class.after that you can use this delegate method where you want.for example...
in my another viewcontroller import after that
create action for calling delegate method like this
- (IBAction)dropDownBtn1Action:(id)sender {
DropDownViewController *vehicleModelDropView = [[DropDownViewController alloc]init];
vehicleModelDropView.dropDownType = DDCITY;
vehicleModelDropView.delegate = self;
[self presentViewController:vehicleModelDropView animated:YES completion:nil];
}
after that call delegate method like this
- (void)dropDownDidSelectItemWithString:(NSString *)itemString DropDownType:(DropDownType)dropDownType {
switch (dropDownType) {
case DDCITY:{
if(itemString.length > 0){
//Here i am printing the selected row
[self.dropDownBtn1 setTitle:itemString forState:UIControlStateNormal];
}
}
break;
case DDSTATE: {
//Here i am printing the selected row
[self.dropDownBtn2 setTitle:itemString forState:UIControlStateNormal];
}
default:
break;
}
}
Delegate :- Create
#protocol addToCartDelegate <NSObject>
-(void)addToCartAction:(ItemsModel *)itemsModel isAdded:(BOOL)added;
#end
Send and please assign delegate to view you are sending data
[self.delegate addToCartAction:itemsModel isAdded:YES];
//1.
//Custom delegate
#protocol TB_RemovedUserCellTag <NSObject>
-(void)didRemoveCellWithTag:(NSInteger)tag;
#end
//2.
//Create a weak reference in a class where you declared the delegate
#property(weak,nonatomic)id <TB_RemovedUserCellTag> removedCellTagDelegate;
//3.
// use it in the class
[self.removedCellTagDelegate didRemoveCellWithTag:self.tag];
//4. import the header file in the class where you want to conform to the protocol
#interface MyClassUsesDelegate ()<TB_RemovedUserCellTag>
#end
//5. Implement the method in the class .m
-(void)didRemoveCellWithTag:(NSInteger)tag
{
NSLog#("Tag %d",tag);
}
Let's start with an example , if we buy a product online ,it goes through process like shipping/delivery handled by different teams.So if shipping gets completed ,shipping team should notify delivery team & it should be one to one communication as broadcasting this information would be overhead for other people / vendor might want to pass this information only to required people.
So if we think in terms of our app, an event can be an online order & different teams can be like multiple views.
Here is code consider ShippingView as Shipping team & DeliveryView as delivery team :
//Declare the protocol with functions having info which needs to be communicated
protocol ShippingDelegate : class {
func productShipped(productID : String)
}
//shippingView which shows shipping status of products
class ShippingView : UIView
{
weak var delegate:ShippingDelegate?
var productID : String
#IBAction func checkShippingStatus(sender: UIButton)
{
// if product is shipped
delegate?.productShipped(productID: productID)
}
}
//Delivery view which shows delivery status & tracking info
class DeliveryView: UIView,ShippingDelegate
{
func productShipped(productID : String)
{
// update status on view & perform delivery
}
}
//Main page on app which has both views & shows updated info on product whole status
class ProductViewController : UIViewController
{
var shippingView : ShippingView
var deliveryView : DeliveryView
override func viewDidLoad() {
super.viewDidLoad()
// as we want to update shipping info on delivery view, so assign delegate to delivery object
// whenever shipping status gets updated it will call productShipped method in DeliveryView & update UI.
shippingView.delegate = deliveryView
//
}
}
A picture is more than a thousand words :-P
The variable greeter in the function main of the Objective-C code is known as a delegate, which is no more than a C++ pointer to an object that implements a class of pure virtual functions.

Objective C Callback on particular event

I am new to objective C and trying to develop my own callback function, the callback function gets called on a particular event like receiving data from network like NSURLprotocol does and once received it will NSLog a message that "Event has Occured" or display as text on UIViewController or any UI related action.
So, I am totally confused as to where the eventOccuredMethod should be called to let the receiveController be called and execute the implementation inside it.
I have used protocols like NSURLProtocol before, but I don't know how to implement them to get such callbacks being called.
Any video links, answers, articles links are welcomed.
//Sample.h file
#import <Foundation/Foundation.h>
#class Sample;
#protocol SampleProtocol <NSObject>
-(void)receivedCallback;
#end
#interface Sample : NSObject
#property (nonatomic,weak) id<SampleProtocol> delegate;
-(void)eventOccured;
#end
//Sample.m file
#import "Sample.h"
#implementation Sample
-(void)eventOccured{
if([_delegate conformsToProtocol:#protocol(SampleProtocol)])
[_delegate receivedCallback];
}
#end
//ViewController.h file
#interface ViewController : UIViewController<SampleProtocol>
#end
//ViewController.m file
#import "ViewController.h"
#interface ViewController (){
Sample *s;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
s = [[Sample alloc] init];
s.delegate = self;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)receivedCallback:(Sample *)sample{
NSLog(#"Event Has Occured");
}
#end
I am not sure of the following call which I am making ...
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
Sample *s = [[Sample alloc] init];
[s eventOccured];
}
You are implementing the delegate pattern the right way. But if the Sample object doesn't generate its own events but instead is relaying events posted to it from somewhere else, as is the case in your example, you have to ensure that the object which has the ViewController as a delegate and the object that receives the message are in fact the same. One way to do it is to make Sample a singleton :
#import "Sample.h"
#implementation Sample
+ (instancetype)sharedInstance
{
static id sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[[self class] alloc] init];
});
return sharedInstance;
}
-(void)eventOccured{
if([_delegate conformsToProtocol:#protocol(SampleProtocol)])
[_delegate receivedCallback];
}
#end
And then in your view controller you would do
s = [Sample sharedInstance];
and in your appDelegate :
[[Sample sharedInstance] eventOccured];
Another way to ensure that you are using the same object, as vikingosegundo pointed out, would be to set the view controller's Sample object from the appDelegate.
For this use case, you could also consider using Notifications.
?, i'm very confused. I don't think you understand what you have written. You should never try copy code like this from online without first reading a tutorial to understand what it is you are doing. This can be very dangerous.
Sample.h / .m is a class, this class defines a protocol that says "In order for me to alert you to the fact an event has occurred, you need to implement method X".
This is the "protocol", by conforming to the protocol, another class (lets say a ViewController) is saying that it implements the method that Sample is looking for.
So Sample will run code, and when it wants to pass some info back to the other class (ViewController in this case) it calls one of the methods defined in the protocol.
e.g. (not fully working code)
Sample.m
- (void)getDataFromURL:(NSStirng *)url
{
[self HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject)
{
if([_delegate conformsToProtocol:#protocol(SampleProtocol)])
{
[_delegate receivedCallback];
}
}];
}
So when Sample runs the method getDataFromURL it will request its data, when the data returns, Sample will call the method receivedCallback on its delegate. Which in this case is an instance of a viewController.
EDIT
please also note what [_delegate conformsToProtocol:#protocol(SampleProtocol)] does. This asks does the delegate instance conform to the protocol. But this protocol hasn't said that recievedCallback is required. So you have no way of knowing the method is there.
either use:
#protocol SampleProtocol <NSObject>
#required
-(void)receivedCallback;
#end
in the protocol definition or
if(self.delegate && [self.delegate respondsToSelector:#selector(receivedCallback)])
to check is it implemented
you are calling eventOccured on a second, independent Sample instance that has now delegate set.
The easiest fix: make the view controller send it to it's sample instance.
better: give the view controller a property that holds sample and sat that from the application delegate.
You should call EventOccurred within your data retrieving method. Once the data retrieving is complete call EventOccured.
#protocol SampleProtocol <NSObject>
-(void)receivedCallback;
#end
This protocol must be implemented in your data retrieving class. And make sure -(void)receivedCallback; has a parameter to send data to your ViewController

Invoke Method in Different Class

I have a class that subclasses UITableViewController. Based on user actions that are recognized in this class, I need to call a method on a table in the UIViewController were the table is instantiated. I can't figure out how to do this.
I tried to make the function static, but that won't work since there is an instance variable that I need to reach. I could probably use NSNotificationCenter but my intuition is that there is a better way. Can someone help? Thanks!
MonthsTableViewController.h
#interface MonthsTableViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate>
{
NSArray *monthsArray;
}
#end
MonthsTableViewController.m
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
NSLog(#"calling the UIViewController");
//this is where I am stuck!!!
}
SubscribeViewController.h
#interface SubscribeViewController : UIViewController <SIMChargeCardViewControllerDelegate>
{
MonthsTableViewController *monthsController;
IBOutlet UITableView *monthsTable;
}
- (void) snapMonthsToCenter;
#end
SubscribeViewController.m
- (void) snapMonthsToCenter {
// snap the table selections to the center of the row
NSLog(#"method called!");
NSIndexPath *pathForMonthCenterCell = [monthsTable indexPathForRowAtPoint:CGPointMake(CGRectGetMidX(monthsTable.bounds), CGRectGetMidY(monthsTable.bounds))];
[monthsTable scrollToRowAtIndexPath:pathForMonthCenterCell atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
Basically in order to do this, you need a reference to your UIViewController from your UITableViewController. This will allow you to call the methods of this object. Typically you would call this property a delegate, because you're assigning the "parent" UIViewController as the delegate of the "child" UITableViewController.
Modify your UITableViewController (MonthsTableViewController.h) to add a delegate property like so:
#interface MonthsTableViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate>
{
NSArray *monthsArray;
id delegate;
}
#property (nonatomic, retain) id delegate;
#end
You will need to #synthesize the property in your .m file. You'll also want to import SubscribeViewController.h in your header here, if you haven't already.
Then, when you instantiate your MonthsTableViewController, set the delegate to your current object MonthsTableViewController like so:
MonthsTableViewController *example = [[MonthsTableViewController alloc] init.... // This is the line you should already have
[example setDelegate:self]; // Set this object's delegate property to the current object
Now you have access to the parent SubscribeViewController from your MonthsTableViewController. So how do you call functions? Easy! You can either hardcode the method call, or, to be super safe, use respondsToSelector::
[(MonthsTableViewController*)[self delegate] snapMonthsToCenter];
In your case, the above code is absolutely fine, because you know that this method will always exist on this object. Typically, however, delegates are declared as protocols that may have optional methods. This means that although methods are declared in the #interface, they may not actually exist (be implemented) in the object. In this case, the following code would be used to make sure that the method can actually be called on the object:
if([[self delegate] respondsToSelector:#selector(snapMonthsToCenter)]) {
[[self delegate] snapMonthsToCenter];
}

Using my own delegate

I´m having problems declarating my own delegate. Well...thats not exactly true: i have it declarated and, when i build the project, the compiler reports no issues. I declarated it in this way:
I made a file (enviarDatos.h) for declare the protocol:
#protocol enviarDatos <NSObject>
- (void)addItemViewController:(NSMutableArray *)item;
#end
In the Vista2.h (ViewController) file I imported the file enviarDatos.h and declared a property:
#property (nonatomic, weak) id <enviarDatos> delegare;
In the Vista2.m (ViewController) file I use the protocol method:
#interface ViewController : UIViewController <enviarDatos> {
And, finally, in the ViewController.m file I implement the delegates method:
- (void)addItemViewController:(NSMutableArray *)ar {
origen = ar;
}
Does anyone see something wrong? the code of the last function its never executing.
Thanks for your help.
EDIT:
What i need is to change an array in ViewController from Vista2 (another viewcontroller)
Then create delegate property in next view(child view) & set it to self in parent view while pushing or showing child view.
ParentView.m
1.Implement protocol methods
- (void)addItemViewController:(NSMutableArray *)ar
{
origen = ar;
}
2.While showing child view
ChildViewController *child = [[ChildViewController alloc] init];
child.delegate = self;
//present child view
ChildView.h
#property (nonatomic, weak) id <enviarDatos> delegare;
ChildView.m
-(void) anyMethod
{
if([self.delegate respondsToSelector:#selector(addItemViewController:)])
{
[self.delegate addItemViewController:mutableArray];
}
}
Ah, it looks like you are declaring the delegate property in the wrong place.
You should declare the property delegate in enviarDatos.h.
#property (nonatomic, weak) id <enviarDatos> delegate;
Then in Vista2.m you will do something like this...
EnviarDatos *myObject = [[EnviarDatos alloc] init];
myObject.delegate = self;
This then sets up the EnviarDatos object and assigns the Vista2 object as the delegate.
Now, in EnviarDatos.m you can run...
[self.delegate addItemViewController:someObjectArray];
And this will then run that code in the Vista2 object.
Delegates are used for calling back to objects that create them (or some other objects). If you create an object and then want to run a method in it then you won't need a delegate.
Can you say at what condition addItemViewController is invoked?
You seem to be on the right track, but are you sure you are setting the delegate as
[yourObject setDelegate: self];
Have you tried debugging it? Does the debugger pause at addItemViewController if you set a breakpoint there? Can you confirm the delegate is not null inside the method? I may post some code but your seems to be right except for the assigning of delegate, I think you should check it.

Resources