iOS:我可以在block中执行一个方法吗?



两个方法,一个用于上传,一个用于下载,在self.FfAppClient工作在一个单独的应用程序中,uploadFiledownloadFile是由视图控制器上的按钮触发的。当上传完成时,用户有一个视觉反馈,因此可以继续按下按钮来下载文件。

在下面的应用程序中,我已经测试了uploadFiledownloadFile都在那里工作,但是当我使用下面的代码段时,上传有时会失败,下载永远不会工作。

我正试图等到我知道上传完成(self.FfAppClient uploadFile给出success),然后开始下载。这是完全错误的方式来使用块,更重要的是,有[self downloadImage:[NSString stringWithFormat:@"ımage id=%d",entryID]];块内不会工作的原因吗?

- (void)uploadThenDownloadImage:(UIImage*)image usingImagePath:(NSString*)imagePath
{
    NSData *imageData = UIImageJPEGRepresentation(image, 1);
    [self.FfAppClient uploadFile:imagePath withContent:imageData success:^(id response) {
        NSInteger entryID = [[response objectForKey:@"id"] integerValue];
        [self downloadImage:[NSString stringWithFormat:@"ımage id=%d",entryID]];
   } failure:^(NSError *error) {
    NSLog(@"Upload error: %@", error.description);
   }];
}
- (void)downloadImage:(NSString*)fileID
{
    [self.FfAppClient downloadFile:fileID success:^(id response) {
        NSString* suggested = [response objectForKey:@"suggested"];
        NSString* temp = [response objectForKey:@"temp"];
        [self moveTempFileNamed:suggested toIncomingFolderFromTemporaryLocation:temp];
    } failure:^(NSError *error) {
        NSLog(@"Download error: %@", error.description);
    } progress:^(float prc) {
        NSLog(@"Download amount: %@", [NSString stringWithFormat:@"downloaded %.02f", prc]);
    }];
}

下载部分的错误是:

-[FfAppClient URLSession:task:didCompleteWithError:]: error: Error Domain=NSURLErrorDomain Code=-1000 "bad URL" UserInfo=0x1383b500 {NSUnderlyingError=0x15370380 "bad URL", NSLocalizedDescription=bad URL}

有时,上传也会失败,因为在success块中的响应给出了一个无意义的字符串,例如;8@c1jL2gZK3yWziVNuY-h1btzGG.t!u5zoRW2MV,而不是指服务器上图片的名称。

是否有另一种方法来实现这个或我的代码失败的原因?

* *

编辑:uploadFiledownloadFile方法:* *

- (void)uploadFile:(NSString *)filename withContent:(NSData*)content success:(FfSuccessBlock)successBlock failure:(FfFailBlock)failBlock
{
        if ( ![self isConnected] )
{
    NSError *error = [NSError errorWithDomain:@"Not connected" code:0 userInfo:nil];
    failBlock(error);
    return;
}
NSString *urlFormat = [NSString stringWithFormat:@"%@%@/%@", kFfPicsBasePath, kFfPutFileURL, kFfSubscriptionId];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
NSMutableURLRequest* request = [self signedRequestWithURL:[NSURL URLWithString:urlFormat] andMethod:@"POST" andParams:params];
[request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
NSString* boundary = [NSString stringWithFormat:@"Boundary+%08X%08X", arc4random(), arc4random()];
[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary] forHTTPHeaderField:@"Content-Type"];
// Body part for the attachament. This is an image.
NSMutableData *body = [NSMutableData data];
[body appendData:[[NSString stringWithFormat:@"--%@rn", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name="%@"; filename="%@"rn", @"docfile", filename] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Type: image/jpegrnrn" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:content];
[body appendData:[[NSString stringWithFormat:@"rn"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"--%@--rn", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
request.HTTPBody = body;
self.currentSuccessBlock = successBlock;
self.currentFailBlock = failBlock;
__block FfAppClient* me = self;
self->_resTask = [self->_resSession dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
    int statusCode = httpResponse.statusCode;
    if ( !error )
    {
        if ( statusCode >= 400 )
        {
            NSString* bodyError = data ? [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] : [NSString stringWithFormat:NSLocalizedString(@"HTTP Error: %d", @"FfResourceHTTPErrorDomain description"), statusCode];
            NSDictionary *errorInfo =[NSDictionary dictionaryWithObject:bodyError forKey:NSLocalizedDescriptionKey];
            error = [NSError errorWithDomain:@"Failed URL" code:statusCode userInfo:errorInfo];
        }
        else if ( ![[response MIMEType] isEqualToString:@"application/json"] || [data length] == 0 )
        {
            NSString* bodyStr = data ? [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] : @"";
            NSString* bodyError = [NSString stringWithFormat:NSLocalizedString(@"HTTP Content Type Error: %@/n%@", @"FfOResource2HTTPErrorDomain description"), [response MIMEType], bodyStr];
            NSDictionary *errorInfo =[NSDictionary dictionaryWithObject:bodyError forKey:NSLocalizedDescriptionKey];
            error = [NSError errorWithDomain:@"Failed URL" code:555 userInfo:errorInfo];
        }
    }
    id jsonResponse = nil;
    if ( !error )
    {
        jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
    }
    if ( error )
    {
        data = nil;
        if ( me.currentFailBlock ) {
            __block NSError* blockError = error;
            dispatch_sync(dispatch_get_main_queue(), ^{ me.currentFailBlock( blockError ); });
        }
    }
    else
    {
        if ( me.currentSuccessBlock )
        {
            dispatch_sync(dispatch_get_main_queue(), ^{ me.currentSuccessBlock(jsonResponse); });
        }
    }
    me->_resTask = nil;
    [me clearBlocks];
}];
[self->_resTask resume];
}
- (void)downloadFile:(NSString *)fileId success:(FfSuccessBlock)successBlock failure:(FfFailBlock)failBlock progress:(FfProgressBlock)progress;
{
if ( ![self isConnected] )
{
    NSError *error = [NSError errorWithDomain:@"Not connected" code:0 userInfo:nil];
    failBlock(error);
    return;
}
NSString *urlFormat = [NSString stringWithFormat:@"%@%@/%@", kFfPicsBasePath, kFfGetFileURL, fileId];
NSLog(@"fileid: %@", fileId);
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
NSMutableURLRequest* request = [self signedRequestWithURL:[NSURL URLWithString:urlFormat] andMethod:@"GET" andParams:params];
NSLog(@"---> Request: %@", request);
[request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
self.currentSuccessBlock = successBlock;
self.currentFailBlock = failBlock;
self.currentProgressBlock = progress;
self->_resTask = [self->_resSession downloadTaskWithRequest:request];
[self->_resTask resume];
}

听起来像是内存管理或多线程问题;从块内调用方法是可以的,但可能不是您在这里使用FfAppClient所做的。在上传_resTask完全完成之前,您启动了一个下载任务,该任务覆盖了仍然未完成的上传调用所设置的大多数ivars(这可能导致对象被释放),并且该任务在另一个线程上运行。您可能需要对FfAppClient代码进行重大重写以使其安全,但您可以尝试以下两种快速技巧:

1)尽可能使用两个不同的FfAppClient

注意下面代码中的FfAppClientAFfAppClientB:

- (void)uploadThenDownloadImage:(UIImage*)image usingImagePath:(NSString*)imagePath
{
    NSData *imageData = UIImageJPEGRepresentation(image, 1);
    [self.FfAppClientA uploadFile:imagePath withContent:imageData success:^(id response) {
        NSInteger entryID = [[response objectForKey:@"id"] integerValue];
        [self downloadImage:[NSString stringWithFormat:@"ımage id=%d",entryID]];
   } failure:^(NSError *error) {
    NSLog(@"Upload error: %@", error.description);
   }];
}
- (void)downloadImage:(NSString*)fileID
{
    [self.FfAppClientB downloadFile:fileID success:^(id response) {
        NSString* suggested = [response objectForKey:@"suggested"];
        NSString* temp = [response objectForKey:@"temp"];
        [self moveTempFileNamed:suggested toIncomingFolderFromTemporaryLocation:temp];
    } failure:^(NSError *error) {
        NSLog(@"Download error: %@", error.description);
    } progress:^(float prc) {
        NSLog(@"Download amount: %@", [NSString stringWithFormat:@"downloaded %.02f", prc]);
    }];
}


2)异步调度并允许第一个任务在开始第二个任务之前完全完成

当成功和失败块同步分配到main时,尝试以下操作:

- (void)uploadThenDownloadImage:(UIImage*)image usingImagePath:(NSString*)imagePath
{
    NSData *imageData = UIImageJPEGRepresentation(image, 1);
    [self.FfAppClientA uploadFile:imagePath withContent:imageData success:^(id response) {
        dispatch_async(dispatch_get_main_queue(), ^{ 
            NSInteger entryID = [[response objectForKey:@"id"] integerValue];
            [self downloadImage:[NSString stringWithFormat:@"ımage id=%d",entryID]];
        });    
   } failure:^(NSError *error) {
    NSLog(@"Upload error: %@", error.description);
   }];
}


不过,这些都是比较快速的技巧,而不是真正的解决方案。

最新更新