×

让 NSNotification 用起来更舒爽 :)

96
王大屁帅2333
2016.05.03 01:17* 字数 415

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.

Ref :

stackoverflow

iOS
Web note ad 1