NSNotification
是我们在 iOS 中经常使用的一个类
我们可以简单的修改重构我们的代码,来更舒爽的发送和接收 NSNotification
比如我们要在图片下载完之后发送一个通知,并传递图片和图片 url 参数.
传统的使用方式如下:
- (void)viewDidLoad {
[super viewDidLoad];
UIImage *img;
NSURL *imgUrl;
NSDictionary *userInfo=@{@"image":img,@"imgUrl":imgUrl};
[[NSNotificationCenter defaultCenter]postNotificationName:@"NotificationName" object:self userInfo:userInfo];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(handleNotification:) name:@"NotificationName" object:nil];
}
-(void)handleNotification:(NSNotification*)noti{
UIImage *img= noti.userInfo[@"image"];
NSURL *imgUrl= noti.userInfo[@"imgUrl"];
}
开始重构
现在,我们来改造上面的代码.
首先创建一个 NSNotifcation Category
#import <Foundation/Foundation.h>
@import UIKit;
//将 Notification Name 定义为常量
extern NSString *const kDownloadImageCompleteNotification;
@interface NSNotification (DownloadImage)
//注意下面2个属性是 readonly
//定义 image 和 imageURl 属性,我们可以使用 notification.image , notification.imageUrl 点语法来访问userInfo 里的内容
@property (strong,nonatomic,readonly) UIImage *image;
@property (strong,nonatomic,readonly) NSURL *imageUrl;
//方便我们发送 NSNotifcation
+(void)postDownloadImageNotification:(id)object image:(UIImage*)img url:(NSURL*)imageUrl;
@end
.m 文件
#import "NSNotification+DownloadImage.h"
#import "NSNotification+Post.h"
NSString *const kDownloadImageCompleteNotification=@"kDownloadImageCompleteNotification";
//将 userinfo 字典的 key 定义为常量
static NSString *const kDownloadedImage=@"kDownloadedImage";
static NSString *const kDownloadedImageUrl=@"kDownloadedImageUrl";
@implementation NSNotification (DownloadImage)
+(void)postDownloadImageNotification:(id)object image:(UIImage*)img url:(NSURL*)imageUrl{
[[NSNotification notificationWithName:kDownloadImageCompleteNotification object:object userInfo:@{kDownloadedImage:img,kDownloadedImageUrl:imageUrl}]post];
}
//提供方便的读取 userInfo 字典value 的 Getter 方法
-(UIImage *)image{
return self.userInfo[kDownloadedImage];
}
-(NSURL *)imageUrl{
return self.userInfo[kDownloadedImageUrl];
}
@end
其中#import "NSNotification+Post.h"
是另一个 NSNotification 的分类
实现如下
@interface NSNotification (Post)
-(void)post;
@end
.m 中
@implementation NSNotification (Post)
-(void)post{
[[NSNotificationCenter defaultCenter]postNotification:self];
}
@end
改造完毕
现在我们使用 NSNotification
的方式如下:
先引入头文件 #import "NSNotification+DownloadImage.h"
发送:
[NSNotification postDownloadImageNotification:self image:img url:imgUrl];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(handleNotification:) name:kDownloadImageCompleteNotification object:nil];
接收:
-(void)handleNotification:(NSNotification*)noti{
noti.image;
noti.imageUrl;
}
我们只简单的重构了一下代码,就让 NSNotification 使用起来更舒爽了.
Demo 中还有一个更复杂的 NSNotification+UploadMedia
分类来提供参考,所有Demo代码可以在 GitHub 中获取
补充
- 如果你的 App 里大量使用 NSNotification, 可以考虑为方法属性等添加前缀.
- NSNotification 类似 NSString,NSArray 是类簇,在 XCode Console 查看是
NSConcretNotification
类 - 关于 Subclass NSNotification,创建 NSNotification 子类也是一个简化发送接收通知的方式.但一般来说,我们都是用 userInfo 来传值,下面是官方文档关于创建 NSNotification 子类的说明,感觉创建子类会更加麻烦.
Creating Subclasses
You can subclass NSNotification to contain information in addition to the notification name, object, and dictionary. This extra data must be agreed upon between notifiers and observers.
NSNotification is a class cluster with no instance variables. As such, you must subclass NSNotification and override the primitive methods name, object, and userInfo. You can choose any designated initializer you like, but be sure that your initializer does not call [super init]. NSNotification is not meant to be instantiated directly, and its init method raises an exception.