ソースを参照

Fix IOS memory leaks

Ben Hsieh 7 年 前
コミット
b617a8ca1a
共有5 個のファイルを変更した38 個の追加26 個の削除を含む
  1. 2
    6
      src/ios/RNFetchBlob/RNFetchBlob.m
  2. 5
    4
      src/ios/RNFetchBlobFS.m
  3. 22
    7
      src/ios/RNFetchBlobNetwork.m
  4. 1
    1
      src/ios/RNFetchBlobReqBuilder.h
  5. 8
    8
      src/ios/RNFetchBlobReqBuilder.m

+ 2
- 6
src/ios/RNFetchBlob/RNFetchBlob.m ファイルの表示

@@ -63,11 +63,10 @@ RCT_EXPORT_METHOD(fetchBlobForm:(NSDictionary *)options
63 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 67
         // send HTTP request
68 68
         RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init];
69 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,13 +79,10 @@ RCT_EXPORT_METHOD(fetchBlob:(NSDictionary *)options
80 79
                   headers:(NSDictionary *)headers
81 80
                   body:(NSString *)body callback:(RCTResponseSenderBlock)callback)
82 81
 {
83
-    NSString *cType = [headers valueForKey:@"content-type"];
84
-    
85 82
     [RNFetchBlobReqBuilder buildOctetRequest:options taskId:taskId method:method url:url headers:headers body:body onComplete:^(NSURLRequest *req, long bodyLength) {
86 83
         // send HTTP request
87
-        RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init];
84
+        __block RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init];
88 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 ファイルの表示

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

+ 22
- 7
src/ios/RNFetchBlobNetwork.m ファイルの表示

@@ -109,11 +109,11 @@ NSOperationQueue *taskQueue;
109 109
 }
110 110
 
111 111
 // send HTTP request
112
-- (void) sendRequest:(NSDictionary  * _Nullable )options
112
+- (void) sendRequest:(__weak NSDictionary  * _Nullable )options
113 113
        contentLength:(long) contentLength
114 114
               bridge:(RCTBridge * _Nullable)bridgeRef
115 115
               taskId:(NSString * _Nullable)taskId
116
-         withRequest:(NSURLRequest * _Nullable)req
116
+         withRequest:(__weak NSURLRequest * _Nullable)req
117 117
             callback:(_Nullable RCTResponseSenderBlock) callback
118 118
 {
119 119
     self.taskId = taskId;
@@ -127,19 +127,19 @@ NSOperationQueue *taskQueue;
127 127
     NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
128 128
     NSString * ext = [self.options valueForKey:CONFIG_FILE_EXT];
129 129
 	NSString * key = [self.options valueForKey:CONFIG_KEY];
130
-    NSURLSession * session;
130
+    __block NSURLSession * session;
131 131
 
132 132
     bodyLength = contentLength;
133 133
 
134 134
     // the session trust any SSL certification
135 135
 
136
+    
136 137
     NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
137 138
     if([options valueForKey:@"timeout"] != nil)
138 139
     {
139 140
         defaultConfigObject.timeoutIntervalForRequest = [[options valueForKey:@"timeout"] floatValue];
140 141
     }
141 142
     session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:taskQueue];
142
-    
143 143
     if(path != nil || [self.options valueForKey:CONFIG_USE_TEMP]!= nil)
144 144
     {
145 145
         respFile = YES;
@@ -229,10 +229,13 @@ NSOperationQueue *taskQueue;
229 229
                      @"timeout" : @NO,
230 230
                      @"status": [NSString stringWithFormat:@"%d", statusCode ]
231 231
                      };
232
+        
232 233
         [self.bridge.eventDispatcher
233 234
          sendDeviceEventWithName: EVENT_STATE_CHANGE
234 235
          body:respInfo
235
-         ];
236
+        ];
237
+        headers = nil;
238
+        respInfo = nil;
236 239
     }
237 240
 
238 241
     if(respFile == YES)
@@ -259,7 +262,8 @@ NSOperationQueue *taskQueue;
259 262
 // download progress handler
260 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 267
     if(respFile == NO)
264 268
     {
265 269
         [respData appendData:data];
@@ -280,10 +284,18 @@ NSOperationQueue *taskQueue;
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 300
     self.error = error;
289 301
     [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
@@ -313,6 +325,9 @@ NSOperationQueue *taskQueue;
313 325
     [taskTable removeObjectForKey:taskId];
314 326
     [uploadProgressTable removeObjectForKey:taskId];
315 327
     [progressTable removeObjectForKey:taskId];
328
+    respData = nil;
329
+    receivedBytes = 0;
330
+    [session finishTasksAndInvalidate];
316 331
 }
317 332
 
318 333
 // upload progress handler

+ 1
- 1
src/ios/RNFetchBlobReqBuilder.h ファイルの表示

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

+ 8
- 8
src/ios/RNFetchBlobReqBuilder.m ファイルの表示

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