6

我有 4 个方法,每个方法在方法返回之前需要一两秒钟,这些方法返回 UIImage,我需要这些图像以最快的方式显示。

-(NSMutableArray*)prepareImages{
  UIImage *imageToModifyUsingUIImageCategory;

  NSMutableArray *imageArray = [[NSMutableArray alloc]initWithObjects:
  [imageToModifyUsingUIImageCategory doSomethingAndReturn1],
  [imageToModifyUsingUIImageCategory doSomethingAndReturn2],
  [imageToModifyUsingUIImageCategory doSomethingAndReturn3],
  [imageToModifyUsingUIImageCategory doSomethingAndReturn4],nil];    
  return imageArray;
}

在上述方法结束时,我将从该数组中获得 4 张图像。每个“doSomethingAndReturn”方法需要一两秒,这意味着我的prepareImages方法将在大约 5 秒内完成执行。太长了吧?

我的问题是,还有什么其他方法可以更快地完成所有这些工作?GCD 对我来说是一个选择吗?如何?

任何帮助将非常感激。谢谢!

4

5 回答 5

16

假设您不介意在后台顺序加载图像(而不是并行加载),一个简单的调度到后台队列运行prepareImages就可以了:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    NSArray *images = [self prepareImages];

    // now send the result back to the main thread so we can do
    // UIKit stuff
    dispatch_async(dispatch_get_main_queue(), ^{
        // set the images on your UIImageViews here...
    });
});

这会将图像加载到低优先级的后台队列中,然后在完成后分派回主线程。

如果你想保持这个更低的优先级,你可以使用DISPATCH_QUEUE_PRIORITY_BACKGROUND,尽管这仅在 iOS 4.3 和更高版本中可用。在这种情况下,您应该检查返回值dispatch_get_global_queue,如果它返回 0,您可以回退到其他优先级之一。

如果您想并行加载每个图像,您可能应该将您的doSomethingAndReturn方法转换为NSOperation子类并使用 anNSOperationQueue来运行它们。这将需要更多的努力来实施。如果一次处理多个大图像,还要注意内存使用情况。

于 2012-06-01T09:48:28.957 回答
1

我有一个想法如何解决,但尚未测试。我正在从我遇到并解决的其他几个问题中得出解决方案:

  • 插入NSNullNSMutableArray作为占位符。
  • dispatch_async繁重的工作并替换相应的条目NSMutableArray(使用@synchronized关键字锁定NSMutableArray
  • 同样在dispatch async函数中,将函数分派回主队列以更新视图。
于 2012-06-01T09:40:07.773 回答
1

你可以使用NSOperationQueue

NSOperationQueue 类管理一组 NSOperation 对象的执行。被添加到队列后,操作将保留在该队列中,直到它被显式取消或完成其任务的执行。队列中的操作(但尚未执行)本身根据优先级和互操作对象依赖性进行组织,并相应地执行。一个应用程序可以创建多个操作队列并向其中的任何一个提交操作。

NSOperationQueue 实现的示例

GCD 队列

Grand Central Dispatch (GCD) 调度队列是执行任务的强大工具。调度队列允许您相对于调用者异步或同步地执行任意代码块。您可以使用调度队列来执行您过去在单独线程上执行的几乎所有任务。调度队列的优点是它们比相应的线程代码更易于使用并且在执行这些任务时效率更高。

GCD 队列实现的示例

于 2012-06-01T09:46:07.523 回答
1

您可以在处理器的另一个内核上同时执行该操作:

NSThread detachNewThreadSelector:@selector(YOUR_METHODS_HERE:) toTarget:self withObject:nil];
NSThread detachNewThreadSelector:@selector(YOUR_METHODS_HERE:) toTarget:self withObject:nil];
NSThread detachNewThreadSelector:@selector(YOUR_METHODS_HERE:) toTarget:self withObject:nil];
NSThread detachNewThreadSelector:@selector(YOUR_METHODS_HERE:) toTarget:self withObject:nil];

如果您的处理器有四个内核,则每种方法都将在不同的内核上执行。

于 2012-06-01T09:57:24.030 回答
0

我只是将其作为练习:对每个 doSomethingAndReturn 使用 GCD 并发 Q 并使用串行 q 来监视回调的数量。当回调的数量等于 doSomethingAndReturn(s) 的数量时,则返回 prepareImages 数组。

我创建了代码来测试这个概念。

-(NSString *)doSomethingAndReturn1
{
    for (int i=0; i<30; i++) 
    {
        NSLog(@"soSomethingAndReturn1 i: %i", i);
    }
    return @"soSomethingAndReturn1";
}

-(NSString *)doSomethingAndReturn2
{
    for (int i=0; i<10; i++) 
    {
        NSLog(@"soSomethingAndReturn2 i: %i", i);
    }
    return @"soSomethingAndReturn2";
}

-(NSString *)doSomethingAndReturn3
{
    for (int i=0; i<20; i++) 
    {
        NSLog(@"soSomethingAndReturn3 i: %i", i);
    }
    return @"soSomethingAndReturn3";
}

-(void)addToArray:(NSString *)str
{
    [asyncArray addObject:str];
    NSLog(@"asyncArray: %@", asyncArray);
}

- (IBAction)buttonMultitasksPressed:(id)sender 
{
    dispatch_queue_t serialdQueue;
    serialdQueue = dispatch_queue_create("com.mydomain.testbed.multimethods", NULL);
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self addToArray:[self doSomethingAndReturn1]];
        });
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self addToArray:[self doSomethingAndReturn2]];
        });
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self addToArray:[self doSomethingAndReturn3]];
        });
        dispatch_sync(serialdQueue, ^{
            while (!([asyncArray count] == 3)) 
            {
                NSLog(@"not there yet count: %i", [asyncArray count]);
            }
        });

    NSLog(@"end of dispatch_sync serialQueue");
//    return asyncArray;
}

编辑:第二个想法:连续剧是没有必要的。

于 2012-06-01T14:22:02.633 回答