Skip to content

Commit

Permalink
Remove duplicate code
Browse files Browse the repository at this point in the history
Add AYRuntime dependency
  • Loading branch information
Alan Yeh committed Aug 2, 2016
1 parent c069e29 commit bc250f1
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 119 deletions.
3 changes: 2 additions & 1 deletion AYPromise.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Pod::Spec.new do |s|
s.name = 'AYPromise'
s.version = '1.1.0'
s.version = '1.1.1'
s.summary = 'Promise for objective-c.'

s.homepage = 'https://github.com/alan-yeh/AYPromise'
Expand All @@ -19,4 +19,5 @@ Pod::Spec.new do |s|
s.ios.deployment_target = '6.0'

s.source_files = 'AYPromise/Classes/**/*'
s.dependency 'AYRuntime'
end
12 changes: 7 additions & 5 deletions AYPromise/Classes/AYPromise.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// AYPromise.h
// AYPromise
//
// Created by PoiSon on 16/2/15.
// Copyright © 2016年 PoiSon. All rights reserved.
// Created by Alan Yeh on 16/2/15.
// Copyright © 2016年 Alan Yeh. All rights reserved.
//

#import <Foundation/Foundation.h>
Expand All @@ -21,7 +21,7 @@ NSError *NSErrorMake(id _Nullable internalErrors, NSString *localizedDescription

NSInvocation *NSInvocationMake(id target, SEL action);

typedef void (^PSResolve)(id __nullable result);
typedef void (^AYResolve)(id __nullable result);

typedef NS_ENUM(NSUInteger, AYPromiseState) {
AYPromiseStatePending = 1 << 0, /**< 待执行状态 */
Expand Down Expand Up @@ -72,6 +72,7 @@ typedef NS_ENUM(NSUInteger, AYPromiseState) {
* 如果then的返回值不是Promise,会作为下一个then的参数
* 如果then的返回值是Promise对象,那么之后的then添加的操作函数会被托管给返回的Promise对象
* 如果value是一个Promise,则认为then的返回值是Promise对象
* 如果value是一个NSInvocation对象,则将上一个Promise的结果作为参数调用NSInvocation
*/
- (AYPromise *(^)(id value))then;

Expand All @@ -92,7 +93,7 @@ typedef NS_ENUM(NSUInteger, AYPromiseState) {
- (AYPromise *(^)(id value))thenAsync;/**< 异步执行 */
- (AYPromise *(^)(NSTimeInterval delaySecond, id value))thenDelay;/**< 延迟执行 */
- (AYPromise *(^)(dispatch_queue_t queue, id value))thenOn;/**< 在指定线程执行 */
- (AYPromise *(^)(void (^resolver)(id result, PSResolve resolve)))thenPromise;/**< 需要回调的任务 */
- (AYPromise *(^)(void (^resolver)(id result, AYResolve resolve)))thenPromise;/**< 需要回调的任务 */
- (AYPromise *(^)(id value))catchAsync;/**< 异步处理错误 */
- (AYPromise *(^)(dispatch_queue_t queue, id value))catchOn;/**< 在指定线程处理错误 */
- (AYPromise *(^)(id value))always;/**< 无论错误还是正确都执行 */
Expand All @@ -101,6 +102,7 @@ typedef NS_ENUM(NSUInteger, AYPromiseState) {
* 创建Promise对象
*
* 如果value是block,则创建一个Pending状态的Promise并同步执行block
* 如果value是NSInvocation对象,则创建一个Pending状态的Promise并同步执行NSInvocation
* 如果value是Promise, 则直接返回Promise
* 如果vlaue是数组,则返回Promise.all封装的Promise
* 如果vlaue是NSError对象,则返回一个Rejected状态的Promise
Expand All @@ -117,7 +119,7 @@ FOUNDATION_EXPORT AYPromise *AYPromiseAsyncWith(_Nullable id value);
/**
* 创建一个需要回调的Promise
*/
FOUNDATION_EXPORT AYPromise *AYPromiseWithResolve(void (^)(PSResolve resolve));
FOUNDATION_EXPORT AYPromise *AYPromiseWithResolve(void (^)(AYResolve resolve));
NS_ASSUME_NONNULL_END


102 changes: 26 additions & 76 deletions AYPromise/Classes/AYPromise.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
// AYPromise.m
// AYPromise
//
// Created by PoiSon on 16/2/21.
// Copyright © 2016年 PoiSon. All rights reserved.
// Created by Alan Yeh on 16/2/21.
// Copyright © 2016年 Alan Yeh. All rights reserved.
//

#import "AYPromise.h"
#import <libkern/OSAtomic.h>
#import <AYRuntime/AYBlockInvocation.h>

#define isError(obj) [obj isKindOfClass:[NSError class]]
#define isPromise(obj) [obj isKindOfClass:[AYPromise class]]
Expand Down Expand Up @@ -45,73 +46,22 @@
return invocation;
}

/**
* @see CTObjectiveCRuntimeAdditions https://github.com/ebf/CTObjectiveCRuntimeAdditions
*/
struct PSBlockLiteral {
void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
int flags;
int reserved;
void (*invoke)(void *, ...);
struct ps_block_descriptor {
unsigned long int reserved; // NULL
unsigned long int size; // sizeof(struct Block_literal_1)
// optional helper functions
void (*copy_helper)(void *dst, void *src); // IFF (1<<25)
void (*dispose_helper)(void *src); // IFF (1<<25)
// required ABI.2010.3.16
const char *signature; // IFF (1<<30)
} *descriptor;
// imported variables
};

typedef NS_ENUM(NSUInteger, PSBlockDescriptionFlags) {
PSBlockDescriptionFlagsHasCopyDispose = (1 << 25),
PSBlockDescriptionFlagsHasCtor = (1 << 26), // helpers have C++ code
PSBlockDescriptionFlagsIsGlobal = (1 << 28),
PSBlockDescriptionFlagsHasStret = (1 << 29), // IFF BLOCK_HAS_SIGNATURE
PSBlockDescriptionFlagsHasSignature = (1 << 30)
};

static NSMethodSignature *_signatureForBlock(id block) {
if (!block)
return nil;

struct PSBlockLiteral *blockRef = (__bridge struct PSBlockLiteral *)block;
PSBlockDescriptionFlags flags = (PSBlockDescriptionFlags)blockRef->flags;

if (flags & PSBlockDescriptionFlagsHasSignature) {
void *signatureLocation = blockRef->descriptor;
signatureLocation += sizeof(unsigned long int);
signatureLocation += sizeof(unsigned long int);

if (flags & PSBlockDescriptionFlagsHasCopyDispose) {
signatureLocation += sizeof(void (*)(void *dst, void *src));
signatureLocation += sizeof(void (*)(void *src));
}

const char *signature = (*(const char **)signatureLocation);
return [NSMethodSignature signatureWithObjCTypes:signature];
}
return nil;
}

static id __execute__(id target, id args){
NSCParameterAssert(isBlock(target) || isInvocation(target));

NSMethodSignature *signature;
NSInvocation *invocation;
id invocation;

if (isBlock(target)) {
signature = _signatureForBlock(target);
invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:target];
invocation = [AYBlockInvocation invocationWithBlock:target];
signature = [invocation blockSignature].signature;
if (args && signature.numberOfArguments > 1) {
[invocation setArgument:&args atIndex:1];
}
}else{
signature = [target methodSignature];
//target is NSInvocation object
invocation = target;
signature = [target methodSignature];
if (args && signature.numberOfArguments > 2) {
[invocation setArgument:&args atIndex:2];
}
Expand All @@ -136,7 +86,7 @@ static id __execute__(id target, id args){
@interface AYPromise()
@property (nonatomic) dispatch_queue_t barrier;
@property (nonatomic, strong) id value;
@property (nonatomic, strong) NSMutableArray<PSResolve> *handlers;
@property (nonatomic, strong) NSMutableArray<AYResolve> *handlers;
@end

@implementation AYPromise
Expand All @@ -151,11 +101,11 @@ - (NSMutableArray *)handlers{
/**
* 创建一个未执行的Promise
*/
- (instancetype)initWithResolver:(void (^)(PSResolve))resolver{
- (instancetype)initWithResolver:(void (^)(AYResolve))resolver{
if (self = [super init]) {
_state = AYPromiseStatePending;

PSResolve __presolve = ^(id result){
AYResolve __presolve = ^(id result){
__block NSMutableArray *handlers;
//保证执行链的顺序执行
dispatch_barrier_sync(self.barrier, ^{
Expand All @@ -171,12 +121,12 @@ - (instancetype)initWithResolver:(void (^)(PSResolve))resolver{
self.value = result;
}
});
for (PSResolve handler in handlers) {
for (AYResolve handler in handlers) {
handler(result);
}
};

PSResolve __resolve = ^(id result){
AYResolve __resolve = ^(id result){
if (self.state & AYPromiseStatePending) {
if (isPromise(result)) {
[result pipe:__presolve];
Expand Down Expand Up @@ -224,7 +174,7 @@ - (instancetype)initWithValue:(id)value{
* 如果当前Promise还没有被执行,则接接在当前Promise的执行栈中
* 如果当前Promise已经执行了,则直接将当前Promise的值传给下一个执行者
*/
- (void)pipe:(PSResolve)resolve{
- (void)pipe:(AYResolve)resolve{
if (self.state == AYPromiseStatePending) {
[self.handlers addObject:resolve];
}else{
Expand All @@ -236,8 +186,8 @@ - (void)pipe:(PSResolve)resolve{
* 创建一个Promise,并拼接在Promise(self)的执行链中
*
*/
static inline AYPromise *__pipe(AYPromise *self, void(^then)(id, PSResolve)){
return [[AYPromise alloc] initWithResolver:^(PSResolve resolver) {
static inline AYPromise *__pipe(AYPromise *self, void(^then)(id, AYResolve)){
return [[AYPromise alloc] initWithResolver:^(AYResolve resolver) {
[self pipe:^(id result) {
then(result, resolver);//handle resule of previous promise
}];
Expand All @@ -248,7 +198,7 @@ - (void)pipe:(PSResolve)resolve{
* 将Promise拼接在self之后,仅处理正确的逻辑
*/
static inline AYPromise *__then(AYPromise *self, dispatch_queue_t queue, id block){
return __pipe(self, ^(id result, PSResolve resolver) {
return __pipe(self, ^(id result, AYResolve resolver) {
if (isError(result)) {
resolver(result);
}else{
Expand All @@ -262,7 +212,7 @@ - (void)pipe:(PSResolve)resolve{
* 将Promise接接在self之后,仅处理错误的逻辑
*/
static inline AYPromise *__catch(AYPromise *self, dispatch_queue_t queue, id block){
return __pipe(self, ^(id result, PSResolve resolver) {
return __pipe(self, ^(id result, AYResolve resolver) {
if (isError(result)) {
dispatch_async(queue, ^{
resolver(__execute__(block, result));
Expand All @@ -284,7 +234,7 @@ @implementation AYPromise (CommonJS)

+ (AYPromise *(^)(NSArray<AYPromise *> *))all{
return ^(NSArray<AYPromise *> *promises){
return [[AYPromise alloc] initWithResolver:^(PSResolve resolve) {
return [[AYPromise alloc] initWithResolver:^(AYResolve resolve) {
NSAssert(isArray(promises), @"all can only hand array");

__block int64_t totalCount = [promises count];
Expand Down Expand Up @@ -316,7 +266,7 @@ @implementation AYPromise (CommonJS)
return ^(NSArray<AYPromise *> *promises){
NSAssert(isArray(promises), @"race can only hand array");

return [[AYPromise alloc] initWithResolver:^(PSResolve resolve) {
return [[AYPromise alloc] initWithResolver:^(AYResolve resolve) {
__block int64_t totalCount = [promises count];
for (__strong id promise in promises) {
if (!isPromise(promise)) {
Expand Down Expand Up @@ -375,7 +325,7 @@ @implementation AYPromise (Extension)
- (AYPromise *(^)(NSTimeInterval, id))thenDelay{
return ^(NSTimeInterval delaySecond, id value){
NSAssert(isBlock(value) || isInvocation(value), @"[thenDelay] can only handle block/invocation.");
return __pipe(self, ^(id result, PSResolve resolver) {
return __pipe(self, ^(id result, AYResolve resolver) {
if (isError(result)) {
resolver(result);
}else{
Expand All @@ -396,9 +346,9 @@ @implementation AYPromise (Extension)
};
}

- (AYPromise * (^)(void (^)(id, PSResolve)))thenPromise{
return ^(void (^resolver)(id, PSResolve)){
return __pipe(self, ^(id result, PSResolve resolve) {
- (AYPromise * (^)(void (^)(id, AYResolve)))thenPromise{
return ^(void (^resolver)(id, AYResolve)){
return __pipe(self, ^(id result, AYResolve resolve) {
if (!isError(result)) {
dispatch_async(dispatch_get_main_queue(), ^{
@try {
Expand Down Expand Up @@ -432,7 +382,7 @@ @implementation AYPromise (Extension)
- (AYPromise *(^)(id))always{
return ^(id value){
NSAssert(isBlock(value) || isInvocation(value), @"[always] can only handle block/invocation.");
return __pipe(self, ^(id result, PSResolve resolver) {
return __pipe(self, ^(id result, AYResolve resolver) {
dispatch_async(dispatch_get_main_queue(), ^{
@try {
resolver(__execute__(value, result));
Expand Down Expand Up @@ -464,7 +414,7 @@ @implementation AYPromise (Extension)
}
}

AYPromise *AYPromiseWithResolve(void (^resolver)(PSResolve)){
AYPromise *AYPromiseWithResolve(void (^resolver)(AYResolve)){
return [[AYPromise alloc] initWithResolver:resolver];
}

6 changes: 5 additions & 1 deletion Example/AYPromise.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
1D37FD491D42044700A690FD /* ErrorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D37FD481D42044700A690FD /* ErrorTest.m */; };
1D37FD4B1D42048800A690FD /* PromiseTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D37FD4A1D42048800A690FD /* PromiseTest.m */; };
1D37FD4D1D4204B400A690FD /* ThreadTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D37FD4C1D4204B400A690FD /* ThreadTest.m */; };
5D4500A51D50BDEC005D1483 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5D4500A41D50BDEC005D1483 /* Launch Screen.storyboard */; };
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; };
6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
Expand Down Expand Up @@ -41,6 +42,7 @@
1D37FD481D42044700A690FD /* ErrorTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ErrorTest.m; sourceTree = "<group>"; };
1D37FD4A1D42048800A690FD /* PromiseTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PromiseTest.m; sourceTree = "<group>"; };
1D37FD4C1D4204B400A690FD /* ThreadTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThreadTest.m; sourceTree = "<group>"; };
5D4500A41D50BDEC005D1483 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = "<group>"; };
6003F58A195388D20070C39A /* AYPromise_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AYPromise_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
6003F58F195388D20070C39A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
Expand Down Expand Up @@ -136,10 +138,11 @@
children = (
6003F59C195388D20070C39A /* AYAppDelegate.h */,
6003F59D195388D20070C39A /* AYAppDelegate.m */,
873B8AEA1B1F5CCA007FD442 /* Main.storyboard */,
6003F5A5195388D20070C39A /* AYViewController.h */,
6003F5A6195388D20070C39A /* AYViewController.m */,
6003F5A8195388D20070C39A /* Images.xcassets */,
5D4500A41D50BDEC005D1483 /* Launch Screen.storyboard */,
873B8AEA1B1F5CCA007FD442 /* Main.storyboard */,
6003F594195388D20070C39A /* Supporting Files */,
);
name = "Example for AYPromise";
Expand Down Expand Up @@ -290,6 +293,7 @@
files = (
873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */,
6003F5A9195388D20070C39A /* Images.xcassets in Resources */,
5D4500A51D50BDEC005D1483 /* Launch Screen.storyboard in Resources */,
6003F598195388D20070C39A /* InfoPlist.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
Loading

0 comments on commit bc250f1

Please sign in to comment.