참고 : 저는 ARC를 사용하고 있습니다.AFNetworking NSOperations를 사용하여 여러 파일을 연속적으로 다운로드하는 중 ..... 메모리가 부족합니다.
HTTP 서버에서 JSON을 통해 파일 목록을 요청하는 코드가 있습니다. 그런 다음이 목록을 모델 객체로 구문 분석하여 다운로드 작업 (파일 다운로드 용)을 다른 nsoperationue에 추가 한 다음 모든 작업을 추가하면 (대기열이 일시 중단됨) 대기열에서 빠져 나와 대기합니다. 계속하기 전에 모든 작업을 완료해야합니다. (주 : 이것은 메인 스레드를 막지 않도록 백그라운드 스레드에서 모두 수행됩니다). 다음
NSURLRequest* request = [NSURLRequest requestWithURL:parseServiceUrl];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
op.responseSerializer = [AFJSONResponseSerializer serializer];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
//NSLog(@"JSON: %@", responseObject);
// Parse JSON into model objects
NSNumber* results = [responseObject objectForKey:@"results"];
if ([results intValue] > 0)
{
dispatch_async(_processQueue, ^{
_totalFiles = [results intValue];
_timestamp = [responseObject objectForKey:@"timestamp"];
NSArray* files = [responseObject objectForKey:@"files"];
for (NSDictionary* fileDict in files)
{
DownloadableFile* file = [[DownloadableFile alloc] init];
file.file_id = [fileDict objectForKey:@"file_id"];
file.file_location = [fileDict objectForKey:@"file_location"];
file.timestamp = [fileDict objectForKey:@"timestamp"];
file.orderInQueue = [files indexOfObject:fileDict];
NSNumber* action = [fileDict objectForKey:@"action"];
if ([action intValue] >= 1)
{
if ([file.file_location.lastPathComponent.pathExtension isEqualToString:@""])
{
continue;
}
[self downloadSingleFile:file];
}
else // action == 0 so DELETE file if it exists
{
if ([[NSFileManager defaultManager] fileExistsAtPath:file.localPath])
{
NSError* error;
[[NSFileManager defaultManager] removeItemAtPath:file.localPath error:&error];
if (error)
{
NSLog(@"Error deleting file after given an Action of 0: %@: %@", file.file_location, error);
}
}
}
[self updateProgress:[files indexOfObject:fileDict] withTotal:[files count]];
}
dispatch_sync(dispatch_get_main_queue(), ^{
[_label setText:@"Syncing Files..."];
});
[_dlQueue setSuspended:NO];
[_dlQueue waitUntilAllOperationsAreFinished];
[SettingsManager sharedInstance].timestamp = _timestamp;
dispatch_async(dispatch_get_main_queue(), ^{
callback(nil);
});
});
}
else
{
dispatch_async(dispatch_get_main_queue(), ^{
callback(nil);
});
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
callback(error);
}];
[_parseQueue addOperation:op];
과 downloadSingleFile 방법 : 더 많은 파일을 다운로드받을으로
- (void)downloadSingleFile:(DownloadableFile*)dfile
{
NSURLRequest* req = [NSURLRequest requestWithURL:dfile.downloadUrl];
AFHTTPRequestOperation* reqOper = [[AFHTTPRequestOperation alloc] initWithRequest:req];
reqOper.responseSerializer = [AFHTTPResponseSerializer serializer];
[reqOper setCompletionBlockWithSuccess:^(AFHTTPRequestOperation* op, id response)
{
__weak NSData* fileData = response;
NSError* error;
__weak DownloadableFile* file = dfile;
NSString* fullPath = [file.localPath substringToIndex:[file.localPath rangeOfString:file.localPath.lastPathComponent options:NSBackwardsSearch].location];
[[NSFileManager defaultManager] createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:Nil error:&error];
if (error)
{
NSLog(@"Error creating directory path: %@: %@", fullPath, error);
}
else
{
error = nil;
[fileData writeToFile:file.localPath options:NSDataWritingFileProtectionComplete error:&error];
if (error)
{
NSLog(@"Error writing fileData for file: %@: %@", file.file_location, error);
}
}
[self updateProgress:file.orderInQueue withTotal:_totalFiles];
}
failure:^(AFHTTPRequestOperation* op, NSError* error)
{
[self updateProgress:dfile.orderInQueue withTotal:_totalFiles];
NSLog(@"Error downloading %@: %@", dfile.downloadUrl, error.localizedDescription);
}];
[_dlQueue addOperation:reqOper];
}
내가보고하고있어 메모리에 일정한 스파이크가
는 여기에 기본 코드입니다. 그것은 responseObject 또는 어쩌면 전체 completionBlock과 같은 것입니다.
나는 fileData뿐만 아니라 responseObject __weak을 만들려고 시도했다. 나는 autoreleasepool을 추가하려고 시도하고 실제 파일 도메인 객체 __weak을 만들려고했으나 여전히 메모리가 올라 타고 올라갔습니다.
저는 Instruments를 실행했는데 누출은 없었지만 메모리가 부족해지기 전에 모든 파일이 다운로드 된 지점에 도달하지 못했습니다. "fat not allocate region"오류가 발생했습니다. 할당을 살펴보면 didFinishLoading 및 connection : didReceiveData 메소드가 연결되지 않는 것으로 나타났습니다. 나는 그것보다 더 그것을 디버깅 할 수없는 것.
내 질문 : 왜 메모리가 부족합니까? 할당 해제되지 않는 것은 무엇이며 어떻게 그렇게 할 수 있습니까?
트위터의 누군가가 [self updateProgress]를 사용하고 있기 때문에 자기가 보유하고 있다고 언급 했으므로 컨트롤러가 소유하고있는 작업 큐 소유의 작업이 소유하고있는 완료 블록 내에 유지됩니다. 컨트롤러 ..... 그래서 유지주기가 있습니다. 직접 [self updateProgress] 코드를 블록으로 직접 옮기면 어떻게 될지 알아야합니다. – valheru
[self updateProgress]를 제거해도 문제가 해결되지 않음을 유의하십시오. – valheru