iOS 7 UIImagePickerController具有黑色预览

时间:2013-09-29 18:29:26

标签: iphone uiimagepickercontroller ios7

我有一个使用sourceType相机调用的UIImagePickerController,有80%的时间我得到黑色预览。如果我等一下,让我们说大约30秒,我会得到一个很好的预览,它会在大约50%的时间内有效,然后它会再次破裂。

有问题的图像与此非常相似。 iDevice camera shows black instead of preview

其他人暗示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:快照未呈现的视图会导致空快照。确保在屏幕更新后快照或快照之前,您的视图至少呈现过一次。

这会在我尝试打开拾取器控制器时显示ALWAYS,但即使相机正确显示预览,它也会显示。我不认为错误在这里,但这也让我很烦恼。

7 个答案:

答案 0 :(得分:13)

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

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

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

您可以在此处找到它:https://github.com/idamediafoundry/CameraTest

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

同样,你不应该在主线程之外的任何东西中调用UIKit。但我不认为违反这条规则导致相机在主线程中稍后打开时会导致相机故障是不正常的,这是完全不同的流程的一部分,对吗?

希望这有帮助。

答案 1 :(得分:10)

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

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

这个黑色相机问题发生在iOS 7主线程上执行UIKit的副作用。一般来说,后台UIKit操作导致iOS 7上发生各种奇怪的事情(内存没有及时解除分配,奇怪的性能故障和黑色相机问题。)

为防止这种情况,您不需要在后台线程上执行任何UIKit操作。

在后台主题上你无法做的事情: - 分配/初始化UIViews和子类 - 修改UIViews和子类(例如,设置框架,设置.image / .text属性等)。

现在,在主线程上执行此操作的问题在于它可能会破坏UI性能,这就是为什么您会看到所有这些iOS 6“后台加载”解决方案在iOS 7上无法最佳运行(即导致黑色相机问题,除其他外)。

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

祝你好运!您可以通过在应用程序运行时监视内存使用情况来测试您的工作方式。背景UIKit =>迅速升级的内存使用量。

答案 2 :(得分:5)

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

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

enter image description here

事实证明,如果您将关键字“Bundle display name”添加到info.plist并将值保留为空白,则永远不会显示权限警报。似乎权限警报会将此值拉出以显示在警报中,如果将其留空,则根本不会显示警报。

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

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

答案 3 :(得分:2)

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

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

最后但并非最不重要的是,我有另一个使用zxing扫描仪的应用程序,它使用AVFoundation解码来自实时预览流的图像...这个非常难以修复,它是ARC混合非弧(zxing non弧)。我不得不重构更多代码,因为视图/ UIViewController层次结构要复杂得多,并且将包含AVFoundation会话的实际对象解析为dealloc是关键。经过一天的重构后,这个问题消失了,所以是的,插入内存泄漏是iOS 7中黑色图像预览问题的答案。

答案 4 :(得分: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
});

我希望这会有所帮助:)

答案 5 :(得分:1)

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

答案 6 :(得分:0)

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