0

我必须上传多个文件,跟踪它们的进度并订阅完成和失败块,以便在操作结束时显示相关消息。

我编写了自己的 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];
}

调用此方法的视图控制器不会被释放,因此包含的所有图像也会保留在内存中,从而导致内存泄漏并最终导致内存警告。

进行分析表明,在整个操作结束时,视图控制器的 arefCount为 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];
}

通知由父控制器接收,从父视图中删除此控制器的视图并将其设置为 nil。

PS CRLMultiPartFile 是一个自定义类,用于保存要上传的文件的属性

4

1 回答 1

1

如果您使用的是 ARC,则应使用__weak而不是__block,因此您不会self在块内捕获。

于 2013-04-15T05:55:19.043 回答