How do delegates work in objective c? - ios

I'm trying to figure out delegates because I really need them for a project I'm working on, but for the life of me, I can't figure them out. No matter how much I tweak the code, nothing works
ViewController.h:
#import <UIKit/UIKit.h>
#class ViewController;
#protocol testDelegate
-(void)sayHi;
#end
#interface ViewController : UIViewController
- (IBAction)button:(id)sender;
#property (weak, nonatomic)id <testDelegate> delegate;
#end
ViewController.m:
#import "ViewController.h"
#import "DelegateController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
DelegateController *dc = [[DelegateController alloc] init];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)button:(id)sender {
[self.delegate sayHi];
}
#end
DelegateController.h:
#import "ViewController.h"
#interface DelegateController : UIViewController <testDelegate>
#end
DelegateController.m:
#import "DelegateController.h"
#interface DelegateController ()
#end
#implementation DelegateController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
NSLog(#"init");
ViewController *vc = [[ViewController alloc] init];
[vc setDelegate:self];
}
return self;
}
-(void)viewDidLoad
{
[super viewDidLoad];
}
-(void)sayHi
{
NSLog(#"hi");
}
#end
The - (IBAction)button:(id)sender method is connect to a button, but when clicked I get no output. What am I doing wrong?

ViewController.h:
#import <UIKit/UIKit.h>
#protocol testDelegate
-(void)sayHi;
#end
#interface ViewController : UIViewController
#end
ViewController.m:
#import "ViewController.h"
#import "DelegateController.h"
#interface ViewController () <testDelegate>
#end
#implementation ViewController
- (IBAction)pushNewViewController:(id)sender
{
DelegateController *dc = [[DelegateController alloc] init];
dc.delegate = self;
[self.navigationController pushViewController:dc animated:YES];
}
- (void)sayHi
{
NSLog(#"It works!");
}
#end
DelegateController.h:
#import "ViewController.h"
#interface DelegateController : UIViewController
#property (weak, nonatomic) id<testDelegate> delegate;
#end
DelegateController.m:
#import "DelegateController.h"
#implementation DelegateController
- (IBAction)button:(id)sender
{
if([_delegate respondsToSelector:#selector(sayHi)]) {
[_delegate performSelector:#selector(sayHi)];
}
}
#end

Try this:
ViewController.h
#import <UIKit/UIKit.h>
#class ViewController;
#protocol testDelegate
-(void)sayHi;
#end
#interface ViewController : UIViewController
- (IBAction)button:(id)sender;
#property (weak, nonatomic)id <testDelegate> delegate;
#end
ViewController.m
#import "ViewController.h"
#import "DelegateController.h"
#interface ViewController ()
#property (nonatomic, strong) DelegateController *dc;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_dc = [[DelegateController alloc] init];
[self setDelegate:_dc];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)button:(id)sender
{
[self.delegate sayHi];
}
#end
DelegateController.h
#interface DelegateController : UIViewController <testDelegate>
#end
DelegateController.m
#import "DelegateController.h"
#interface DelegateController ()
#end
#implementation DelegateController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
NSLog(#"init");
}
return self;
}
-(void)viewDidLoad
{
[super viewDidLoad];
}
-(void)sayHi
{
NSLog(#"hi");
}
#end

Your problem is that ViewController creates DelegateController, then in DelegateController you're creating a new, different, instance of ViewController, and setting yourself as the delegate of that instance. Normally, the way you set a delegate is that DelegateController would create an instance of ViewController and set itself as the delegate. This assumes that DelegateController is created first, but exactly how to do this depends on your app structure, and how you move from controller to controller.

Replace you button Click method with following
- (IBAction)button:(id)sender {
// Check whether your Delegate method is implemeted or not
if([delegate respondsToSelector:#selector(sayHi)])
{
// Call Delegate Method
[delegate performSelector:#selector(sayHi)];
}
}

Related

Why is my delegate method not called in a storyboard?

I have two UIViewControllers embedded in a UINavigationController. The first view controller has the following source code :
ViewController.h :
#import <UIKit/UIKit.h>
#import "ViewController_2.h"
#interface ViewController : UIViewController <HanselDelegate>
#property (strong, nonatomic) IBOutlet UILabel *TestLabel;
- (IBAction)ButtonClick:(id)sender;
#end
ViewController.m :
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)ButtonClick:(id)sender {
NSLog(#"To call the second UIViewController...");
[self performSegueWithIdentifier:#"idCallSecond" sender:self];
}
-(void)SetFirstLabel {
NSLog(#"To run the delegate method...");
_TestLabel.text = #"Hello from the second...";
}
#end
The second controller has the following code:
ViewController2.h :
#import <UIKit/UIKit.h>
#protocol HanselDelegate <NSObject>
-(void)SetFirstLabel;
#end
#interface ViewController_2 : UIViewController
#property (nonatomic, weak)id<HanselDelegate> delegate;
- (IBAction)Button2Click:(id)sender;
#end
ViewController2.m:
#import "ViewController_2.h"
#interface ViewController_2 ()
#end
#implementation ViewController_2
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)Button2Click:(id)sender {
if ([self.delegate respondsToSelector:#selector(SetFirstLabel)]) {
NSLog(#"To call the delegate method");
[self.delegate SetFirstLabel];
}
[self.navigationController popViewControllerAnimated:YES];
}
#end
If I press the button in ViewController2, the method SetFirstLabel doesn't get called. Why is it so? Did I forgot something?
You forgot to set the delegate in ViewController.m
set this in ViewController.m
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"idCallSecond"]) {
ViewController_2 * vc2 = [segue destinationViewController];
vc2.delegate = self;
}
}

UIBarButtonItem Cancel does not work

I want to cancel the second view controller with a UIBarButtonItem, but I just don't get the code right. Please help.
Viewcontroller.h
#import <UIKit/UIKit.h>
#import "SecondViewController.h"
#interface ViewController : UIViewController <SecondViewControllerDelegate>
#end
Viewcontroller.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.destinationViewController isKindOfClass:[SecondViewController class]]) {
SecondViewController *vc2 = segue.destinationViewController;
vc2.delegate = self;
}
}
-(void)dismissViewController
{
NSLog(#"dismissed");
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
Secondviewcontroller.h
#import <UIKit/UIKit.h>
#protocol SecondViewControllerDelegate <NSObject>
- (void) dismissViewController;
#end
#interface SecondViewController : UIViewController
#property (weak, nonatomic) id <SecondViewControllerDelegate> delegate;
- (IBAction)backBarButtonItemPressed:(UIBarButtonItem *)sender;
#end
BackbarButton means cancelbutton
Secondviewcontroller.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)backBarButtonItemPressed:(UIBarButtonItem *)sender {
[self.delegate dismissViewController];
}
#end
You can dismiss in secondViewController,I do not see the meaning of Delegate in your code
- (IBAction)backBarButtonItemPressed:(UIBarButtonItem *)sender {
[self dismissViewControllerAnimated:true completion:nil];
}
If you use show segue,and you have a navigationController with these two ViewControllers,Use
- (IBAction)dismiss:(id)sender {
[self.navigationController popViewControllerAnimated:true];
}

accessing IBOutlet properties from another class

How do I access IBOutlets that have been created in another class?
here is my code...
Class one
.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (retain, readwrite) IBOutlet UIView *myView;
#end
.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize myView;
- (void)viewDidLoad {
[super viewDidLoad];
}
#end
Class two
.h
#import <UIKit/UIKit.h>
#interface ViewController2 : UIViewController
- (IBAction)accion:(id)sender;
- (IBAction)btnBack:(id)sender;
#end
.m
#import "ViewController.h"
#import "ViewController2.h"
#interface ViewController2 ()
#end
#implementation ViewController2
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)accion:(id)sender {
ViewController *a = [ViewController new];
UIView *someView = [a myView];
[someView setBackgroundColor:[UIColor redColor]];
}
- (IBAction)btnBack:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
why not works? no change the backgroundColor when return on my view
I think you try to delegate pattern to set the values Viewcontroller2.h file
Add protocol like this...
#import <UIKit/UIKit.h>
#protocol tutorialDelegate <NSObject> //set protocol
-(void)delegatesDescribedWithDescription;
#end
#interface ViewController2 : UIViewController
#property (weak, nonatomic) id<tutorialDelegate> tutorialDelegate1;
- (IBAction)accion:(id)sender;
- (IBAction)btnBack:(id)sender;
#end
after the declaring protocol in viewcontroller2.m file first synthesize and call method like this..
#import "ViewController.h"
#interface ViewController2 ()
#end
#implementation ViewController2
#synthesize tutorialDelegate1; // synthesize here
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)accion:(id)sender {
ViewController *a = [ViewController new];
UIView *someView = [a myView];
[someView setBackgroundColor:[UIColor redColor]];
}
- (IBAction)btnBack:(id)sender {
// Here we tell delegate to invoke method in parent view.
[self.tutorialDelegate1 delegatesDescribedWithDescription
];
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
and finally we implement this method in view controller.m file but first set delegate in viewcotroller.h file like this...
#import <UIKit/UIKit.h>
#import "ViewController2.h" //import here
#interface ViewController : UIViewController <tutorialDelegate> //set delegate
#property (retain, readwrite) IBOutlet UIView *myView;
#end
and viewcontroller.m file
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize myView;
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"yourIdentifier"]) {
ViewController2 *detailViewController =
segue.destinationViewController;
// here we set the ViewController to be delegate in
// detailViewController
detailViewController.tutorialDelegate1 = self;
}
}
// ViewController must implement tutorialDelegate's methods
// because we specified that ViewController will conform to
// tutorialDelegate protocol
-(void)delegatesDescribedWithDescription
{ // here your code please
viewTemp.backgroundColor =[UIColor redColor];
}
#end

Make some calculation on Viewcontroller, need show the result to another Viewcontroller

I have an app, where I making some calculation, and need to transfer result of this calculation to ViewController3 and show the result there. Now I use label in same ViewController2 where I have calculation. Thank you for your help.
ViewController2.h
#import <UIKit/UIKit.h>
#interface ViewController2 : UIViewController<UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UILabel *gasPrice;
#property (weak, nonatomic) IBOutlet UILabel *gasCarMileage;
#property (weak, nonatomic) IBOutlet UITextField *perGalon;
#property (weak, nonatomic) IBOutlet UITextField *miles;
#property(nonatomic, copy, readonly) NSString *result;
- (IBAction)getIt:(id)sender;
#end
ViewController2.m
#import "ViewController2.h"
#import "ViewController3.h"
#interface ViewController2 ()
#end
#implementation ViewController2
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
//Start calculation
- (IBAction)getIt:(id)sender; {
float perGalon = ([_perGalon.text floatValue]);
float miles = ([_miles.text floatValue]);
float mileCost = perGalon / miles;
[self performSegueWithIdentifier:#"viewController3" sender: nil];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"viewController3"]) {
ViewController3 *viewController3 = [segue destinationViewController];
viewController3.result = [[NSString alloc] initWithFormat: #"Every mile you drive
will cost you $ %f", mileCost];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.perGalon.delegate = self;
self.miles.delegate = self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
return [textField resignFirstResponder];
}
#end
ViewController3.h
#import <UIKit/UIKit.h>
#interface ViewController3 : UIViewController
#property(nonatomic, copy) NSString *result;
#end
ViewController3.m
#import "ViewController3.h"
#import "ViewController2.h"
#interface ViewController3 ()
#end
#interface ViewController2 ()
#property(nonatomic, copy, readwrite) NSString *result;
#end
#implementation ViewController3
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
You can define a string property in View controller 3 which you will set when you push view controller 3 from view controller 2.
ViewController3 interface declaration
#interface ViewController2 ()
#property(nonatomic, copy) NSString *result;
#end
In ViewController 2, you will implement this line at the last of your getIt() method.
[self performSegueWithIdentifier:#"viewController3" sender: nil]
And implement another method called prepareForSegue as follows
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"viewController3"]) {
ViewController3 *viewController3 = [segue destinationViewController];
viewController3.result = "YOUR CALCULATION RESULT HERE"
}
}
Bear in mind, you have to set identifier for view controller 3, go to storyboard and select the view for view controller 3 and On identify inspector, specified Storyboard ID as "viewController3".
Use a protocol,
In ViewController2.h
#protocol ViewController2Delegate;
#property (strong, nonatomic) id<ViewController2Delegate> delegate;
#protocol BexAPIClientDelegate <NSObject>
- (void)ViewController2:(ViewController2 *)vc didCalculateCost:(CGFloat)cost;
#end
Then at the end of the getIt() call the delegate
[self.delegate viewController2:self didCalculateCost:gasCostPerMile];
You need to set ViewController3 to be ViewController2's delegate when you load it. Also you will need to setup ViewController3 to conform to the protocol.
Using the protocol is worth the effort as it will make your code clear and easy to manage.
Retain a string in VC3. While initializing the VC3 object, set the value from VC2. Update the label in VC3(in viewDidLoad method)

Show image in ViewController when button is clicked in SecondViewController

How to show an UIIimage by clicking on an UIButton inside another UIViewController? I would like to add to the same UIButton the command to add an image to the SecondViewController. Excused my poor question.
myProtocol.h
#import <Foundation/Foundation.h>
#protocol myProtocol <NSObject>
-(UIImage *)transferImage;
#end
ViewController.h
#import "SecondClass.h"
#interface ViewController : UIViewController<myProtocol, UINavigationControllerDelegate>{
UIView *view;
}
#property (nonatomic,retain) UIImageView *imageView;
- (IBAction)sendImage:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#import "SecondViewController.h"
#import "myProtocol.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad{
[super viewDidLoad];
_imageView = [[UIImageView alloc]initWithImage:
[UIImage imageNamed:#"VoodooVibe#2x.png"]];
[view addSubview:_imageView];
NSLog(#"I am in VC.m");
}
-(UIImage *)transferImage{
NSLog(#"I am in transferImage");
return _imageView.image;
}
- (IBAction)sendImage:(id)sender {
SecondViewController *secClass = [[SecondViewController alloc]init];
secClass.delegate=self;
[secClass callTransfer];
NSLog(#"I am in sender");
[self.navigationController pushViewController:secClass animated:YES];
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#import "myProtocol.h"
#import "ViewController.h"
#interface SecondViewController :UIViewController
<myProtocol,UINavigationControllerDelegate> {
UIView *secondView;
IBOutlet UIImageView *myImage;
id <myProtocol> myDelegate;
}
#property (nonatomic,retain) UIImageView *myImage;
#property(nonatomic,assign) id delegate;
-(void)callTransfer;
#end
SecondViewController.m
#import "SecondViewController.h"
#import "ViewController.h"
#import "myProtocol.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize delegate,myImage;
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view.
[secondView addSubview:myImage];
}
-(void)callTransfer{
myImage.image=[delegate performSelector:#selector(transferImage)];
myImage.image=[UIImage imageNamed:#"VoodooVibe#2x.png"];
NSLog(#"%#",myImage.image);
NSLog(#"I am in call transfer");
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Delegates should normally be used, if you you have a class included inside your UIViewController which will do something and notify you with the delegate method when the specific process has finished. But in this case you would set an UIImage two times. Once by your delegate and a second time by setting an UIImage programmatically.
You shouldn't do anything like calling a method for initializing the UIImage of the second UIViewController from outside. Just call everything inside viewDidLoad and you don't have to care about it, because the UIViewController handles it itself.
You just have to insert an UIImageView inside your SecondViewController and connect it to your header file. then you can access it inside the m. file. I had the problem that I first used a jpg instead of a png, but after changing the suffix everything worked fine.
ViewController.m
- (IBAction)sendImage:(id)sender {
SecondViewController *secClass = [[SecondViewController alloc] init];
[secClass setImageName:#"pic.png"];
[self.navigationController pushViewController:secClass
animated:YES];
}
SecondViewController.h
#interface SecondViewController : UIViewController
#property (strong, nonatomic)NSString *imageName;
#property (weak, nonatomic) IBOutlet UIImageView *myImage;
#end
SecondViewController.m (There are just these two lines)
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[_myImage setImage:[UIImage imageNamed:_imageName]];
}

Resources