Skip to content

Commit

Permalink
修复promise.all的内存泄露问题
Browse files Browse the repository at this point in the history
  • Loading branch information
alan committed Dec 10, 2018
1 parent e09b644 commit d02c766
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 15 deletions.
2 changes: 1 addition & 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.5'
s.version = '1.1.6'
s.summary = 'Promise for objective-c.'

s.homepage = 'https://github.com/alan-yeh/AYPromise'
Expand Down
6 changes: 3 additions & 3 deletions AYPromise/Classes/AYPromise.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ FOUNDATION_EXPORT NSString * const AYPromiseInternalErrorsKey;
* @param localizedDescription 错误描述
* @param internalErrors 内部错误,通过error.userInfo[AYPromiseInternalErrorsKey]可以获得
*/
NSError *NSErrorMake(id _Nullable internalErrors, NSString *localizedDescription, ...) NS_FORMAT_FUNCTION(2,3);
NSError *NSErrorWithUserInfo(NSDictionary *userInfo, NSString *localizedDescription, ...) NS_FORMAT_FUNCTION(2,3);
FOUNDATION_EXPORT NSError *NSErrorMake(id _Nullable internalErrors, NSString *localizedDescription, ...) NS_FORMAT_FUNCTION(2,3);
FOUNDATION_EXPORT NSError *NSErrorWithUserInfo(NSDictionary *userInfo, NSString *localizedDescription, ...) NS_FORMAT_FUNCTION(2,3);

NSInvocation *NSInvocationMake(id target, SEL action);
FOUNDATION_EXPORT NSInvocation *NSInvocationMake(id target, SEL action);

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

Expand Down
22 changes: 16 additions & 6 deletions AYPromise/Classes/AYPromise.m
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,14 @@ static id __execute__(id target, id args){
}

@interface AYPromise()
@property (nonatomic) dispatch_queue_t barrier;
//@property (nonatomic) dispatch_queue_t barrier;
@property (nonatomic, strong) id value;
@property (nonatomic, strong) NSMutableArray<AYResolve> *handlers;
@property (nonatomic, assign) AYPromiseState state;
@end

@implementation AYPromise
static dispatch_queue_t _barrier = nil;
- (dispatch_queue_t)barrier{
return _barrier ?: (_barrier = dispatch_queue_create("cn.yerl.promise.barrier", DISPATCH_QUEUE_CONCURRENT));
}
Expand Down Expand Up @@ -262,7 +263,10 @@ @implementation AYPromise (CommonJS)
NSAssert(isArray(promises), @"all can only hand array");

__block int64_t totalCount = [promises count];
NSMutableArray *holders = [NSMutableArray arrayWithArray:promises];

for (__strong id promise in promises) {

if (!isPromise(promise)) {
promise = AYPromise.resolve(promise);
}
Expand All @@ -273,11 +277,12 @@ @implementation AYPromise (CommonJS)
userInfo:@{NSLocalizedDescriptionKey: [result localizedDescription],
AYPromiseInternalErrorsKey: result}]);
}else if (OSAtomicDecrement64(&totalCount) == 0){
id results = [NSMutableArray new];
for (AYPromise *promise in promises) {
NSMutableArray *results = [NSMutableArray new];
for (AYPromise *promise in holders) {
id value = isPromise(promise) ? [promise value] : promise;
[results addObject:value ?: [NSNull null]];
}
[holders removeAllObjects];
resolve(results);
}
}];
Expand All @@ -292,18 +297,23 @@ @implementation AYPromise (CommonJS)

return [[AYPromise alloc] initWithResolver:^(AYResolve resolve) {
__block int64_t totalCount = [promises count];
NSMutableArray *holders = [NSMutableArray arrayWithArray:promises];

for (__strong id promise in promises) {
if (!isPromise(promise)) {
promise = [[AYPromise alloc] initWithValue:promise];
}

[promise pipe:^(id result) {
if (!isError(result)) {
[holders removeAllObjects];
resolve(result);
}else if (OSAtomicDecrement64(&totalCount) == 0){
id errors = [NSMutableArray new];
for (AYPromise *promise in promises) {
} else if (OSAtomicDecrement64(&totalCount) == 0){
NSMutableArray *errors = [NSMutableArray new];
for (AYPromise *promise in holders) {
[errors addObject:isPromise(promise) ? [promise value] : promise];
}
[holders removeAllObjects];
resolve([NSError errorWithDomain:@"cn.yerl.promise"
code:-1000
userInfo:@{NSLocalizedDescriptionKey: @"all promise were rejected",
Expand Down
25 changes: 25 additions & 0 deletions Example/AYPromise/Images.xcassets/AppIcon.appiconset/Contents.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
Expand Down Expand Up @@ -30,6 +40,16 @@
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
Expand Down Expand Up @@ -64,6 +84,11 @@
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
Expand Down
35 changes: 30 additions & 5 deletions Example/Tests/PromiseTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ - (void)testPipe{
- (void)testPromiseAll{
id ex1 = [self expectationWithDescription:@""];

AYPromise *p1 = AYPromiseWithResolve(^(AYResolve _Nonnull resolve) {
XCTAssertEqual([NSThread currentThread].isMainThread, YES);
AYPromise *p1 = AYPromiseAsyncWithResolve(^(AYResolve _Nonnull resolve) {
XCTAssertEqual([NSThread currentThread].isMainThread, NO);
resolve(@"thread1");
});

Expand All @@ -168,10 +168,35 @@ - (void)testPromiseAll{
resolve(@"thread2");
});

AYPromise.all(@[@"1", p1, p2]).then(^(NSArray<NSString *> *result){
BOOL isEqual = [result isEqualToArray:@[@"1", @"thread1", @"thread2"]];
AYPromise *p3 = AYPromiseAsyncWithResolve(^(AYResolve _Nonnull resolve) {
XCTAssertEqual([NSThread currentThread].isMainThread, NO);
resolve(@"thread3");
});

AYPromise *p4 = AYPromiseWithResolve(^(AYResolve _Nonnull resolve) {
XCTAssertEqual([NSThread currentThread].isMainThread, YES);
resolve(@"thread4");
});

AYPromise *p5 = AYPromiseAsyncWithResolve(^(AYResolve _Nonnull resolve) {
XCTAssertEqual([NSThread currentThread].isMainThread, NO);
resolve(@"thread5");
});

AYPromise *p6 = AYPromiseWithResolve(^(AYResolve _Nonnull resolve) {
XCTAssertEqual([NSThread currentThread].isMainThread, YES);
resolve(@"thread6");
});

AYPromise.all(@[p1, p2, p3, p4, p5, p6]).then(^(NSArray<NSString *> *result){
NSLog(@"%@", result);
BOOL isEqual = [result isEqualToArray:@[@"thread1", @"thread2", @"thread3", @"thread4", @"thread5", @"thread6"]];
XCTAssert(isEqual);
[ex1 fulfill];
}).catch(^(NSError *error){
NSLog(@"error");
}).always(^{
NSLog(@"always");
});

[self waitForExpectationsWithTimeout:TIME_OUT handler:nil];
Expand Down Expand Up @@ -272,4 +297,4 @@ - (void)testThenInvocation{
[self waitForExpectationsWithTimeout:TIME_OUT handler:nil];
}

@end
@end

0 comments on commit d02c766

Please sign in to comment.