Skizz
Skizz

Reputation: 1271

Where do I put delegate methods and how do I invoke them?

As a new iOS developer, I have finally stumbled across delegates. I'm trying to follow a tutorial: http://gabriel-tips.blogspot.com/2011/05/input-accessory-view-how-to-add-extra.html, But I'm having difficulty understanding where I am supposed to put the actual delegate methods.

Secondly, would anyone mind providing a dumbed down explanation of how a delegate method is invoked?

Thanks!

Upvotes: 0

Views: 152

Answers (3)

SushiGrass Jacob
SushiGrass Jacob

Reputation: 19834

A delegate pattern is a convenient way to allow for the communication between independent controller that allows for loose coupling. So let's say you have a pattern like this:

        A
       / \
      B   C

Where A instantiates B and C. Communicating between A to B and A to C are easy but how would you communicate between B and C? B to A? C to A? There are a couple different ways you could do so such as Key-Value Observing or Block Callbacks. Delegation, though, are still most frequently used although Blocks are coming on strong.

In this example, object A instantiates object B to create an object and fill it with info. How would object B pass the new object back to A as you want to keep things loose? Well, with these 9 easy steps, you can do it too! It may not make sense but we'll start with ClassB…

// ClassB.h

@protocol ClassBDelegate; //(1)

@interface ClassB : NSObject

@property (nonatomic, weak) id<ClassBDelegate>bDelegate; //(2)

-(void)makeNewObjectAndSendBack;

@end

@protocol ClassBDelegate : NSObject //(3)

-(void) classB:(Class B *)theClassB finishedWithObject:(id)finishedObject; //(4)

@end

ClassB.m
@implementation
@synthesize bDelegate = _bDelegate; //(5)

-(void)makeNewObjectAndSendBack {

//something something something
[self.bDelegate classB:self finishedWithObject:newObject]; //(6)

}

@end
  1. define the protocol that will be established later
  2. set an instance of an object that will conform to that protocol
  3. set up the protocol
  4. set up the method call that you'll use to send the finishedObject back to A.
  5. synthesize the delegate
  6. after you do what you need to do, you send it back using the method you defined in 4

// ClassA.h

@interface ClassA : NSObject <ClassBDelegate> //(7)

@property (nonatomic, strong) ClassB theClassB;

-(void)yourMethodToDoSomething;

@end

ClassA.m
@implementation
@synthesize theClassB = _theClassB; 

-(void)randomMethod {

self.theClassB = [ClassB new];
self.theClassB.bDelegate = self; //(8)
[self.theClassB makeNewObjectAndSendBack];

}

-(void) classB:(Class B *)theClassB finishedWithObject:(id)finishedObject { //(9)
[self doSomethingWithFinishedObject:finishedObject]; //ta-da!
}

@end

7.Conform to the ClassBDelegate protocol. This basically says that you will implement the methods defined in the protocol definition.

8.Set the classB object's delegate object as self! This is crucial and often skipped.

9.Implement the delegate method for when you get the new object back.

So the process, in short is: A instanciate B. A sets B's delegate as self. A tells B to do something. B does something and sends object back via delegate method. A gets it back.

For more information, including what you can do with protocols, check out: Big Nerd Ranch talk about Protocols Part 1 Part 2 Part 3

Good luck!

Upvotes: 1

sc0rp10n
sc0rp10n

Reputation: 1118

A delegate is simply a class that agrees to do work for another class. The delegate methods are invoked by the delegating class. The delegate must therefore, provide an implementation of the appropriate method. Let's make a simple view controller with a table view.

// MyViewController.h
@interface MyViewController : UIViewController <UITableViewDelegate>
@property (nonatomic, retain) UITableView *myTableView;
@end

Here in the MyViewController.h file I have declared my view controller to be a delegate of type UITableViewDelegate (it really means it implements the UITableViewDelegate protocol. More on this later). I have thus agreed to respond to requests to my view controller. The requests will come from the table view called myTableView. However, simply stating that I adhere to UITableViewDelegate does not make my view controller a delegate of anything. I must specify that directly:

// MyViewController.m
#import "MyViewController.h"

@implementation MyViewController

- (void)loadView
{
    myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
    myTableView.delegate = self;
    self.view = myTableView;
}

@end

Here I specifically set MyViewController to be the delegate of myTableView. Now whenever the table view wants to ask its delegate to do something, it will send that message to my view controller. Thus, MyViewController MUST provide implementations of the appropriate delegate methods:

// MyViewController.m
#import "MyViewController.h"

@implementation MyViewController

- (void)loadView
{
    myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
    myTableView.delegate = self;
    self.view = myTableView;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"Selected section:%i row:%i", indexPath.section, indexPath.row);
}

@end

Here I have provided an implementation for the delegate method tableView:didSelectRowAtIndexPath: which will be called by myTableView when it is appropriate (the user selects a row).

Here you can find all the delegate methods defined in UITableViewDelegate. Some are required and others are optional:

http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UITableViewDelegate_Protocol/Reference/Reference.html

In order to be a delegate of a class you should know which methods you are required to provide implementations for.

If you wanted to create your own delegate definitions, you would create a new protocol. You do not retain your delegates (see the property declaration), as this creates a retain cycle:

// MyViewController.h
@class MyViewController;

@protocol MyViewControllerDelegate
- (void)viewController:(MyViewController *)viewController didChangeSelection:(NSIndexPath *)newIndexPath;
@end

@interface MyViewController : UIViewController <UITableViewDelegate>
@property (nonatomic, retain) UITableView *myTableView;
@property (nonatomic, assign) id<MyViewControllerDelegate> delegate;
@end

Here we have created a new protocol. Any class that wants to be respond to the viewController:didChangeSelection: message could now do so. Just like with the table view above it would set the delegate to itself and then implement the method. Now that you have a delegate, you can invoke the method at an appropriate time.

// MyViewController.m
#import "MyViewController.h"

@implementation MyViewController

- (void)loadView
{
    myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
    myTableView.delegate = self;
    self.view = myTableView;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"Selected section:%i row:%i", indexPath.section, indexPath.row);

    indexPath = [NSIndexPath indexPathForRow:1 inSection:0];
    [self.delegate viewController:self didChangeSelection:indexPath];
}

@end

Now the delegate can receive the message and do what it wants knowing that my view controller changed the selection.

Upvotes: 1

Simon Goldeen
Simon Goldeen

Reputation: 9080

It seems you might be a little confused as to what delegates are and how they are used. Here are two links to Apple documentation you might find useful: A conceptual overview and a more in depth explaination.

Upvotes: 0

Related Questions