Browse Source

Fix IOS memory leaks

Ben Hsieh 8 years ago
parent
commit
b617a8ca1a

+ 2
- 6
src/ios/RNFetchBlob/RNFetchBlob.m View File

63
                   callback:(RCTResponseSenderBlock)callback)
63
                   callback:(RCTResponseSenderBlock)callback)
64
 {
64
 {
65
 
65
 
66
-    [RNFetchBlobReqBuilder buildMultipartRequest:options taskId:taskId method:method url:url headers:headers form:form onComplete:^(NSURLRequest *req, long bodyLength) {
66
+    [RNFetchBlobReqBuilder buildMultipartRequest:options taskId:taskId method:method url:url headers:headers form:form onComplete:^(__weak NSURLRequest *req, long bodyLength) {
67
         // send HTTP request
67
         // send HTTP request
68
         RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init];
68
         RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init];
69
         [utils sendRequest:options contentLength:bodyLength bridge:self.bridge taskId:taskId withRequest:req callback:callback];
69
         [utils sendRequest:options contentLength:bodyLength bridge:self.bridge taskId:taskId withRequest:req callback:callback];
70
-        utils = nil;
71
     }];
70
     }];
72
 
71
 
73
 }
72
 }
80
                   headers:(NSDictionary *)headers
79
                   headers:(NSDictionary *)headers
81
                   body:(NSString *)body callback:(RCTResponseSenderBlock)callback)
80
                   body:(NSString *)body callback:(RCTResponseSenderBlock)callback)
82
 {
81
 {
83
-    NSString *cType = [headers valueForKey:@"content-type"];
84
-    
85
     [RNFetchBlobReqBuilder buildOctetRequest:options taskId:taskId method:method url:url headers:headers body:body onComplete:^(NSURLRequest *req, long bodyLength) {
82
     [RNFetchBlobReqBuilder buildOctetRequest:options taskId:taskId method:method url:url headers:headers body:body onComplete:^(NSURLRequest *req, long bodyLength) {
86
         // send HTTP request
83
         // send HTTP request
87
-        RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init];
84
+        __block RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init];
88
         [utils sendRequest:options contentLength:bodyLength bridge:self.bridge taskId:taskId withRequest:req callback:callback];
85
         [utils sendRequest:options contentLength:bodyLength bridge:self.bridge taskId:taskId withRequest:req callback:callback];
89
-        utils = nil;
90
     }];
86
     }];
91
 }
87
 }
92
 
88
 

+ 5
- 4
src/ios/RNFetchBlobFS.m View File

304
     @try
304
     @try
305
     {
305
     {
306
         [[self class] getPathFromUri:path completionHandler:^(NSString *path, ALAssetRepresentation *asset) {
306
         [[self class] getPathFromUri:path completionHandler:^(NSString *path, ALAssetRepresentation *asset) {
307
-            NSData * fileContent;
307
+            __block NSData * fileContent;
308
             NSError * err;
308
             NSError * err;
309
-            Byte * buffer;
309
+            __block Byte * buffer;
310
             if(asset != nil)
310
             if(asset != nil)
311
             {
311
             {
312
                 buffer = malloc(asset.size);
312
                 buffer = malloc(asset.size);
672
     if([uri hasPrefix:AL_PREFIX])
672
     if([uri hasPrefix:AL_PREFIX])
673
     {
673
     {
674
         NSURL *asseturl = [NSURL URLWithString:uri];
674
         NSURL *asseturl = [NSURL URLWithString:uri];
675
-        ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
675
+        __block ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
676
         [assetslibrary assetForURL:asseturl
676
         [assetslibrary assetForURL:asseturl
677
                        resultBlock:^(ALAsset *asset) {
677
                        resultBlock:^(ALAsset *asset) {
678
-                           onComplete(nil, [asset defaultRepresentation]);
678
+                           __block ALAssetRepresentation * present = [asset defaultRepresentation];
679
+                           onComplete(nil, present);
679
                        }
680
                        }
680
                       failureBlock:^(NSError *error) {
681
                       failureBlock:^(NSError *error) {
681
                           onComplete(nil, nil);
682
                           onComplete(nil, nil);

+ 22
- 7
src/ios/RNFetchBlobNetwork.m View File

109
 }
109
 }
110
 
110
 
111
 // send HTTP request
111
 // send HTTP request
112
-- (void) sendRequest:(NSDictionary  * _Nullable )options
112
+- (void) sendRequest:(__weak NSDictionary  * _Nullable )options
113
        contentLength:(long) contentLength
113
        contentLength:(long) contentLength
114
               bridge:(RCTBridge * _Nullable)bridgeRef
114
               bridge:(RCTBridge * _Nullable)bridgeRef
115
               taskId:(NSString * _Nullable)taskId
115
               taskId:(NSString * _Nullable)taskId
116
-         withRequest:(NSURLRequest * _Nullable)req
116
+         withRequest:(__weak NSURLRequest * _Nullable)req
117
             callback:(_Nullable RCTResponseSenderBlock) callback
117
             callback:(_Nullable RCTResponseSenderBlock) callback
118
 {
118
 {
119
     self.taskId = taskId;
119
     self.taskId = taskId;
127
     NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
127
     NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
128
     NSString * ext = [self.options valueForKey:CONFIG_FILE_EXT];
128
     NSString * ext = [self.options valueForKey:CONFIG_FILE_EXT];
129
 	NSString * key = [self.options valueForKey:CONFIG_KEY];
129
 	NSString * key = [self.options valueForKey:CONFIG_KEY];
130
-    NSURLSession * session;
130
+    __block NSURLSession * session;
131
 
131
 
132
     bodyLength = contentLength;
132
     bodyLength = contentLength;
133
 
133
 
134
     // the session trust any SSL certification
134
     // the session trust any SSL certification
135
 
135
 
136
+    
136
     NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
137
     NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
137
     if([options valueForKey:@"timeout"] != nil)
138
     if([options valueForKey:@"timeout"] != nil)
138
     {
139
     {
139
         defaultConfigObject.timeoutIntervalForRequest = [[options valueForKey:@"timeout"] floatValue];
140
         defaultConfigObject.timeoutIntervalForRequest = [[options valueForKey:@"timeout"] floatValue];
140
     }
141
     }
141
     session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:taskQueue];
142
     session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:taskQueue];
142
-    
143
     if(path != nil || [self.options valueForKey:CONFIG_USE_TEMP]!= nil)
143
     if(path != nil || [self.options valueForKey:CONFIG_USE_TEMP]!= nil)
144
     {
144
     {
145
         respFile = YES;
145
         respFile = YES;
229
                      @"timeout" : @NO,
229
                      @"timeout" : @NO,
230
                      @"status": [NSString stringWithFormat:@"%d", statusCode ]
230
                      @"status": [NSString stringWithFormat:@"%d", statusCode ]
231
                      };
231
                      };
232
+        
232
         [self.bridge.eventDispatcher
233
         [self.bridge.eventDispatcher
233
          sendDeviceEventWithName: EVENT_STATE_CHANGE
234
          sendDeviceEventWithName: EVENT_STATE_CHANGE
234
          body:respInfo
235
          body:respInfo
235
-         ];
236
+        ];
237
+        headers = nil;
238
+        respInfo = nil;
236
     }
239
     }
237
 
240
 
238
     if(respFile == YES)
241
     if(respFile == YES)
259
 // download progress handler
262
 // download progress handler
260
 - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
263
 - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
261
 {
264
 {
262
-    receivedBytes += [data length];
265
+    NSNumber * received = [NSNumber numberWithLong:[data length]];
266
+    receivedBytes += [received longValue];
263
     if(respFile == NO)
267
     if(respFile == NO)
264
     {
268
     {
265
         [respData appendData:data];
269
         [respData appendData:data];
280
                 }
284
                 }
281
          ];
285
          ];
282
     }
286
     }
287
+    received = nil;
283
 
288
 
284
 }
289
 }
285
 
290
 
286
-- (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
291
+- (void) URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error
292
+{
293
+    if([session isEqual:session])
294
+        session = nil;
295
+}
296
+
297
+- (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
298
+{
287
     
299
     
288
     self.error = error;
300
     self.error = error;
289
     [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
301
     [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
313
     [taskTable removeObjectForKey:taskId];
325
     [taskTable removeObjectForKey:taskId];
314
     [uploadProgressTable removeObjectForKey:taskId];
326
     [uploadProgressTable removeObjectForKey:taskId];
315
     [progressTable removeObjectForKey:taskId];
327
     [progressTable removeObjectForKey:taskId];
328
+    respData = nil;
329
+    receivedBytes = 0;
330
+    [session finishTasksAndInvalidate];
316
 }
331
 }
317
 
332
 
318
 // upload progress handler
333
 // upload progress handler

+ 1
- 1
src/ios/RNFetchBlobReqBuilder.h View File

35
                          url:(NSString *)url
35
                          url:(NSString *)url
36
                      headers:(NSDictionary *)headers
36
                      headers:(NSDictionary *)headers
37
                         form:(NSString *)body
37
                         form:(NSString *)body
38
-                  onComplete:(void(^)(NSURLRequest * req, long bodyLength))onComplete;
38
+                  onComplete:(void(^)(__weak NSURLRequest * req, long bodyLength))onComplete;
39
 
39
 
40
 +(NSString *) getHeaderIgnoreCases:(NSString *)field fromHeaders:(NSMutableArray *) headers;
40
 +(NSString *) getHeaderIgnoreCases:(NSString *)field fromHeaders:(NSMutableArray *) headers;
41
 
41
 

+ 8
- 8
src/ios/RNFetchBlobReqBuilder.m View File

34
     NSString * encodedUrl = url;
34
     NSString * encodedUrl = url;
35
     
35
     
36
     // send request
36
     // send request
37
-    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString: encodedUrl]];
37
+    __block NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString: encodedUrl]];
38
     NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[RNFetchBlobNetwork normalizeHeaders:headers]];
38
     NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[RNFetchBlobNetwork normalizeHeaders:headers]];
39
     NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
39
     NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
40
     NSNumber * timeStampObj = [NSNumber numberWithDouble: timeStamp];
40
     NSNumber * timeStampObj = [NSNumber numberWithDouble: timeStamp];
42
     // generate boundary
42
     // generate boundary
43
     NSString * boundary = [NSString stringWithFormat:@"RNFetchBlob%d", timeStampObj];
43
     NSString * boundary = [NSString stringWithFormat:@"RNFetchBlob%d", timeStampObj];
44
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
44
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
45
-        NSMutableData * postData = [[NSMutableData alloc] init];
45
+        __block NSMutableData * postData = [[NSMutableData alloc] init];
46
         // combine multipart/form-data body
46
         // combine multipart/form-data body
47
         [[self class] buildFormBody:form boundary:boundary onComplete:^(NSData *formData) {
47
         [[self class] buildFormBody:form boundary:boundary onComplete:^(NSData *formData) {
48
             if(formData != nil) {
48
             if(formData != nil) {
71
                       url:(NSString *)url
71
                       url:(NSString *)url
72
                   headers:(NSDictionary *)headers
72
                   headers:(NSDictionary *)headers
73
                      body:(NSString *)body
73
                      body:(NSString *)body
74
-               onComplete:(void(^)(NSURLRequest * req, long bodyLength))onComplete
74
+               onComplete:(void(^)(__weak NSURLRequest * req, long bodyLength))onComplete
75
 {
75
 {
76
 //    NSString * encodedUrl = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
76
 //    NSString * encodedUrl = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
77
     NSString * encodedUrl = url;
77
     NSString * encodedUrl = url;
78
     // send request
78
     // send request
79
-    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
79
+    __block NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
80
                                     initWithURL:[NSURL URLWithString: encodedUrl]];
80
                                     initWithURL:[NSURL URLWithString: encodedUrl]];
81
 
81
 
82
-    NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[RNFetchBlobNetwork normalizeHeaders:headers]];
82
+    __block NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[RNFetchBlobNetwork normalizeHeaders:headers]];
83
     // move heavy task to another thread
83
     // move heavy task to another thread
84
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
84
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
85
         NSMutableData * blobData;
85
         NSMutableData * blobData;
88
         if([[method lowercaseString] isEqualToString:@"post"] || [[method lowercaseString] isEqualToString:@"put"]) {
88
         if([[method lowercaseString] isEqualToString:@"post"] || [[method lowercaseString] isEqualToString:@"put"]) {
89
             // generate octet-stream body
89
             // generate octet-stream body
90
             if(body != nil) {
90
             if(body != nil) {
91
-                NSString * cType = [[self class] getHeaderIgnoreCases:@"content-type" fromHeaders:mheaders];
91
+                __block NSString * cType = [[self class] getHeaderIgnoreCases:@"content-type" fromHeaders:mheaders];
92
                 // when headers does not contain a key named "content-type" (case ignored), use default content type
92
                 // when headers does not contain a key named "content-type" (case ignored), use default content type
93
                 if(cType == nil)
93
                 if(cType == nil)
94
                 {
94
                 {
97
                 
97
                 
98
                 // when body is a string contains file path prefix, try load file from the path
98
                 // when body is a string contains file path prefix, try load file from the path
99
                 if([body hasPrefix:FILE_PREFIX]) {
99
                 if([body hasPrefix:FILE_PREFIX]) {
100
-                    NSString * orgPath = [body substringFromIndex:[FILE_PREFIX length]];
100
+                    __block NSString * orgPath = [body substringFromIndex:[FILE_PREFIX length]];
101
                     orgPath = [RNFetchBlobFS getPathOfAsset:orgPath];
101
                     orgPath = [RNFetchBlobFS getPathOfAsset:orgPath];
102
                     if([orgPath hasPrefix:AL_PREFIX])
102
                     if([orgPath hasPrefix:AL_PREFIX])
103
                     {
103
                     {
115
                 // otherwise convert it as BASE64 data string
115
                 // otherwise convert it as BASE64 data string
116
                 else {
116
                 else {
117
                     
117
                     
118
-                    NSString * cType = [[self class]getHeaderIgnoreCases:@"content-type" fromHeaders:mheaders];
118
+                    __block NSString * cType = [[self class]getHeaderIgnoreCases:@"content-type" fromHeaders:mheaders];
119
                     // when content-type is application/octet* decode body string using BASE64 decoder
119
                     // when content-type is application/octet* decode body string using BASE64 decoder
120
                     if([[cType lowercaseString] hasPrefix:@"application/octet"] || [[cType lowercaseString] containsString:@";base64"])
120
                     if([[cType lowercaseString] hasPrefix:@"application/octet"] || [[cType lowercaseString] containsString:@";base64"])
121
                     {
121
                     {