2012年10月29日

Obj-C observer pattern

下面是obj-c observer pattern的source code


首先先定義一個protocol


//
//  Protocols.h
//  ObserverTest
//
//  Created by Steve on 12/10/5.
//  Copyright (c) 2012年 Steve. All rights reserved.
//
 
#import <Foundation/Foundation.h>
 
@protocol IxxxObserver <NSObject>
@required
-(void)doSomethingAfterNotify:(NSString*)someStr;
@end
接著,定義一個observer class,要實作剛剛那個protocol

//
//  ObserverClass.h
//  ObserverTest
//
//  Created by Steve on 12/10/5.
//  Copyright (c) 2012年 Steve. All rights reserved.
//
 
#import <Foundation/Foundation.h>
#import "Protocols.h"
@interface ObserverClass : NSObject <IxxxObserver>
 
@end

//
//  ObserverClass.m
//  ObserverTest
//
//  Created by Steve on 12/10/5.
//  Copyright (c) 2012年 Steve. All rights reserved.
//
 
#import "ObserverClass.h"
 
@implementation ObserverClass
-(void)doSomethingAfterNotify:(NSString*)someStr {
    NSLog(@"notified! class %@, with value %@", self, someStr);
}
@end

然後,定義一個singleton class
拿來add observer, remove observer, 以及notify observer

//
//  FirstClass.h
//  ObserverTest
//
//  Created by Steve on 12/10/5.
//  Copyright (c) 2012年 Steve. All rights reserved.
//
#import "Protocols.h"
#import <Foundation/Foundation.h>
 
@interface FirstClass : NSObject
+(FirstClass*)sharedInstance;
-(NSString*)regiestObserver:(id<IxxxObserver>)observer;
-(void)unregiestObserverWithTicket:(NSString*)ticket;
-(void)notifyWithStr:(NSString*)str;
@end

//
//  FirstClass.m
//  ObserverTest
//
//  Created by Steve on 12/10/5.
//  Copyright (c) 2012年 Steve. All rights reserved.
//
 
#import "FirstClass.h"
#import <CommonCrypto/CommonDigest.h>
@interface FirstClass () {
    NSMutableDictionary *mObservers;
    NSMutableArray *mUnRegTickets;
    NSMutableDictionary *mNeedToRegObservers;
}
-(void)doInit;
-(NSString*)generateTicket;
-(NSString*)timeStrFromTimeObj:(NSDate*)timeObj;
-(NSString*)stringToSha1:(NSString*)input;
@end

@implementation FirstClass
static FirstClass *instance = nil;
+(FirstClass*)sharedInstance {
    @synchronized(self) {
        if (instance == nil){
            instance = [[FirstClass alloc] init];
            [instance doInit];
        }
    }
    return instance;
}
 
-(void)dealloc {
    [mObservers release];
    [mUnRegTickets release];
    [mNeedToRegObservers release];
    [super dealloc];
}
 
#pragma mark - public
-(NSString*)regiestObserver:(id<IxxxObserver>)observer {
    NSString *ticket = [self generateTicket];
    [mNeedToRegObservers setObject:observer forKey:ticket];
    NSLog(@"save reg observer %@ to queue, ticket %@", observer, ticket);
    return ticket;
}
 
-(void)unregiestObserverWithTicket:(NSString*)ticket {
    [mUnRegTickets addObject:ticket];
    NSLog(@"save unreg observer ticket %@ to queue", ticket);
}
 
-(void)notifyWithStr:(NSString*)str {
    @synchronized(self) {
        // add and remove observers
        NSLog(@"reg observers from queue");
        [mObservers setValuesForKeysWithDictionary:mNeedToRegObservers];
        for (NSString *ticket in mUnRegTickets) {
            NSLog(@"unreg observer %@, ticket %@", [mObservers objectForKey:ticket], ticket);
            [mObservers removeObjectForKey:ticket];
        }
        [mUnRegTickets removeAllObjects];
        [mNeedToRegObservers removeAllObjects];
         
        // update
        for (id<IxxxObserver> observer in [mObservers allValues]) {
            NSLog(@"notify observer %@", observer);
            [observer doSomethingAfterNotify:str];
        }
    }
}
 
#pragma mark - private
-(void)doInit {
    mObservers = [[NSMutableDictionary alloc] init];
    mUnRegTickets = [[NSMutableArray alloc] init];
    mNeedToRegObservers = [[NSMutableDictionary alloc] init];
}
 
-(NSString*)generateTicket {
    NSString *result = nil;
    int r = arc4random() % 9999999999;
     
    result = [self timeStrFromTimeObj:[NSDate date]];
    result = [NSString stringWithFormat:@"%d %@", r, result];
    result = [self stringToSha1:result];
    return result;
}
 
-(NSString*)timeStrFromTimeObj:(NSDate*)timeObj {
    NSString *result = nil;
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    if (!timeObj) {
        goto EXIT;
    }
     
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    result = [dateFormatter stringFromDate:timeObj];
     
EXIT:
    [dateFormatter release];
    return result;
}
 
-(NSString*)stringToSha1:(NSString*)input {
    const char *cstr = [input cStringUsingEncoding:NSUTF8StringEncoding];
    NSData *data = [NSData dataWithBytes:cstr length:input.length];
    uint8_t digest[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1(data.bytes, data.length, digest);
    NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
    for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
        [output appendFormat:@"%02x", digest[i]];
    }
     
    return output;
}
@end

最後,使用方法如下…

//
//  main.m
//  ObserverTest
//
//  Created by Steve on 12/10/5.
//  Copyright (c) 2012年 Steve. All rights reserved.
//
 
#import <Foundation/Foundation.h>
#import "FirstClass.h"
#import "ObserverClass.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        FirstClass *fc = [FirstClass sharedInstance];
        ObserverClass *oc = [[ObserverClass alloc] init];
        // reg
        NSString *ticket = [fc regiestObserver:oc];
        // notify
        [fc notifyWithStr:@"XDD"];
        // unreg
        [fc unregiestObserverWithTicket:ticket];
        // notify
        [fc notifyWithStr:@"XDDDD"];       
    }
    return 0;
}

沒有留言:

張貼留言