21

我有一个 UIImagePickerController 被 sourceType 相机调用,并且 80%​​ 的时间我得到一个黑色预览。如果我等待,比如说大约 30 秒,我会得到一个很好的预览,大约 50% 的时间会很好,然后它会再次中断。

有问题的图像与此非常相似。iDevice 相机显示黑色而不是预览

其他人暗示 GCD 可能会导致相机出现一些问题,并且在加载图像选择器时更新 UI 会破坏它。为此,我在每个调用主线程的 GCD 块上都加了锁。

这是一个旋转以模拟活动指示器的图像示例。

-(void)animateLoadingImage {

if (isMainThreadBlocked) {
    return;
}

self.radians += M_PI_4 / 2;
[UIView beginAnimations:@"progress rotation" context:nil];
[UIView setAnimationDuration:.1];
self.loadingImageView.transform = CGAffineTransformMakeRotation(self.radians);
[UIView commitAnimations];


}

PS:对尚未渲染的视图进行快照会导致快照为空。确保在快照或屏幕更新后的快照之前至少渲染一次视图。

当我尝试打开选择器控制器时,这总是显示,但即​​使相机正确显示预览,它也会显示它。我不认为错误就在这里,但这也让我很烦恼。

4

7 回答 7

13

在我最近的一个项目中,我遇到了同样(或类似)的问题,即在 iOS7(iPad)上使用 UIImagePickerController 时相机预览显示黑屏。

我发现 GCD 本身不是问题。当您尝试在主线程以外的线程(作为 NSOperation 的一部分)中使用 UIKit 框架中的任何内容时,就会出现问题。

首先,让我先说,我很清楚你不应该一开始就这样做。然而,在我的具体情况下,我别无选择。由于我认为其他人很有可能遇到同样奇怪的 UIImagePickerController 相机行为,原因相同,所以我编写了一些非常简单的示例代码来解释发生了什么。

你可以在这里找到它:https ://github.com/idamediafoundry/CameraTest

ViewController 显示了 2 个简单的按钮。一个调用 UIImagePickerController,显示相机,另一个启动一些 GCD 操作做一个简单的任务。如果您只是打开相机,一切正常。如果您先开始操作然后打开相机,则会出现黑色预览问题。

同样,你不应该在除主线程之外的任何地方调用 UIKit。但是我不认为打破这个规则会导致相机在稍后在主线程中作为完全不同的流程的一部分打开时出现故障是正常的,对吧?

希望这可以帮助。

于 2013-11-15T16:06:41.377 回答
10

在网上的任何地方似乎都没有一个好的答案,所以我不得不自己费力地解决这个问题。

我正在使用 ARC(可能像现在大多数其他人一样),所以上面的答案并没有真正帮助我。

这个黑色摄像头问题是在 iOS 7 的主线程之外执行 UIKit 操作的副作用。一般来说,后台 UIKit 操作会导致 iOS 7 上发生各种奇怪的事情(内存没有被及时释放、奇怪的性能故障,以及黑色相机问题)。

为了防止这种情况,你不需要在后台线程上做任何 UIKit 的事情。

您不能在后台线程上做的事情: - 分配/初始化 UIViews 和子类 - 修改 UIViews 和子类(例如,设置框架、设置 .image/.text 属性等)。

现在,在主线程上做这些事情的问题是它可能会影响 UI 性能,这就是为什么你会看到所有这些 iOS 6“后台加载”解决方案在 iOS 7 上不能以最佳方式工作(即,导致黑色摄像头问题等)。

在防止后台 UIKit 操作的不良影响的同时,我做了两件事来修复性能: - 在后台线程上预先创建和初始化所有 UIImage。您应该在主线程上使用 UIImages 做的唯一事情是设置“imageView.image = preloadedImageObject;” - 尽可能重复使用视图。如果您在 cellForRowAtIndex 或在响应性非常重要的其他情况下执行此操作,则在主线程上执行 [[UIView alloc] init] 仍然可能存在问题。

祝你好运!您可以通过在应用运行时监控内存使用情况来测试您的表现。背景 UIKit => 快速升级的内存使用量。

于 2013-11-14T05:48:22.617 回答
5

我遇到了同样的问题,但是该应用程序永远不会显示授予访问照片权限的警报,并且它永远不会在设置->隐私->照片中显示为已请求许可。它只会在没有权限提示的情况下显示黑屏。

我终于将其追溯到 info.plist。

在此处输入图像描述

事实证明,如果您将键“捆绑显示名称”添加到 info.plist 并将值留空,则权限警报将永远不会显示。似乎权限警报会将此值拉到警报中显示,如果您将其留空,它根本不会显示警报。

如果你的 plist 中有这个没有值,它可能会导致黑色预览。

编辑:我在某些设备而不是其他设备上遇到了这个问题,我测试了我测试过的所有 3 台 iPhone 6 设备,而 iPhone 5s 不会显示警报并且会挂在黑屏上。iPhone 4s 和 iPhone 6S+ 显示警报并按预期工作。

于 2015-11-24T22:30:41.733 回答
2

首先,这个问题似乎部分是苹果和开发人员的错,可能更多是在开发人员方面。UIImagePickerController通过在本机相机应用程序和我自己的应用程序对相机模式的使用之间切换,我能够让我的应用程序生成黑色预览图像。它并不一致,但我确实让它发生了重复这些步骤大约 5-15 次,最终它会变成黑色预览。

另一方面,我可以通过重构自己的代码来解决这个问题。我不需要像其他人使用 AVFoundation 那样构建自定义相机,而是从我的代码中删除了所有潜在/有效的内存泄漏。确保您使用 Instruments 测试您的应用程序,消除任何泄漏。还要清理UIImagePickerController,这可能因是否使用 ARC 而异。在我重构之后,黑色预览的问题就消失了。我相信您的应用程序中的内存泄漏是导致视频预览在一段时间后变黑的原因。

最后但并非最不重要的一点是,我有另一个使用 zxing 扫描仪的应用程序,它使用 AVFoundation 来解码来自实时预览流的图像……这个修复起来非常棘手,它是 ARC 与非弧(zxing 非弧)混合的。我不得不重构更多代码,因为视图/UIViewController层次结构要复杂得多,并且获取包含 AVFoundation Session 的实际对象以释放是关键。经过一天的重构,这个问题就消失了,所以,是的,在我的 iOS 7 中黑色图像预览问题的两种情况下,堵住内存泄漏都是答案。

于 2013-10-10T22:43:19.870 回答
1

在我的情况下,我不得不将一些方法移动到主线程。

我的应用程序使用新上下文创建新图像,我可以在不同的线程中创建新上下文并使用 CGContext 函数(如 CGContextScaleCTM 或 CGContextTranslateCTM 或 CGContextConcatCTM)和 [uiimage drawInRect:Mybounds];。

基本上,当我在上下文中绘制图层时,我必须将 renderInContext 方法移至主线程:

CGSize sizeView = viewPrintBase.frame.size;
UIGraphicsBeginImageContext(sizeView);
currentContext = UIGraphicsGetCurrentContext();

dispatch_sync(dispatch_get_main_queue(), ^{
    [viewPrintBase.layer renderInContext:currentContext];
    [imageViewPhotoUser.layer renderInContext:currentContext];
    if (imageViewMask) {
        [imageViewMask.layer renderInContext:currentContext];
    }
});
[imageSnapShotDrawinfView drawInRect:viewPrintBase.bounds];
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

CGImageRef imageRef = CGImageCreateWithImageInRect([finalImage CGImage], viewPrintBase.bounds);
// or use the UIImage wherever you like
imageSnapShot = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);

此外,我必须将所有 UI 对象的创建移至主线程,例如:

    __block UIView *viewPrintBase;
dispatch_sync(dispatch_get_main_queue(), ^{
    viewPrintBase = [[UIView alloc]initWithFrame:CGRectMake(0, 0, WIDTH_FINAL_IMAGE, HEIGHT_FINAL_IMAGE)];
    viewPrintBase.backgroundColor = [UIColor whiteColor];
    [viewPrintBase setClipsToBounds:YES];
    //We get the photo user
});

我希望这有帮助 :)

于 2014-01-07T13:19:44.997 回答
1

首先检查您的应用程序是否有权访问相机。我认为您在相机第一次在应用程序中启动时按下了“否”选项。现在做一件事。转到“设置”->“隐私”->“相机”,然后在此处选择您的应用程序,检查其是否打开,如果关闭则打开..现在您可以在应用程序中访问相机。

于 2014-10-14T04:25:36.013 回答
0

似乎这是 iOS 7 的问题。即使我遇到了类似的情况,当我从我的应用程序中从图片库上传照片,然后尝试打开相机时出现黑屏。

于 2013-10-01T10:10:35.890 回答