先簡單介紹蘋果封裝的消息通知,再獻上根據觀察者模式原理實現的源碼供參考。 ios
對於觀察者模式,蘋果封裝了消息通知(NSNotification)和通知中心(NSNotificationCenter)供開發者使用。使用也比較簡便,例如:git
// defaultCenter
[[NSNotificationCenter defaultCenter] addObserver:observer selector:@selector(nsSelector:) name:ZZNotificationWithDefaultCenter object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:ZZNotificationWithDefaultCenter object:@"默認實例 >>>> defaultCenter"];
複製代碼
其中@property (class, readonly, strong) NSNotificationCenter *defaultCenter;
只是蘋果提供的一個單例,你也能夠本身建立一個,例如:github
// newCenter
NSNotificationCenter *newCenter = [NSNotificationCenter new];
[newCenter addObserver:observer selector:@selector(nsSelector:) name:ZZNotificationWithNew1 object:nil];
[newCenter postNotificationName:ZZNotificationWithNew1 object:@"newCenter1"];
複製代碼
須要注意的是,addObserver和postNotificationName的必須是同一個NSNotificationCenter實例。macos
若是不想調用selector,蘋果也提供了執行block的方法:設計模式
- (id <NSObject>)addObserverForName:(nullable NSNotificationName)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));
複製代碼
參照着蘋果提供的接口文檔和使用,以及加上對觀察者模式的理解,試着去實現ZZNotification、ZZNotification (ZZNotificationCreation)、ZZNotificationCenter三個類,前綴NS改爲ZZ,代碼以下:bash
ZZNotification.hpost
typedef NSString *ZZNotificationName;
@interface ZZNotification : NSObject<NSCopying>
@property (readonly, copy) ZZNotificationName name;
@property (nullable, readonly, retain) id object;
@property (nullable, readonly, copy) NSDictionary *userInfo;
- (instancetype)initWithName:(ZZNotificationName)name object:(nullable id)object userInfo:(nullable NSDictionary *)userInfo;
@end
複製代碼
ZZNotification.mui
@implementation ZZNotification
- (instancetype)initWithName:(ZZNotificationName)name object:(id)object userInfo:(NSDictionary *)userInfo
{
if (self = [super init]) {
_name = name;
_object = object;
_userInfo = userInfo;
}
return self;
}
- (nonnull id)copyWithZone:(nullable NSZone *)zone
{
return self;
}
@end
複製代碼
ZZNotification (ZZNotificationCreation).hatom
@interface ZZNotification (ZZNotificationCreation)
+ (instancetype)notificationWithName:(ZZNotificationName)aName object:(nullable id)anObject;
+ (instancetype)notificationWithName:(ZZNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;
+ (instancetype)new __attribute__((unavailable("use -initWithName:object:userInfo instead")));
- (instancetype)init __attribute__((unavailable("use -initWithName:object:userInfo instead")));
@end
複製代碼
ZZNotification (ZZNotificationCreation).mspa
@implementation ZZNotification (ZZNotificationCreation)
+ (instancetype)notificationWithName:(ZZNotificationName)aName object:(id)anObject
{
return [self notificationWithName:aName object:anObject userInfo:nil];
}
+ (instancetype)notificationWithName:(ZZNotificationName)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo
{
ZZNotification *notification = [[[self class] alloc] initWithName:aName object:anObject userInfo:aUserInfo];
return notification;
}
@end
複製代碼
另外,先增長一個管理觀察者屬性的ZZObserverModel:
@interface ZZObserverModel : NSObject
@property (nullable, nonatomic, copy) ZZNotificationName name; // 通知名稱
@property (nullable, nonatomic, strong) id observer; // 觀察者
@property (nullable, nonatomic, strong) id object; // 監聽到通知後傳入對象
@property (nonatomic, assign) SEL selector; // 監聽到通知後執行方法
@property (nonatomic, strong) NSOperationQueue *queue;
@property (nonatomic, copy) ZZNotificationBlock block;
@end
@implementation ZZObserverModel
+ (instancetype)modelWithObserver:(id)observer name:(ZZNotificationName)name selector:(SEL)selector object:(id)object
{
return [self modelWithObserver:observer name:name selector:selector object:object queue:nil block:nil];
}
+ (instancetype)modelWithObserver:(id)observer name:(ZZNotificationName)name selector:(SEL)selector object:(id)object queue:(NSOperationQueue *)queue block:(ZZNotificationBlock)block
{
ZZObserverModel *model = [[[self class] alloc] init];
model.observer = observer;
model.name = name;
model.selector = selector;
model.object = object;
model.queue = queue;
model.block = block;
return model;
}
@end
複製代碼
最後實現最重要的ZZNotificationCenter
ZZNotificationCenter.h
@interface ZZNotificationCenter : NSObject
@property (class, readonly, strong) ZZNotificationCenter *defaultCenter;
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable ZZNotificationName)aName object:(nullable id)anObject;
- (void)postNotification:(ZZNotification *)notification;
- (void)postNotificationName:(ZZNotificationName)aName object:(nullable id)anObject;
- (void)postNotificationName:(ZZNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;
- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(nullable ZZNotificationName)aName object:(nullable id)anObject;
- (id <NSObject>)addObserverForName:(nullable ZZNotificationName)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(ZZNotification *note))block;
@end
複製代碼
ZZNotificationCenter ()
@interface ZZNotificationCenter ()
// 觀察者字典:key是ZZNotificationName,value是NSMutableArray,即全部具備相同名稱的觀察者
@property (nullable, nonatomic, strong) NSMutableDictionary <NSString*, NSMutableArray<ZZObserverModel *>*>*observersDictionary;
@end
複製代碼
ZZNotificationCenter.m
// 編譯器不實現getter,需手動實現
@dynamic defaultCenter;
- (instancetype)init
{
if (self = [super init]) {
_observersDictionary = [NSMutableDictionary new];
}
return self;
}
// 提供單例
+ (ZZNotificationCenter *)defaultCenter
{
static ZZNotificationCenter *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[ZZNotificationCenter alloc] init];
});
return sharedInstance;
}
複製代碼
#pragma mark - addObserver
// 增長觀察者,方式:selector
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(ZZNotificationName)aName object:(id)anObject
{
if (aName) {
ZZObserverModel *model = [ZZObserverModel modelWithObserver:observer name:aName selector:aSelector object:anObject];
NSMutableArray *observers = self.observersDictionary[aName];
if (!observers) {
observers = [NSMutableArray new];
}
[observers addObject:model];
self.observersDictionary[aName] = observers;
}
}
// 增長觀察者,方式:queue、block
- (id<NSObject>)addObserverForName:(ZZNotificationName)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(ZZNotification * _Nonnull))block
{
if (name) {
ZZObserverModel *model = [ZZObserverModel modelWithObserver:nil name:name selector:nil object:obj queue:queue block:block];
NSMutableArray *observers = self.observersDictionary[name];
if (!observers) {
observers = [NSMutableArray new];
}
[observers addObject:model];
self.observersDictionary[name] = observers;
}
return nil;
}
複製代碼
#pragma mark - postNotification
// 發送通知
- (void)postNotification:(ZZNotification *)notification
{
if (notification.name) {
NSArray <ZZObserverModel *>*observers = self.observersDictionary[notification.name];
[observers enumerateObjectsUsingBlock:^(ZZObserverModel * _Nonnull model, NSUInteger idx, BOOL * _Nonnull stop) {
if (model.queue) {
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
model.block(notification);
}];
NSOperationQueue *queue = model.queue;
[queue addOperation:operation];
} else {
id observer = model.observer;
SEL selector = model.selector;
if (observer && [observer respondsToSelector:selector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[observer performSelector:selector withObject:notification];
#pragma clang diagnostic pop
}
}
/*
// 或者用消息轉發
NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:"v@:@"];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
SEL sel = observer.selector;
if ([observer.observer respondsToSelector:sel]) {
[invocation setTarget:observer.observer];
[invocation setSelector:sel];
[invocation setArgument:¬ification atIndex:2];
[invocation invoke];
}
*/
}];
}
}
- (void)postNotificationName:(ZZNotificationName)aName object:(id)anObject
{
[self postNotification:[ZZNotification notificationWithName:aName object:anObject]];
}
- (void)postNotificationName:(ZZNotificationName)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo
{
[self postNotification:[ZZNotification notificationWithName:aName object:anObject userInfo:aUserInfo]];
}
複製代碼
#pragma mark - removeObserver
// 移除觀察者
- (void)removeObserver:(id)observer
{
[self removeObserver:observer name:nil object:nil];
}
- (void)removeObserver:(id)observer name:(ZZNotificationName)aName object:(id)anObject
{
[[self.observersDictionary allValues] enumerateObjectsUsingBlock:^(NSMutableArray<ZZObserverModel *> * _Nonnull observers, NSUInteger idx, BOOL * _Nonnull stop) {
[observers enumerateObjectsUsingBlock:^(ZZObserverModel * _Nonnull anObserver, NSUInteger idx, BOOL * _Nonnull stop) {
if (observer && observer == anObserver.observer) {
if (!aName || [anObserver.name isEqualToString:aName]) {
if (!anObject || anObserver.object == anObject) {
[observers removeObject:anObserver];
}
}
}
}];
}];
}
@end
複製代碼
23種設計模式代碼:ZZDesignPatterns