Examples of message forwarding in Objective-C
From Wikipedia, the free encyclopedia
Below are examples of message forwarding in the Objective-C programming language.
Contents |
[edit] Observer design pattern
Objective-C forwarding capability can allow for implementation for a design pattern such as the observer pattern. Here is one simple implementation of the design pattern.
[edit] Notifiable.h
@protocol Notifiable - (id) notify: (id) obj; @end
[edit] Observer.h
#import <objc/Object.h> #import <stdlib.h> #import "Notifiable.h" #define MAX_LISTENERS 5 @interface Observer : Object { id <Notifiable> *listeners; } - (id) subscribe: (id <Notifiable>) object; @end;
[edit] Observer.m
#import "Observer.h" @implementation Observer - (id) init { /* * Allocate array of listeners. This may be better implemented by a * stack, but we're just illustrating the concept here, so we just * use an array */ listeners = malloc(sizeof(id)*MAX_LISTENERS); memset(listeners, '\0', MAX_LISTENERS); return self; } - (retval_t) forward: (SEL) sel : (arglist_t) args { /* * The forwarding method. */ id <Notifiable> *ptr; retval_t temp; for(ptr = listeners; *ptr; ptr++) { /* * The performv:: method, provided by Object (and thus all objects) * executes an object's method based on a selector an arguments. */ id <Notifiable> element = *ptr; if([element respondsTo:sel] ) [element performv: sel : args]; else [element error:"Unrecognized message sent via Observer"]; } return temp; } - (id) subscribe: (id <Notifiable>) object; { id <Notifiable> *ptr; int i=0; // Find the next null slot for(ptr = listeners; *ptr; ++ptr) ++i; if(i == MAX_LISTENERS) [self error: "Maximum number of listeners reached"]; *ptr = object; return self; } @end
[edit] Subject.h
#import <objc/Object.h> #import "Observer.h" @interface Subject : Object //no pun intended { int value; Observer *observer; } - (int) value; - (id) value: (int) _value; - (Observer *) observer; - (id) observer: (Observer *) _observer; @end
[edit] Subject.m
#import "Subject.h" #import "Observer.h" @implementation Subject - (int) value { return value; } - (id) value: (int) _value { value = _value; (void)[observer notify: self]; return self; } - (Observer *) observer; { return observer; } - (id) observer: (Observer *) _observer { observer = _observer; return self; } @end
[edit] Viewer1.h
#import <objc/Object.h> #import "stdio.h" #import "Notifiable.h" @interface Viewer1 : Object <Notifiable> { int local_val; } - (id) notify: (id) object; @end
[edit] Viewer1.m
#import "Viewer1.h" #import "Subject.h" @implementation Viewer1 - (id) notify: (id) subject; { int i; local_val = [subject value]; printf("Viewer1: "); for(i=0; i < local_val; i++) printf("*"); printf("\n"); return self; } @end
[edit] Viewer2.h
#import <objc/Object.h> #import "stdio.h" #import "Notifiable.h" @interface Viewer2 : Object <Notifiable> { int local_val; } - (id) notify: (id) subject; @end
[edit] Viewer2.m
#import "Viewer2.h" #import "Subject.h" @implementation Viewer2 - (id) notify: (id) subject { local_val = [subject value]; printf("Viewer2: %d\n", local_val); return self; } @end
[edit] main.c
#import "Observer.h" #import "Subject.h" #import "Viewer1.h" #import "Viewer2.h" int main(void) { Observer *observer = [Observer new]; Viewer1 *viewer1 = [Viewer1 new]; Viewer2 *viewer2 = [Viewer2 new]; Subject *subject = [Subject new]; [[observer subscribe:viewer1] subscribe:viewer2]; [subject observer:observer]; while(1) { int x; printf("Enter a number (negative to quit): "); scanf("%d", &x); if(x < 0) break; [subject value:x]; } return 0; }
[edit] Notes
We have two different viewers Viewer1 and Viewer2 representing the Subject, by a line of asterisks and simply printing the number. When the Subject's value is reassigned, the notify message is sent to the Observer. The observer will then forward the message to all subscribed objects implementing the Notifiable protocol. Conceptually, we can think of the Observer as broadcasting the one incoming message call to its subscribed objects. The viewers Viewer1 and Viewer2 represent the Subject object, successfully implementing the pattern.