self.FfAppClient中的两种方法(一种用于上载和一种用于下载)在单独的App中工作,其中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块中给出了无意义的字符串,例如;[email protected]!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:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", @"docfile", filename] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Type: image/jpeg\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:content];
[body appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

[body appendData:[[NSString stringWithFormat:@"--%@--\r\n", 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);
   }];

}



但是,相比真正的解决方案,这是相当快速的hack。

10-08 18:42