【问题标题】:iOS 8 Snapshotting a view that has not been rendered results in an empty snapshotiOS 8 对尚未渲染的视图进行快照会导致快照为空
【发布时间】:2014-09-17 07:31:48
【问题描述】:

在 iOS 8 中,我在从相机捕捉图像时遇到问题,直到现在我将此代码用于

UIImagePickerController *controller=[[UIImagePickerController alloc] init];
controller.videoQuality=UIImagePickerControllerQualityTypeMedium;
controller.delegate=(id)self;
controller.sourceType=UIImagePickerControllerSourceTypeCamera;
[self presentViewController:controller animated:YES completion:nil];

但在 iOS 8 中我得到了这个:

Snapshotting a view that has not been rendered results in an empty snapshot. Ensure your view has been rendered at least once before snapshotting or snapshot after screen updates.

我已经尝试了This Post 提供的解决方案

@property (strong,nonatomic)UIImagePickerController *controller;

_controller=[[UIImagePickerController alloc] init];
_controller.videoQuality=UIImagePickerControllerQualityTypeMedium;
_controller.delegate=(id)self;
_controller.sourceType=UIImagePickerControllerSourceTypeCamera;
_[self presentViewController:controller animated:YES completion:nil];

还有这个

...
controller.modalPresentationStyle=UIModalPresentationFullScreen;
or
controller.modalPresentationStyle=UIModalPresentationCurrentContext;
...

还有这个

double delayInSeconds = 0.1;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    [self presentViewController:controller animated:YES completion:nil];
});

还有这个

[self presentViewController:controller animated:YES completion:NULL];

还有这个

[self presentViewController:controller animated:YES completion:^{

}];

有什么想法吗?

【问题讨论】:

  • 有同样的问题,而且这个错误会导致我的应用程序多次崩溃。希望更新 8.0.2 将修复此错误。当我在 iOS7 中运行我的应用程序时,它就像魅力一样工作,没有任何愚蠢的警告。看起来 iOS 8 的稳定性还有很长的路要走。
  • 事件与 8.0.2 更新此问题仍然存在
  • 我遇到了同样的问题。拍完照片后,我正在另一个线程中进行一些处理。将代码移至主线程后,一切正常。即,我之前的代码是:dispatch_async(dispatch_get_main_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{,我改成dispatch_async(dispatch_get_main_queue(), ^{
  • iOS 8.1 出现同样的问题
  • 在 iOS 9 中也会发生。

标签: objective-c ios8 uiimagepickercontroller


【解决方案1】:

我很确定这只是 iOS 8.0 中的一个错误。它可以通过最简单的 POC 应用程序重现,这些应用程序只不过是尝试呈现UIImagePickerController,就像您在上面所做的那样。此外,据我所知,没有其他模式可以显示图像选择器/相机。您甚至可以下载 Apple 的 Using UIImagePickerController sample app,运行它,它会立即生成相同的错误。

也就是说,该功能仍然适用于我。除了警告/错误之外,您的应用的功能是否存在问题?

【讨论】:

  • 是的,这可能是一个错误,代码对我来说也可以正常工作。
  • @souvickcse 我也遇到了这个错误。每当发生这种情况时,拍摄新照片后弹出的图像预览都是全黑的。但是,屏幕底部的“重拍”和“使用照片”按钮仍会出现并且功能正常。您是否目睹了同样的行为?
  • @souvickcse 我正在使用位于此处的最新 phonegap 相机插件基线:github.com/apache/cordova-plugin-camera。在 iPhone 5 上运行 iOS 7.1 时一切正常,但我找不到在 iPhone 6 上使用 iOS 8 使其正常工作的方法。
  • iOS8.1 final 对我来说也是如此
  • IOS 9 中仍然存在
【解决方案2】:

我为这个问题苦苦挣扎了几个小时,我阅读了所有相关主题,发现错误是因为在我设备的隐私设置下,相机访问我的应用程序被阻止了!!!我从来没有拒绝访问相机,我不知道它是如何被阻止的,但这就是问题所在!

【讨论】:

  • 我不确定它是否真的对你有用,但它对我没有用。我只是希望@KevinH 是正确的。
  • 不,在我的情况下,该应用程序的相机访问已被选中。但我确实相信这可能是由设置间接引起的:对设置的更改有时不会立即生效,cupertino 的某个人必须优化调用以在某处同步
  • 这个建议为我解决了这个问题。当相机选择器出现在我的应用程序中时,我之前曾触摸过“不允许”。我以为每次我访问相机时它都会问我,但它没有。我必须转到设置>隐私>相机并打开我的应用程序的滑块。然后它工作正常。 Apple 每次都不问似乎有点愚蠢......
  • 没错,有时我们不能认为此类错误会引发问题。谢谢朋友非常有帮助
  • 最好的选择是在使用相机之前检测该功能是否处于活动状态,如果没有,请提醒用户在设置中激活相机之前无法拍照。在 iOS 10 上,可以将用户发送到特定的应用程序设置(如果我没记错的话,在 iOS 8 之前可以,但在 iOS 8 和 9 中是不可能的)。
【解决方案3】:

我没有足够的声望点来评论上面@greg 的回答,所以将在这里添加我的观察。我有一个适用于 iPad 和 iPhone 的 Swift 项目。我的主视图控制器中有一个方法(下面的相关位)。当我在手机上对此进行测试时,一切正常,并且不会产生任何警告。当我在 iPad 上运行它时,一切正常,但我看到有关快照视图的警告。然而,有趣的是,当我在 iPad 上运行而不使用 popover 控制器时,一切正常,没有任何警告。不幸的是,如果不使用相机,Apple 要求必须在 iPad 上的弹出框内使用图像选择器。

    dispatch_async(dispatch_get_main_queue(), {
        let imagePicker: UIImagePickerController = UIImagePickerController();
        imagePicker.sourceType = UIImagePickerControllerSourceType.SavedPhotosAlbum;
        imagePicker.mediaTypes = [kUTTypeImage];
        imagePicker.allowsEditing = false;
        imagePicker.delegate = self;

        if(UIDevice.currentDevice().userInterfaceIdiom == .Pad){ // on a tablet, the image picker is supposed to be in a popover
            let popRect: CGRect = buttonRect;
            let popover: UIPopoverController = UIPopoverController(contentViewController: imagePicker);
            popover.presentPopoverFromRect(popRect, inView: self.view, permittedArrowDirections: UIPopoverArrowDirection.Up, animated: true);
        }else{
            self.presentViewController(imagePicker, animated: true, completion: nil);
        }
    });

【讨论】:

  • 看起来这是一个正确的建议,因为即使使用 iOS 9.0.2 我也会收到该错误消息。我只有 iPhone 的应用程序,当我在我的 iPad Mini 上运行它时,我会在展示图像选择器时看到该消息。出于某种原因,iOS 认为我运行的是 iPad 应用程序。
【解决方案4】:

我在调用 UIImagePickerController presentViewController: 从回调到 UIAlertView 委托后遇到了这个问题。我通过推送 presentViewController 解决了这个问题:使用 dispatch_async 取消当前执行跟踪。

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    dispatch_async(dispatch_get_main_queue(), ^{
        UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
        imagePickerController.delegate = self;

        if (buttonIndex == 1)
            imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
        else
            imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;

        [self presentViewController: imagePickerController
                           animated: YES
                         completion: nil];
    });
}

【讨论】:

  • 这就是为我解决的问题。我试图从 UIAlertAction 的操作块中呈现 UIImagePickerController。
  • alertView 已被弃用,如果我在 UIAlertViewController 操作中使用异步,这会起作用吗?
  • @DrPatience 当然。 dispatch_async 可以在任何你想要的地方工作。我不知道这是必要的(取决于你的代码)。阅读 GCD - 它有很多用途。
【解决方案5】:

我在为某些视图设置动画时遇到了这个问题,应用程序会进入后台模式并返回。我通过设置标志 isActive 来处理它。我把它设置为NO in

- (void)applicationWillResignActive:(UIApplication *)application

是的

- (void)applicationDidBecomeActive:(UIApplication *)application

并相应地动画或不动画我的观点。解决了这个问题。

【讨论】:

    【解决方案6】:

    我有一个 UIAlertControllerStyleActionSheet 让用户可以选择用相机拍照或使用图书馆中的一张。

    我在错误信息上尝试了一个符号断点

    这表明错误是由实习生在演示期间使用 UICollectionView 产生的

    [self presentViewController:alert animated:YES completion:nil];
    

    我通过在呈现之前明确设置框架来解决此问题

    [alert setPreferredContentSize: alert.view.frame.size];
    

    这是没有错误的完整方法

    -(void)showImageSourceAlertFromSender:(id)sender{
    UIButton *senderButton = (UIButton*)sender;
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
    UIAlertAction *cameraAction = [UIAlertAction actionWithTitle:@"Camera" style:UIAlertActionStyleDefault
                                                         handler:^(UIAlertAction *action) {
                                                             [self takePhoto];
                                                         }];
    UIAlertAction *libraryAction = [UIAlertAction actionWithTitle:@"Library" style:UIAlertActionStyleDefault
                                                          handler:^(UIAlertAction *action) {
                                                              [self selectPhotoFromLibraryFromSender:sender];
                                                          }];
    [alert addAction:cameraAction];
    [alert addAction:libraryAction];
    alert.popoverPresentationController.delegate = self;
    alert.popoverPresentationController.sourceRect = senderButton.frame;
    alert.popoverPresentationController.sourceView = self.view;
    
    [alert setPreferredContentSize: alert.view.frame.size];
    
    [self presentViewController:alert animated:YES completion:^(){
    }];}
    

    【讨论】:

      【解决方案7】:

      您可以在显示视图控制器之前通过引用view 属性来消除“快照视图”警告。这样做会导致视图加载并允许 iOS 在拍摄快照之前对其进行渲染。

      UIAlertController *controller = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
      controller.modalPresentationStyle = UIModalPresentationPopover;
      controller.popoverPresentationController.barButtonItem = (UIBarButtonItem *)sender;
      
      ... setup the UIAlertController ... 
      
      [controller view]; // <--- Add to silence the warning.
      
      [self presentViewController:controller animated:YES completion:nil];
      

      【讨论】:

      • 这是一个非常有用的提示。谢谢!!!! (就我而言,我仍然收到警告,但应用程序不再崩溃。)
      • 但是,当我添加cameraOverlayView 时,不幸的是,即使我应用了这个技巧,我仍然会遇到这个问题。
      【解决方案8】:

      对于在图像捕获后看到黑色预览问题的任何人,在显示 UIPickerController 后隐藏状态栏似乎可以解决问题。

      UIImagePickerControllerSourceType source = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] ? UIImagePickerControllerSourceTypeCamera : UIImagePickerControllerSourceTypeSavedPhotosAlbum;
      UIImagePickerController *cameraController = [[UIImagePickerController alloc] init];
              cameraController.delegate = self;
              cameraController.sourceType = source;
              cameraController.allowsEditing = YES;
              [self presentViewController:cameraController animated:YES completion:^{
                  //iOS 8 bug.  the status bar will sometimes not be hidden after the camera is displayed, which causes the preview after an image is captured to be black
                  if (source == UIImagePickerControllerSourceTypeCamera) {
                      [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
                  }
              }];
      

      【讨论】:

      • 完全节省了我的一天!我已经尝试了上面的方法,没有一个有效。这个有效
      • 解决方案不起作用。我想当我们抓到一张图片的时候,StatusBar 已经隐藏了。
      【解决方案9】:

      我发现了同样的问题并尝试了所有方法。我有两个不同的应用程序,一个在 Objective-C 中,一个在 swift 中 - 两者都有同样的问题。错误消息出现在调试器中,并且在第一张照片后屏幕变黑。这只发生在 iOS >= 8.0 中,显然这是一个错误。

      我找到了一个困难的解决方法。使用 imagePicker.showsCameraControls = false 关闭相机控件并创建您自己的具有缺失按钮的 overlayView。关于如何执行此操作有各种教程。 奇怪的错误消息仍然存在,但至少屏幕没有变黑并且您的应用程序可以正常工作。

      【讨论】:

      • 我遇到了和你完全相同的问题,请参阅下面的答案。
      【解决方案10】:

      这可能是内置 ImagePickerController 的错误。我的代码可以运行,但偶尔会在 iPhone 6 Plus 上崩溃。

      我已经尝试了其他答案建议的所有解决方案,但没有运气。切换到JPSImagePickerController后问题终于解决了。

      【讨论】:

        【解决方案11】:

        我已经尝试了一切,我的问题是相机和照片库的图像选择器在它们显示后立即消失了。我用以下行(swift)解决了它

        imagePicker.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
        

        【讨论】:

          【解决方案12】:

          我很确定这只是 iOS 8.0 中的一个错误。它可以通过最简单的 POC 应用程序重现,这些应用程序只不过是尝试呈现一个 UIImagePickerController ,就像你在上面所做的那样。此外,据我所知,没有其他模式可以显示图像选择器/相机。您甚至可以下载 Apple 的 Using UIImagePickerController 示例应用程序,运行它,它会立即生成相同的错误。

          也就是说,该功能仍然适用于我。除了警告/错误之外,您的应用的功能是否存在问题?

          【讨论】:

            【解决方案13】:

            如果我们使用UIImagePickerController 作为属性,那么这个警告就会消失。 假设我们没有使用来自 UIImagePickerController 的结果,如果我们在函数中实例化 UIImagePickerController

            【讨论】:

              【解决方案14】:

              调用此方法对我有用。在呈现您的视图后放置它。

              [yourViewBeingPresented.view layoutIfNeeded];
              

              【讨论】:

                【解决方案15】:

                我也遇到了同样的问题,我通过检查相机是否可用来解决它:

                BOOL cameraAvailableFlag = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera];
                    if (cameraAvailableFlag)
                        [self performSelector:@selector(showcamera) withObject:nil afterDelay:0.3];
                

                【讨论】:

                • isSourceTypeAvailable 返回 true,即使我拒绝访问我的应用程序的相机。如果相机访问被拒绝,则显示为空白。
                【解决方案16】:

                我遇到了这个问题。当我们调用相机并释放视图时产生了这个问题。例如,调用相机并在 viewDidDisappear 方法中设置视图 nil 会出现此错误,因为相机事件没有回调。对于这个错误,也要确保这种情况。

                【讨论】:

                  【解决方案17】:

                  我遇到了同样的错误,打开相机时在控制台中收到以下消息。

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

                  对我来说,问题是 Info.plist 文件中的 Bundle 显示名称。它是空的,我把我的应用程序名称放在那里,现在它工作正常。由于 Bundle 显示为空,我没有收到任何相机权限警报name.it 阻止了视图的渲染。

                  问题不在于视图,而是在未经许可的情况下展示它。您可以在设置-->隐私-->相机上进行检查,如果您的应用未列出,则问题可能相同。

                  【讨论】:

                    【解决方案18】:

                    我正在使用 Phonegap,但在谷歌搜索错误消息时,此线程一直是第一个线程。

                    对我来说,通过将图像类型定义为 PNG,这个问题就解决了。

                    encodingType : Camera.EncodingType.PNG
                    

                    所以整行是:

                     navigator.camera.getPicture(successFunction, failFunction, { encodingType : Camera.EncodingType.PNG, correctOrientation:true, sourceType : Camera.PictureSourceType    .PHOTOLIBRARY, quality: 70, allowEdit : false , destinationType: Camera.DestinationType.DATA_URL});
                    

                    您的里程可能会有所不同,但这对我有用。

                    【讨论】:

                      【解决方案19】:

                      或者,考虑使用drawViewHierarchyInRect

                      斯威夫特:

                      extension UIImage{
                      
                          class func renderUIViewToImage(viewToBeRendered: UIView) -> UIImage
                          {
                              UIGraphicsBeginImageContextWithOptions(viewToBeRendered.bounds.size, true, 0.0)
                              viewToBeRendered.drawViewHierarchyInRect(viewToBeRendered.bounds, afterScreenUpdates: true)
                              viewToBeRendered.layer.renderInContext(UIGraphicsGetCurrentContext()!)
                      
                              let finalImage = UIGraphicsGetImageFromCurrentImageContext()
                              UIGraphicsEndImageContext()
                      
                              return finalImage
                          }
                      }
                      

                      目标-C:

                      - (UIImage *)snapshot:(UIView *)view
                      {
                          UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES, 0);
                          [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];
                          UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
                          UIGraphicsEndImageContext();
                      
                          return image;
                      }
                      

                      另见:

                      【讨论】:

                        【解决方案20】:

                        在我的情况下(XCode 7 和 iOS 9),我使用 UINavigationController“隐藏”,所以我必须添加 UINavigationControllerDelegate 来展示相机或胶卷,它可以正常工作! And pickerControllerDelegate.self 也不显示错误!

                        【讨论】:

                          猜你喜欢
                          • 2017-02-23
                          • 1970-01-01
                          • 1970-01-01
                          • 2016-12-08
                          • 2013-09-24
                          • 1970-01-01
                          • 2020-06-26
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多