PromiseKit 概要
对PromiseKit理解
PromiseKit 只是 Promise 设计模式的一种实现方式。并不能为我们的 app 带来任何”看得到“的好处,而仅仅是为了满足我们对“代码美学”的追求。因此,使用不使用 PromiseKit 完全取决于你自己的喜好。有的程序员不喜欢 Promise,因为他们觉得原有的异步编程中的回调块或委托模型完全就够用了,没有必要再用 Promise 进行重构。但毋庸置疑的一点是,Promise 确实能够让我们的异步编程代码显得更加优雅,可读性和维护性也更高。
所谓 Promise 设计模式,是借用生活中的“承诺”一词来描述异步编程中的回调模型。承诺是一种对未来的期许,它有两个特点,一,它描述的是未来的一种状态或动作,而不是目前的;二,承诺有一定的不确定性,承诺可以兑现(fullfill),也可能被拒绝(rejectd),拒绝的原因是各种各样的,有可能是承诺者不想兑现了,有可能是因为条件无法满足。举例,如果我们编写一个方法从网络获取图片,网络操作一般都是异步的,所以完全适用于承诺模式。所以这个方法就是一个承诺。它不用直接返回一个 Image,而是返回一个承诺对象,只有当网络请求到需要的数据时,这个承诺才会兑现(返回一个 Image 对象给调用者),否则承诺被拒绝(网络错误或者图片不存在),无论兑现还是拒绝,这个承诺对象都会标记为已解决(resolve),已解决的承诺会被销毁。如果既不兑现,也不拒绝,则这个承诺会一直有效(即未解决)。
PromiseKit使用
基本用法
-(void)jsonPostUrl:(NSString*)url params:(NSDictionary<NSString *,id>*)params success:(nullable void (^)(NSURLSessionDataTask *task, NSDictionary* responseDic))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure{
[[self postUrl:url params:params requestType:@"json" success:^(NSURLSessionDataTask *task, id responseObject) {
if([responseObject isKindOfClass:[NSDictionary class]]){
NSDictionary* dic = (NSDictionary*)responseObject;
NSNumber* code = dic[@"code"];
if(![code isEqual:@0]){
// [self.view makeToast:dic[@"msg"] duration:2 position:CSToastPositionCenter];
if(failure){
NSError *err = [NSError errorWithDomain:@"ServiceError" code:code.integerValue userInfo:@{NSLocalizedDescriptionKey: dic[@"msg"]}];
failure(task,err);
}
}else if(success!=nil){
success(task,dic);
}
}
} failure:failure]resume];
}
修改后代码
-(AnyPromise*)jsonPostUrl:(NSString*)url params:(NSDictionary<NSString *,id>*)params{
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
[[self postUrl:url params:params requestType:@"json" success:^(NSURLSessionDataTask *task, id responseObject) {
if([responseObject isKindOfClass:[NSDictionary class]]){
NSDictionary* dic = (NSDictionary*)responseObject;
NSNumber* code = dic[@"code"];
if(![code isEqual:@0]){
// [self.view makeToast:dic[@"msg"] duration:2 position:CSToastPositionCenter];
NSError *err = [NSError errorWithDomain:@"ServiceError" code:code.integerValue userInfo:@{NSLocalizedDescriptionKey: dic[@"msg"]}];
resolve(err);
}else{
resolve(dic);
}
}
} failure:^(NSURLSessionDataTask *task, NSError *error) {
resolve(error);
}] resume];
}];
}
[self loadAlbums:radioId pageNum:pageNum pageSize:pageSize].then(^(NSArray<AlbumModel>* array){
if(pageNum <= 1){
[_models removeAllObjects];
}
if(array!=nil){
[_models addObjectsFromArray: array];
}
//下一个then中对应的promise
AnyPromise *newPromise1 = [AnyPromise promiseWithAdapterBlock:^(PMKAdapter _Nonnull adapter) {
id errorValue;
NSDictionary *valueDic1 = @{
@"key":@"value1"
};
adapter(valueDic1,errorValue);
}];
//在thenOn中的data则是valueDic1
return newPromise1;
/**
//如果没有return数据则在下面的thenOn中获取不到数据
return _models;
当ruturn error类型的数据则终止返回错误
return [NSError errorWithDomain:PMKErrorDomain code:PMKUnexpectedError userInfo:@{NSLocalizedDescriptionKey: @"reason"}];
*/
}).thenOn(dispatch_get_main_queue(),^(id data){
//.....
}).catch(^(NSError* error){
//失败处理
});
比较总结:
优点:
1.方法省去了 success 和 failure 两个异步块参数。
2.方法返回了一个 AnyPromise 对象。这是 PromiseKit 提供的主要的类,用于实现 Promise 模式。承诺不会执行,当然也不需要实现,但在将来特定时候会执行的(当然需要在未来实现,特别是调用这个方法时实现)动作。也就是说。success 和 failure 的功能由 AnyPromise 替代了。
3.方法中调用了 AnyPromise 的 promiseWithResolverBlock 方法来构造和返回 AnyPromise。这个方法会提供一个 resolve 参数。你可以把它仍然看成是一个回调块。只不过这个回调块同时充当了 success 和 failure。如果 resolve()传递了一个 NSError,则表明这个承诺被拒绝(即 failure),否则承诺会被兑现(success)。
缺点:
仍然需要做一些封装,通常是通过分类的方式扩展
其他用法:
when:可以等到多个异步全部都完成之后在做处理
join:和when类似等待所有异步回调都成功之后就返回成功的回调,不同的是reject部分,join是当所有promise都遍历一遍之后才会执行reject()回调,when是只要发现一个失败了立刻执行reject()回调
race:只要有一个promise返回成功则会调用then里面的回调,也就是第一个胜出.目前只有swift的代码,但是可以仿照when和join的逻辑进行扩展
always:不论promise成功失败与否都会调用该回调
catch:promise失败会调用
例子:
AnyPromise *newPromise1 = [AnyPromise promiseWithAdapterBlock:^(PMKAdapter _Nonnull adapter) {
id errorValue;
NSDictionary *valueDic = @{
@"key":@"value1"
};
adapter(valueDic,errorValue);
}];
AnyPromise *newPromise2 = [AnyPromise promiseWithAdapterBlock:^(PMKAdapter _Nonnull adapter) {
id errorValue;
NSDictionary *valueDic = @{
@"key":@"value2"
};
adapter(valueDic,errorValue);
}];
NSArray *promiseArr = @[
newPromise1,
newPromise2,
];
AnyPromise *allPromise = PMKWhen(promiseArr);
allPromise.then(^(id data){
NSLog(@"data - 3 data = %@",data);
}).always(^(){
NSLog(@"always");
});;
打印结果:从结果可以知道这钟情况的then可以得到最终所有异步情况的所有数据
Promise-OC[1139:29281] data - 3 data = (
{
key = value1;
},
{
key = value2;
}
)
原理篇
when原理,主要是通过for循环遍历所有promise,然后都成功之后在resolve(result)所有结果
AnyPromise *PMKWhen(id promises) {
if (promises == nil)
return [AnyPromise promiseWithValue:[NSError errorWithDomain:PMKErrorDomain code:PMKInvalidUsageError userInfo:@{NSLocalizedDescriptionKey: @"PMKWhen(nil)"}]];
if ([promises isKindOfClass:[NSArray class]] || [promises isKindOfClass:[NSDictionary class]]) {
if ([promises count] == 0)
return [AnyPromise promiseWithValue:promises];
} else if ([promises isKindOfClass:[AnyPromise class]]) {
promises = @[promises];
} else {
return [AnyPromise promiseWithValue:promises];
}
#ifndef PMKDisableProgress
NSProgress *progress = [NSProgress progressWithTotalUnitCount:(int64_t)[promises count]];
progress.pausable = NO;
progress.cancellable = NO;
#else
struct PMKProgress {
int completedUnitCount;
int totalUnitCount;
double fractionCompleted;
};
__block struct PMKProgress progress;
#endif
__block int32_t countdown = (int32_t)[promises count];
BOOL const isdict = [promises isKindOfClass:[NSDictionary class]];
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
NSInteger index = 0;
for (__strong id key in promises) {
AnyPromise *promise = isdict ? promises[key] : key;
if (!isdict) key = @(index);
if (![promise isKindOfClass:[AnyPromise class]])
promise = [AnyPromise promiseWithValue:promise];
[promise __pipe:^(id value){
if (progress.fractionCompleted >= 1)
return;
if (IsError(value)) {//这部分和join方法处理不同
progress.completedUnitCount = progress.totalUnitCount;
NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[value userInfo] ?: @{}];
userInfo[PMKFailingPromiseIndexKey] = key;
[userInfo setObject:value forKey:NSUnderlyingErrorKey];
id err = [[NSError alloc] initWithDomain:[value domain] code:[value code] userInfo:userInfo];
resolve(err);
}
else if (OSAtomicDecrement32(&countdown) == 0) {
progress.completedUnitCount = progress.totalUnitCount;
id results;
if (isdict) {
results = [NSMutableDictionary new];
for (id key in promises) {
id promise = promises[key];
results[key] = IsPromise(promise) ? ((AnyPromise *)promise).value : promise;
}
} else {
results = [NSMutableArray new];
for (AnyPromise *promise in promises) {
id value = IsPromise(promise) ? (promise.value ?: [NSNull null]) : promise;
[results addObject:value];
}
}
resolve(results);
} else {
progress.completedUnitCount++;
}
}];
}
}];
}
join原理,也是通过for循环处理,只是循环内部对于reject部分与when不同
AnyPromise *PMKJoin(NSArray *promises) {
if (promises == nil)
return [AnyPromise promiseWithValue:[NSError errorWithDomain:PMKErrorDomain code:PMKInvalidUsageError userInfo:@{NSLocalizedDescriptionKey: @"PMKJoin(nil)"}]];
if (promises.count == 0)
return [AnyPromise promiseWithValue:promises];
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
NSPointerArray *results = NSPointerArrayMake(promises.count);
__block atomic_int countdown = promises.count;
__block BOOL rejected = NO;
[promises enumerateObjectsUsingBlock:^(AnyPromise *promise, NSUInteger ii, BOOL *stop) {
[promise __pipe:^(id value) {
if (IsError(value)) {//这部分和when方法处理不同
rejected = YES;
}
//FIXME surely this isn't thread safe on multiple cores?
[results replacePointerAtIndex:ii withPointer:(__bridge void *)(value ?: [NSNull null])];
atomic_fetch_sub_explicit(&countdown, 1, memory_order_relaxed);
if (countdown == 0) {
if (!rejected) {
resolve(results.allObjects);
} else {
id userInfo = @{PMKJoinPromisesKey: promises};
id err = [NSError errorWithDomain:PMKErrorDomain code:PMKJoinError userInfo:userInfo];
resolve(err);
}
}
}];
(void) stop;
}];
}];
}
使用范围总结
1,具有强依赖关系的异步任务
2,对某些系统的delegate回调方式修改成block回调(完全凭借个人喜好)
实例代码
@implementation CLLocationManager (PromiseKit)
+ (PMKPromise *)promise {
return [PMKLocationManager promise];
}
@end
@interface PMKLocationManager : CLLocationManager <CLLocationManagerDelegate>
@end
@implementation PMKLocationManager {
PMKResolver resolve;
id retainCycle;
}
+ (PMKPromise *)promise {
PMKLocationManager *manager = [PMKLocationManager new];
manager.delegate = manager;
manager->retainCycle = self; // prevent deallocation
[manager startUpdatingLocation];
return [[AnyPromise alloc] initWithResolve:&manager->resolve];
}
- (void)locationManager:(id)manager didUpdateLocations:(NSArray *)locations {
resolve(PMKManifold(locations.firstObject, locations));
retainCycle = nil; // break retain cycle
}
- (void)locationManager:(id)manager didFailWithError:(NSError *)error {
resolve(error);
retainCycle = nil; // break retain cycle
}
@end
安装遇到的问题:
The “Swift Language Version” (SWIFT_VERSION) build setting must be set to a supported value for targ
![](https://img.haomeiwen.com/i1396448/c4564b294daf9d08.png)
demo:https://github.com/riceForChina/PromiseKitDemo.git
参考文章:
http://blog.csdn.net/kmyhy/article/details/56277524
https://stackoverflow.com/questions/45079502/xcode-9-swift-dependency-analysis-error