I ultimately want to write an iOS app incorporating ALAssetsLibrary, but as a first step toward understanding delegation, I'm trying to pass a simple message between two view controllers. For some reason, I can't seem to get the message to pass. In particular, the delegate object (derpy) doesn't appear to exist (if(self.derpy) returns NO)).
I asked the same question on the Apple forums and was told that I should be using segues and setting properties / calling methods using self.child instead, but that seems strange. If I were to pass messages using the parent / child properties, would I still be able to create my views in Interface Builder? Once I have my two views set up, say inside a UINavigationController, I'm not sure how to actually "wire them up" so I can pass messages between them. Sorry if the question is overly broad.
Here's the controller I'm declaring the protocol in (called PickerViewController):
Interface:
#import <UIKit/UIKit.h>
#import <AssetsLibrary/AssetsLibrary.h>
#protocol DerpDelegate <NSObject>
#required
- (void) test;
#end
#interface PickerViewController : UIViewController
#property (nonatomic, assign) id<DerpDelegate> derpy;
#end
Implementation:
#import "PickerViewController.h"
#interface PickerViewController ()
#end
#implementation PickerViewController
- (void)viewDidLoad
{
[super viewDidLoad];
if (self.derpy) { // If the delegate object exists
[self.derpy test]; // send it this message
} else {
NSLog(#"Still not working."); // This always returns (i.e., self.derpy doesn't exist)
}
}
Delegate controller (MainViewController) interface:
#import <UIKit/UIKit.h>
#import "PickerViewController.h"
#interface MainViewController : UIViewController <DerpDelegate> // public promise to implement delegate methods
#property (strong, nonatomic) PickerViewController *picker;
- (void) test;
#end
And lastly, the delegate controller (MainViewController) implementation:
#import "MainViewController.h"
#import "PickerViewController.h"
#interface MainViewController ()
#end
#implementation MainViewController
// Here's that method I promised I'd implement
- (void) test{
NSLog(#"Test worked."); // This never gets called
}
- (void)viewDidLoad {
[super viewDidLoad];
self.picker.derpy = self;
//lazy instantiation
- (PickerViewController *) picker{
if(!_picker) _picker = [[PickerViewController alloc]init];
return _picker;
}
EDIT: Many thanks to rydgaze for pointing me in the right direction with self.picker.derpy = self, but for some reason, things still aren't working properly. Importantly, once that property has been set, if(self.picker.derpy) returns YES from MainViewController. But if(self.derpy) is still returning NO when called from inside the PickerViewController's viewDidLoad. How can the property exist and not exist at the same time?
You need to be sure that you're setting the delegate on the instance of the view controller that you put on screen. If you're using a navigation controller and segues to go between MainViewController and PickerViewController, then you should set the delegate in prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
self.picker = (PickerViewController *)segue.destinationViewController;
self.picker.derpy = self;
}
You need to populate the delegate first.
Basically, your MainViewController shoudl at somepoint do a
picker.derpy = self;
Then when the delegate fires in PickerViewController, the callback will happen.
Edit:
A good practice is to do something like in PickerViewController
#property (nonatomic, assign) id<DerpDelegate > derpy;
and in your MainViewController indicate that you will implement the delegate
#interface MainViewController : UIViewController<DerpDelegate>
Eventually in your implementation of MainViewController
You will have something like
picker = [[PickerViewController alloc]init];
picker.derpy = self;
[picker doYourThing];
Once picker is all done, it may want to return results using the delegate.
Related
So I am calling delegate function but some how its not getting called, I tried everything from all the other similar threads but nothing works. It looks all good but the method is still not called. here is my code below -
So i created protocol like this -
AuthViewController.h
#class AuthViewController;
#protocol AuthViewControllerDelegate <NSObject>
- (void)updateNavigation:(NSString*)pageType
message:(NSString*)message;
#end
created a property -
#property (nonatomic, weak)id delegate;
And called the function in AuthViewController.m -
[self.delegate updateNavigation:#"xx" message:#"xx"];
Then in other class -
AssociateViewController.h
#interface AssociateViewController : UIViewController <AuthViewControllerDelegate>
#property (nonatomic, strong)AuthViewController *vc;
#End
AssociateViewController.m
First set the delegate in a button action or viewWillAppear(I tried both)-
self.vc = [[AuthViewController alloc] init];
self.vc.delegate = self;
And the here is the method which is somehow never called :( -
- (void)updateNavigation:(NSString*)pageType
message:(NSString*)message;
{
//method to do
}
Any help would be much appreciated. Thanks!
I have written protocol in a view controller, and implement it in AppDelegate, and when I call delegate function from view controller, the delegate function is not called. Below is my code -
In class AuthenticationViewController -
#class AuthenticationViewController;
#protocol ApplicationTiomeoutDelegate <NSObject>
-(void) addObserverForTimeout;
#end
And call this function using delegate -
[self.appTimeoutDelegate addObserverForApplicationTimeout];
And in AppDelegate, I have implemented this protocol like this -
#interface AppDelegate () <ApplicationTiomeoutDelegate>
#end
And then set delegate to self -
AuthenticationViewController *timeoutDelegate = [[AuthenticationViewController alloc] init];
[timeoutDelegate setAppTimeoutDelegate:self];
And implemented delegate function as well in AppDelegate, which is never called somehow -
-(void) addObserverForApplicationTimeout{
// this function is never called
}
I am not sure what is not correct here.
AppDelegate being a singleton need not have the ApplicationTiomeoutDelegate protocol invocation. You can directly invoke addObserverForTimeout
You create method in your appdelegate, you can directly call it wherever you want with instance of appdelegate.
For your question, check this below
Where are creating instance for Your delegate and where are calling your delegate form your viewcontroller, it is used to communicate between two class, it should have reference of protocol.
try this
Your viewcontroller.h
#protocol customDelegate;
#import <UIKit/UIKit.h>
#import "CustomTableViewCell.h"
#interface ViewController : UIViewController<UITableViewDelegate>
{
IBOutlet UITableView *mainTableView;
}
#property (nonatomic,strong) id <customDelegate> delegate;
#end
#protocol customDelegate <NSObject>
-(void)method;
#end
ViewController.m
- (void)viewDidLoad {
[self.delegate method];
}
Your app delegate
#interface AppDelegate () <customDelegate>
#end
Your didfinishlaunghing
viewController = [[ViewController alloc]initWithNibName:#"ViewController" bundle:nil];
viewController.delegate = self;
and implement method:
-(void)method{
NSLog(#"calling");
}
i have created a delegate for my project the code of my main view is
VedantViewController.h
#protocol VedantDelegate;
#interface VedantViewController : UIViewController
{
id <VedantDelegate> delegate;
}
//some other outlets
#property(nonatomic, assign) id <VedantDelegate> delegate;
#protocol VedantDelegate <NSObject>
- (void)display:(NSString *)JSONResponse;
#end
VedantViewController.m
#synthesize delegate;
[delegate display:jsonResponse];
SecondViewController.h
#interface SecondViewController : UIViewController<VedantDelegate>
- (void)display:(NSString *)JSONResponse;
SecondViewController.m
- (void)display:(NSString *)string
{
}
but this code is not working properly
when i debug the code using breakpoints the code reaches the
[delegate display:abc];
but it does not calls display function in SecondViewController.m file
i think my code is right but some mistake that i can't recognize
let me explain you the flow of my project this could be the problem
by default the VedantViewController view is launched
after that when the show button is click it calls the SecondViewController view in the view these is list button that calls the function in VedantViewController this function then calls the delegate method that is [delegate display:jsonResponse];
Thanks in Advance,
Arun.
The view controller which is confirming with the protocol, should have this line in the viewDidLoad or anywhere you are making the object of that viewController
Add this line in SecondViewController.m
VedantViewControllerObject.delegate = self;
#protocol VedantDelegate;
#interface VedantViewController : UIViewController{
id<VedantDelegate> delegate;
}
//some other outlets
#property(nonatomic,assign) id<VedantDelegate> delegate;
#protocol VedantDelegate <NSObject>
-(void)displayAccounts:(NSString *)JSONResponse;
-(void)display:(NSString *)JSONResponse;
#end
and also set delegate to object of VedantViewControllerObject class as self in SecondViewController class and the object of VedantViewControllerObject class should be initialized and allocated.
vedantViewControllerObject.delegate = self;
In your VedantViewController.h file you declared method as below
-(void)displayAccounts:(NSString *)JSONResponse;
But you are calling it [delegate display:jsonResponse];
You just try to call
[delegate displayAccounts:jsonResponse];
And in SecondViewController.m
(void)displayAccounts:(NSString *)string{
}
There are some issues in your code:
set the delegate in second view controller
vedViewObject.delegate = self;
You added displayAccounts method in delegate and calling display method, that can cause issues. If that methods are not implemented in the delegate class.
Add if condition like: if(delegate)[delegate displayAccounts:jsonResponse];
I'm trying to set the delegate for my custom protocol that has one required method allowing me to pass an array of objects back in the hierarchy of two UITableViewControllers. My delegate continues to return nil. Due to this, my required method is never called.
I'm wondering if the datasource and delegate implementations with my UITableViewControllers is causing a conflict. Also, perhaps ARC is getting in the way when declaring the delegate?
It should be noted that both UITableViewControllers were built using Storyboard and are navigated using segues within a UINavigationController (not sure if this may be causing issues or not).
The nav is --> AlarmViewController --> AlarmDetailsViewController. I create an Alarm object in my AlarmDetailsViewController that contains all the details for an alarm, place it into an array and I want to pass that array back to my AlarmViewController to be displayed in a custom cell in the table.
NOTE: I want to use the Delegate pattern here. I'm not interested in solutions that invoke NSNotifications or use my AppDelegate class.
AlarmDetailsViewController.h
#import "Alarm.h"
#protocol PassAlarmArray <NSObject>
#required
-(void) passAlarmsArray:(NSMutableArray *)theAlarmsArray;
#end
#interface AlarmDetailsViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate>
{
//.....
id <PassAlarmArray> passAlarmsArrayDelegate;
}
#property (nonatomic, retain) id <PassAlarmArray> passAlarmsArrayDelegate;
#end
AlarmDetailsViewController.m
#import "AlarmDetailsViewController.h"
#interface AlarmDetailsViewController ()
#end
#implementation AlarmDetailsViewController
#synthesize passAlarmsArrayDelegate;
-(void) viewWillDisappear:(BOOL)animated
{
NSLog(#"delegate = %#", self.passAlarmsArrayDelegate); // This prints nil
[[self passAlarmsArrayDelegate] passAlarmsArray:alarmsArray];
}
//....
#end
AlarmViewController.h
#interface AlarmViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate, PassAlarmArray>
{
//...
AlarmDetailsViewController *alarmDetailsViewController;
}
#property (nonatomic, retain) AlarmDetailsViewController *alarmDetailsViewController;
#end
AlarmViewController.m
#import "AlarmViewController.h"
#import "AlarmDetailsViewController.h"
#import "AlarmTableViewCell.h"
#import "Alarm.h"
#interface AlarmViewController ()
#end
#implementation AlarmViewController
#synthesize alarmDetailsViewController;
- (void)viewDidLoad
{
[super viewDidLoad];
// This is where I'm attempting to set the delegate
alarmDetailsViewController = [[AlarmDetailsViewController alloc]init];
[alarmDetailsViewController setPassAlarmsArrayDelegate:self];
}
//....
//My #required protocol method which never gets called since my delegate is nil
-(void) passAlarmsArray:(NSMutableArray *)theAlarmsArray
{
alarmsTableArray = theAlarmsArray;
NSLog(#"alarmsTableArray contains: %#", alarmsTableArray); // Never gets called due to delegate being nil
NSLog(#"theAlarmsArray contains: %#", theAlarmsArray); // Never gets called due to delegate being nil
}
#end
I've attempted to set the delegate in a method that fires when a button is pressed in AlarmViewController (as opposed to the viewDidLoad method) but that does not work either.
I'm assuming I've got a logic flow error somewhere here . . . but nearly 2 days of hunting and rebuilds haven't uncovered it. Ugh.
You're setting your delegate in the wrong place, and on a different instance of the controller than the one you will get when you do the segue. You should set the delegate in the prepareForSegue method if you're pushing AlarmDetailsViewController from AlarmViewController
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
AlarmDetailsViewController *alarm = segue.destinationViewController;
alarm.passAlarmsArrayDelegate = self;
}
You really need to understand the life cycle of view controllers, how and when they're instantiated, and when they go away. This is the very heart of iOS programming, and Apple has extensive documentation on it. Reading up on segues would also be very useful. A segue (other then an unwind segue) always instantiates a new instance of the destination controller. So, when your segue is performed, whether directly from a button, or in code, a new (different from the one you alloc init'd directly) details controller is instantiated. Before that segue is performed, prepareForSegue: is called, and that's when you have access to the one about to be created. That's the place to set a delegate or pass any information on to the destination view controller.
Did you try replace (nonatomic, retain) with (nonatomic, strong) since you are using ARC?
Auto-synthesized properties like your alarmDetailsViewController property have backing ivars prefixed with underscores, e.g. _alarmDetailsViewController. Your alarmDetailsViewController ivar (the alarmDetailsViewController declared inside the #interface ... {} block in AlarmViewController.h) is different from the backing ivar of your alarmDetailsViewController property.
Just delete your alarmDetailsViewController ivar and use the #property, preferably through self.alarmDetailsViewController.
This question already has answers here:
How do I create delegates in Objective-C?
(20 answers)
Closed 9 years ago.
What is a "delegate" in Objective C's iPhone development?
A delegate is a pointer to an object with a set of methods the delegate-holder knows how to call. In other words, it's a mechanism to enable specific callbacks from a later-created object.
A good example is UIAlertView. You create a UIAlertView object to show a short message box to users, possibly giving them a choice with two buttons like "OK" and "Cancel". The UIAlertView needs a way to call you back, but it has no information of which object to call back and what method to call.
To solve this problem, you can send your self pointer to UIAlertView as a delegate object, and in exchange you agree (by declaring the UIAlertViewDelegate in your object's header file) to implement some methods that UIAlertView can call, such as alertView:clickedButtonAtIndex:.
Check out this post for a quick high-level intro to the delegate design pattern and other callback techniques.
References:
UIAlertView class reference
UIAlertViewDelegate class reference
Apple's guide to Delegates and Data sources
See this discussion
A delegate allows one object to send messages to another object when an event happens. For example, if you're downloading data from a web site asynchronously using the NSURLConnection class. NSURLConnection has three common delegates:
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
One or more of these delegates will get called when NSURLConnection encounters a failure, finishes successfully, or received a response from the web site, respectively.
Delegates are a design pattern; there is no special syntax or language support.
A delegate is just an object that another object sends messages to when certain things happen, so that the delegate can handle app-specific details the original object wasn't designed for. It's a way of customizing behavior without subclassing.
I think this Wikipedia article describes it best: http://en.wikipedia.org/wiki/Delegation_pattern
It is "just" an implementation of a design pattern and very common in Objective-C
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.
I try to elaborate it through simple program
Two Classes
Student.h
#import <Foundation/Foundation.h>
#interface Student : NSObject
#property (weak) id delegate;
- (void) studentInfo;
#end
Student.m
#import "Student.h"
#implementation Student
- (void) studentInfo
{
NSString *teacherName;
if ([self.delegate respondsToSelector:#selector(teacherName)]) {
teacherName = [self.delegate performSelector:#selector(teacherName)];
}
NSLog(#"\n Student name is XYZ\n Teacher name is %#",teacherName);
}
#end
Teacher.h
#import <Foundation/Foundation.h>
#import "Student.h>
#interface Teacher: NSObject
#property (strong,nonatomic) Student *student;
- (NSString *) teacherName;
- (id) initWithStudent:(Student *)student;
#end
Teacher.m
#import "Teacher.h"
#implementation Teacher
- (NSString *) teacherName
{
return #"ABC";
}
- (id) initWithStudent:(Student *)student
{
self = [ super init];
if (self) {
self.student = student;
self.student.delegate = self;
}
return self;
}
#end
main.m
#import <Foundation/Foundation.h>
#import "Teacher.h"
int main ( int argc, const char* argv[])
{
#autoreleasepool {
Student *student = [[Student alloc] init];
Teacher *teacher = [[Teacher alloc] initWithStudent:student];
[student studentInfo];
}
return 0;
}
EXPLANATION :::
From main method when initWithStudent:student will execute
1.1 Teacher's object's property 'student' will be assigned with student object.
1.2 self.student.delegate = self
means student object's delegate will points to teacher object
From main method when [student studentInfo] will be called
2.1 [self.delegate respondToSelector:#selector(teacherName)]
Here delegate already points to teacher object so it can invoke
'teacherName' instance method.
2.2 so [self.delegate performSelector:#selector(teacherName)]
will execute easily.
It looks like Teacher object assign delegate to student object to call it's own method.
It is a relative idea, where we see that student object called 'teacherName' method but it is basically done by teacher object itself.
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).
Here is the sample code may help you.
AppDelegate.h
#import <UIKit/UIKit.h>
#class FirstViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) FirstViewController *firstViewController;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "FirstViewController.h"
#implementation AppDelegate
#synthesize firstViewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
//create instance of FirstViewController
firstViewController = [[FirstViewController alloc] init];
//create UINavigationController instance using firstViewController
UINavigationController *firstView = [[UINavigationController alloc] initWithRootViewController:firstViewController];
//added navigation controller to window as a rootViewController
self.window.rootViewController = firstView;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (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.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
#end
FirstViewController.h
#import <UIKit/UIKit.h>
#import "SecondViewController.h"
#interface FirstViewController : UIViewController<MyDelegate>
#property (nonatomic, retain) NSString *mesasgeData;
#property (weak, nonatomic) IBOutlet UITextField *textField;
#property (weak, nonatomic) IBOutlet UIButton *nextButton;
- (IBAction)buttonPressed:(id)sender;
#property (nonatomic, strong) SecondViewController *secondViewController;
#end
FirstViewController.m
#import "FirstViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
#synthesize mesasgeData;
#synthesize textField;
#synthesize secondViewController;
#pragma mark - View Controller's Life Cycle methods
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Button Click event handling method
- (IBAction)buttonPressed:(id)sender {
//get the input data from text feild and store into string
mesasgeData = textField.text;
//go keypad back when button clicked from textfield
[textField resignFirstResponder];
//crating instance of second view controller
secondViewController = [[SecondViewController alloc]init];
//it says SecondViewController is implementing MyDelegate
secondViewController.myDelegate = self;
//loading new view via navigation controller
[self.navigationController pushViewController:secondViewController animated:YES];
}
#pragma mark - MyDelegate's method implementation
-(NSString *) getMessageString{
return mesasgeData;
}
#end
SecondViewController.h
//declare our own delegate
#protocol MyDelegate <NSObject>
-(NSString *) getMessageString;
#end
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *messageLabel;
#property (nonatomic, retain) id <MyDelegate> myDelegate;
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize messageLabel;
#synthesize myDelegate;
- (void)viewDidLoad
{
[super viewDidLoad];
messageLabel.text = [myDelegate getMessageString];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
The delegate fires the automatic events in Objects C. If you set the delegate to Object, it sends the message to another object through the delegate methods.
It's a way to modify the behavior of a class without requiring subclassing.
Each Objects having the delegate methods.These delegate methods fires, when the particular Objects take part in user interaction and Program flow cycle.
Simply stated: delegation is a way of allowing objects to interact with each other without creating strong interdependencies between them.
A delegate captures the taping actions of an user and performs particular Action according to the user Taping Action.
Delegate is nothing but instance of Object which we can call methods behalf of that Objects. and also helps to create methods in rumtime of that Objects.