让 NSNotification 用起来更舒爽 :)

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 中获取 #补充

NotificationCenter A notification center delivers notifications to observers synchronously. In other words, when posting a notification, control does not return to the poster until all observers have received and processed the notification. To send notifications asynchronously use a notification queue, which is described in Notification Queues. In a multithreaded application, notifications are always delivered in the thread in which the notification was posted, which may not be the same thread in which an observer registered itself.

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.

Ref :

stackoverflow