图像下载不正确

时间:2013-05-22 11:52:59

标签: objective-c macos cocoa nsdata nsimage

 NSOperationQueue *queue = [NSOperationQueue new];
 NSInvocationOperation *operation;
 for(int k=0; k<[imageArray count]; k++)
 {
     operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadData:) object:[imageArray objectAtIndex:k]];
     [queue addOperation:operation];
     [operation release];
 }  

使用上面的代码我调用方法loadData来下载一些图像。

-(void)loadData:(NSString*)newImage
{
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:newImage]];
    NSString* appSuppPath = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString* foofile = [appSuppPath stringByAppendingPathComponent:@"/PSDB"];


    NSString * str =[NSString stringWithFormat:@"%@/%d.jpeg",foofile,x];
    x++;
    [imageData writeToFile:str atomically:YES];
    [CATransaction commit];
}

下载并保存图像。问题是低尺寸的图像被快速下载。例如,如果第6张图像是低尺寸图像,则首先下载并保存为1.jpeg。我该如何将其作为订单。

2 个答案:

答案 0 :(得分:0)

来自NSOperationQueue doc

操作队列根据其优先级和准备情况执行排队的操作对象。如果所有排队的操作对象具有相同的优先级并且在将它们放入队列时准备好执行 - 也就是说,它们的isReady方法返回YES-它们按照它们被提交到队列的顺序执行。对于最大并发操作数设置为1的队列,这相当于一个串行队列。但是,您永远不应该依赖于操作对象的串行执行。操作就绪的更改可能会更改生成的执行顺序。

如果setMaxConcurrentOperationCount没有帮助,请尝试在自定义-isReady

中使用NSInvocationOperation方法

答案 1 :(得分:0)

使用并发队列时,您无法保证它们完成的顺序。但是,你真的不应该在意。让他们尽可能以最有效的方式完成。

但我想,您希望文件名对应于URL的索引k。因此,我建议您在启动请求时将下载过程更改为仅使用k,并停止使用x,例如:

NSOperationQueue *queue = [NSOperationQueue new];
queue.maxConcurrentOperationCount = 5;   // limit number of concurrent requests to some reasonable number

NSString* appSuppPath = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* foofile = [appSuppPath stringByAppendingPathComponent:@"PSDB"];

for (int k = 0; k < [imageArray count]; k++)
{
    [queue addOperationWithBlock:^{
        NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:[imageArray objectAtIndex:k]]];
        if (imageData)
        {
            NSString * str = [NSString stringWithFormat:@"%@/%d.jpeg", foofile, k];
            [imageData writeToFile:str atomically:YES];
        }
    }];
}  

这消除了计数器x的异步更新,消除了文件编号问题。 (这也解决了原始代码中的线程安全问题:如果同时完成两次下载,因此使用相同的x值会怎样?)这也可以确保您的文件正确命名。

现在,如果您真的希望它们因其他原因顺序完成,您可以在串行队列中执行此操作(例如maxConcurrentOperationCount = 1),但这样做会显着降低性能。设计您的体系结构以便完成顺序并不重要。例如。如果您只是需要知道它们何时完成,请根据其他完成操作添加完成操作。

当然,上面的代码更改解决了一个战术问题,但如果还有其他原因导致您认为需要按照排队顺序完成它们,请告诉我们,因为可能存在无需解决方案的解决方案并且让您享受并发下载的性能提升。