【问题标题】:Write image data in dispatch_async在 dispatch_async 中写入图像数据
【发布时间】:2012-04-23 18:06:00
【问题描述】:

当我尝试使用 GCD 将 UIImage 保存为 PNG 文件时遇到问题。 这就是我要写的:


        NSString *fileName = [[NSString stringWithFormat:@"%@.png",url] substringFromIndex:5];
        dispatch_queue_t queue = dispatch_queue_create("screenshotQueue", NULL);
        dispatch_async(queue, ^{
            NSFileManager *fileManager = [NSFileManager defaultManager];
            NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
            NSString *filePath = [documentsDirectory stringByAppendingPathComponent:fileName];
            [fileManager createFileAtPath:filePath contents:UIImagePNGRepresentation(image) attributes:nil];
        });
        dispatch_release(queue);

这是第一次工作,但其他时候我没有创建任何内容。这个 %@.png 很奇怪,因为我创建的唯一文件无法被 Finder 识别。我必须在文件中添加 .png 扩展名(所以 filename.png.png)然后我可以打开它。

【问题讨论】:

    标签: ios uiimage grand-central-dispatch nsfilemanager


    【解决方案1】:

    它看起来像一个竞争条件。您在将块分派给队列后立即释放队列。在调用 dispatch_release 之前尚未执行的任何块都将被取消,并且在调用 dispatch_release 之前 GCD 可能尚未完成自身准备。

    由于您只向 screenshotQueue 提交单个块,因此最好使用全局系统队列之一。这样,您就不必管理队列的生命周期。

    这可能会给你更一致的结果:

    NSString *fileName = [[NSString stringWithFormat:@"%@.png",url] substringFromIndex:5];
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    dispatch_async(queue, ^{
        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
        NSString *filePath = [documentsDirectory stringByAppendingPathComponent:fileName];
        [fileManager createFileAtPath:filePath contents:UIImagePNGRepresentation(image) attributes:nil];
    });
    

    我不确定 PNG 文件类型问题。听起来 Finder 不知道文件的类型。您可以使用此命令查找 Spotlight 在其索引中的类型:

    $ mdls -name kMDItemContentType <filename>.png
    

    它应该报告如下内容:

    kMDItemContentType = "public.png" 
    

    我通常使用[NSData writeToFile:atomically:] 将字节保存到磁盘,它通常会正确处理细节。这可能有点矫枉过正,但您也可以使用 Image I/O 来加倍确定:

    //The following 4 lines should preplace this line in your block:
    //[fileManager createFileAtPath:filePath contents:UIImagePNGRepresentation(image) attributes:nil];
    CGImageDestinationRef imageDest = CGImageDestinationCreateWithURL((__bridge CFURLRef)[NSURL fileURLWithPath:filePath], kUTTypePNG, 1, NULL);
    CGImageDestinationAddImage(imageDest, [image CGImage], NULL);
    CGImageDestinationFinalize(imageDest);
    CFRelease(imageDest);
    

    我现在使用 Image I/O 完成所有图像加载/保存/缩略图。它真的很快。当然,如果您决定使用它,请确保将 ImageIO.framework 添加到您的项目中。

    【讨论】:

    • 使用dispatch_async() 分派到队列的任何块都保留对该队列的引用。在刚刚分配的队列上调用 dispatch_release() 不会取消剩余的块,因为每个块仍然保留一个引用。所有块都将执行。 dispatch_sync() 不保留队列,但这不是问题,除非您已经释放它。
    猜你喜欢
    • 1970-01-01
    • 2013-12-13
    • 1970-01-01
    • 1970-01-01
    • 2015-02-28
    • 2019-10-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多