[Objective-C] Cocoa's Target-Action Pattern

转载 2015年07月10日 16:26:43


Despite being a thin wrapper on top of C, Objective-C has dynamic features that make it feel more like a peer to Ruby than to C++. In this short article, I’ll introduce one of those features and show you how to use it in your code to reduce coupling and increase reuse.


A selector is essentially the name of an Objective-C method, realized as an object in code. It has the type SEL, which is a primitive (no memory management needed). The actual contents of the selector are opaque, but you can get one from a method name with the @selector() syntax.

SEL setToolbar = @selector(setToolbarItems:animated:);

You can also get a selector from an NSString. This is handy if you want to store the selector in a config file.

SEL setToolbar = NSSelectorFromString(@"setToolbarItems:animated:");

Using Selectors

Once you have the selector, there’s a few things you can do with it.

You can ask an object if it responds to that selector; this is like asking if the object implements this method. If you’ve ever done reflection in Java, prepare for a breath of fresh air!

if ([controller respondsToSelector:@selector(setToolbarItems:animated:)]) {
  /* it's possible to set toolbar items on this controller */

You can ask an object to perform that selector:

// direct
[controller viewDidLoad];

// indirect
SEL action = @selector(viewDidLoad);
[controller performSelector:action];

This is the same as calling the method directly, but because the selector could come from a variable, it’s possible to change the method at runtime.

For example, UIBarButtonItem uses a target and action to call your code when the button is tapped. You might have some code in your view controller like this:

- (void)viewDidLoad
  button = [[UIBarButtonItem alloc] initWithTitle:@"Done"
  // more code

- (void)doneButtonHit:(id)sender
  NSLog(@"The done button was tapped!");

When you run the app and tap on the button, you’ll see “The done button was tapped!” in the console. It’s as if the button has a line of code like [controller doneButtonHit:self], but obviously it doesn’t: the button is a generic object that you can use off-the-shelf. The secret sauce is performSelector!

This pattern, called “target-action”, is used throughout Cocoa, especially in user interface code. It allows the UI widgets to stay generic, while making it easy to integrate your custom controller without needing to subclass anything.

Implementing Target-Action

Let’s write a really simple object that implements the target-action pattern. We’ll call it a button, but we’ll skip writing any view-related code. For simplicity, let’s assume that when the user taps on the button, the button will receive the tapmessage.

Here’s our interface.

@interface JVButton : NSObject {
  id _target;
  SEL _action;

- (void)initWithTarget:(id)target action:(SEL)action;

- (void)tap;


And here’s the implementation.

@implementation JVButton

- (void)initWithTarget:(id)target action:(SEL)action
  self = [super init];
  if (self) {
    _target = target;
    _action = action;
  return self;

- (void)tap
  [_target performSelector:_action withObject:self];


The init method is simple, just some vanilla setup. We store the target and action for later. Notice that we don’t retain the target.

In the tap method, we ask the target to perform the action. We also pass the button as an argument to the action. There’s a bunch of variations on the basicperformSelector: method to help with things like passing arguments or delaying before performing: check Apple’s documentation for all of them.

The controller wired up to this button might look like this:

- (void)viewDidLoad
  button = [[JVButton alloc] initWithTarget:self action:@selector(customButtonTapped:)];

- (void)customButtonTapped:(id)sender
  NSLog(@"The custom button was tapped!");

If you look back at the example with UIBarButtonItem, you’ll see that they’re almost identical! Mimicking Apple’s code is easier than it sounds, right? :)

When to Use Target-Action

The best time to reach for this pattern is when:

  • You need or want one object to stay generic (e.g., the button class) but be able to call into custom code.
  • The generic object has exactly one action to perform (e.g., being tapped).

If the generic object has more than one action to perform, or needs to collect information from your custom code, your problem is probably better solved with the delegate pattern or the data source pattern.


// ======= MyButton.h ======

#import <Foundation/Foundation.h>

@interface MyButton : NSObject

@property id target;

@property SEL action;

-(id) initWithTarget:(id)target withAction:(SEL)action;

-(void) tap;


// ======= MyButton.m ======

#import "MyButton.h"

@implementation MyButton

-(id) initWithTarget:(id)target withAction:(SEL)action {
    _target = target;
    _action = action;
    return self;

-(void) tap {
    [_target performSelector:_action withObject:self];


// ======= MyViewController.h ======

#import <Cocoa/Cocoa.h>
#import "MyButton.h"

@interface MyViewController : NSObject

@property MyButton* button;

-(id) init;

-(void) customButtonTapped:(id)sender;

-(void) tapButton;


// ======= MyViewController.m ======

#import "MyViewController.h"

@implementation MyViewController

-(id) init {
    if (self = [super init]) {
        _button = [[MyButton alloc] initWithTarget:self withAction:@selector(customButtonTapped:)];
    return self;

-(void) customButtonTapped:(id)sender {

-(void) tapButton {
    if (_button) {
        [_button tap];


// ======= main.m ======

#import <Foundation/Foundation.h>
#import "MyViewController.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        MyViewController* view = [[MyViewController alloc] init];
        [view tapButton];
    return 0;




深入探究 Objective-C Target Point

Tagged Pointer 介绍苹果对于Tagged Pointer特点的介绍: Tagged Pointer专门用来存储小的对象,例如NSNumber和NSDate Tagged Pointer指...

Objective-C Singleton Pattern

根据该文章写了一篇关于iOS单例模式的文章:http://duckrowing.com/2010/05/21/using-the-singleton-pattern-in-objective-c/ 单...

iPhone开发入门(6)--- Action与Objective-C

我们先来分析一下上一回初次接触的Objective-C代码。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ...


  • 2016-07-23 11:11
  • 36.29MB
  • 下载



Objective-C 之 @property和@synthesize