我必须上传多个文件,跟踪他们的进度&订阅完成&故障块,以便在操作结束时显示相关消息。
我编写了自己的AFHTTPClient包装器并创建了以下方法。
- (void) uploadFiles:(NSArray*)files
path:(NSString*)path
parameters:(NSDictionary*)parameters
progressBlock:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block
success:(void (^)(AFHTTPRequestOperation *, id))success failure:(void (^)(AFHTTPRequestOperation *, NSError *))failure
{
NSMutableURLRequest *request =
[self multipartFormRequestWithMethod:@"POST"
path:path
parameters:parameters
constructingBodyWithBlock:
^(id <AFMultipartFormData>formData) {
for (CRLMultiPartFile *file in files) {
NSAssert(file.name, @"Name cannot be nil");
NSAssert(file.file, @"Nothing found to upload");
NSAssert(file.filename, @"FileName cannot be nil");
NSAssert(file.mimeType, @"Must set Mime-Type for %@", file.filename);
[formData appendPartWithFileData:file.file name:file.name fileName:file.filename mimeType:file.typeString];
}
}];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setUploadProgressBlock:block];
[operation setCompletionBlockWithSuccess:success failure:failure];
[self enqueueHTTPRequestOperation:operation];
}
调用此方法的视图控制器不会被取消分配,因此包含的所有图像也会保留在内存中,从而导致内存泄漏并最终导致内存警告。
进行性能分析后发现,在整个操作结束时,视图控制器的refCount
为1。
当我注释掉上传文件的电话时,一切正常。
这是控制器中的代码。它使用进度块来更新UI上的元素。
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
ContactModel *model = (ContactModel*)[self.contacts lastObject];
[params setObject:model.phone forKey:@"receiver"];
__block typeof(self) sSelf = self;
[[JMClient sharedClient] uploadFiles:files
path:@"picture_share/"
parameters:params
progressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
CGFloat progPercent = ceilf(((CGFloat)totalBytesWritten / (CGFloat)totalBytesExpectedToWrite) * 100);
CGFloat widthToCut = (progPercent * sSelf.progWidth) / 100;
CGRect frame = sSelf.progresViewBG.frame;
frame.size.width = (sSelf.progWidth - widthToCut);
frame.origin.x = (sSelf.progOrigin + widthToCut);
sSelf.progresViewBG.frame = frame;
sSelf.progLabel.text = [NSString stringWithFormat:@"%i%%", (int)progPercent];
frame = sSelf.progTipView.frame;
frame.origin.x = (sSelf.progresViewBG.frame.origin.x - frame.size.width/2);
sSelf.progTipView.frame = frame;
frame = sSelf.progLabel.frame;
frame.origin.x = (sSelf.progresViewBG.frame.origin.x - frame.size.width/2);
sSelf.progLabel.frame = frame;
} success:^(AFHTTPRequestOperation *success, id reponse) {
CGRect frame = sSelf.progresViewBG.frame;
frame.size.width = 0;
frame.origin.x = sSelf.progOrigin;
sSelf.progresViewBG.frame = frame;
[sSelf.cancelButton setImage:[UIImage imageNamed:@"trnsfr_prgss_complt.png"] forState:UIControlStateNormal];
[sSelf performSelector:@selector(hideAwayProgressBars) withObject:nil afterDelay:3];
} failure:^(AFHTTPRequestOperation *failure, NSError *error) {
[Mediator showMessage:TGLocalizedString(kMessageKeyForUploadingFailed)];
[sSelf performSelector:@selector(hideAwayProgressBars) withObject:nil afterDelay:3];
}];
self.operation = [[self.client.sharedClient.operationQueue operations] lastObject];
- (void) hideAwayProgressBars
{
[[NSNotificationCenter defaultCenter] postNotificationName:kNotifcationKeyForPhotoUploadComplete object:nil];
}
父控制器收到通知,从superview中删除该控制器的视图并将其设置为nil。
P.S。 CRLMultiPartFile是一个自定义类,用于保存要上载的文件的属性
答案 0 :(得分:1)
如果您使用ARC,则应使用__weak
而不是__block
,因此您不会在块内捕获self
。