web-dev-qa-db-ja.com

iOS 7UIImagePickerControllerのプレビューは黒です

SourceTypeカメラでUIImagePickerControllerが呼び出されており、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:レンダリングされていないビューのスナップショットを作成すると、スナップショットが空になります。スナップショットの前または画面の更新後のスナップショットで、ビューが少なくとも1回レンダリングされていることを確認してください。

これは、ピッカーコントローラーを開こうとすると常に表示されますが、カメラがプレビューを正しく表示していても表示されます。エラーはこのあたりにあるとは思いませんが、これも私を悩ませます。

21
Heavy_Bullets

オンラインのどこにもこれに対する良い答えはないように思われるので、私はそれを理解するためにこれを自分で調べなければなりませんでした。

私はARCを使用しているので(おそらく最近の他のほとんどのように)、上記の答えは本当に役に立ちませんでした。

この黒いカメラの問題は、iOS 7のメインスレッドからUIKitを実行することの副作用として発生します。概して、バックグラウンドのUIKit操作により、iOS 7であらゆる種類の奇妙なことが起こります(メモリの割り当てがすぐに解除されない、奇妙なパフォーマンスの問題、黒いカメラの問題)。

これを防ぐには、バックグラウンドスレッドでUIKitを実行する必要はありません。

バックグラウンドスレッドでは実行できないこと:-UIViewとサブクラスの割り当て/初期化-UIViewとサブクラスの変更(フレームの設定、.image/.text属性の設定など)。

さて、メインスレッドでこのようなことを行う際の問題は、UIのパフォーマンスが混乱する可能性があることです。そのため、iOS7では最適に機能しない(つまり、黒いカメラが発生する)iOS6の「バックグラウンド読み込み」ソリューションがすべて表示されますとりわけ、問題)。

バックグラウンドUIKit操作の悪影響を防ぎながらパフォーマンスを修正するために私がしたことは2つあります。-バックグラウンドスレッドですべてのUIImageを事前に作成して初期化します。メインスレッドでUIImagesを使用して行う必要があるのは、「imageView.image = preloadedImageObject;」を設定することだけです。 -可能な限りビューを再利用します。メインスレッドで[[UIViewalloc] init]を実行することは、cellForRowAtIndexで実行する場合、または応答性が非常に重要である別の状況で実行する場合、依然として問題になる可能性があります。

頑張ってください!アプリの実行中にメモリ使用量を監視することで、現在の状況をテストできます。背景UIKit =>メモリ使用量が急速に増加しています。

10
Dinkman123

最近のプロジェクトの1つで、これと同じ(または同様の)問題が発生しました。つまり、iOS7(iPad)でUIImagePickerControllerを使用すると、カメラのプレビューに黒い画面が表示されます。

私が発見したのは、GCD自体は問題ではないということです。この問題は、メインスレッド以外のスレッド(NSOperationの一部として)でUIKitフレームワークから何かを使用しようとすると発生します。

まず最初に、これを最初から行うべきではないことは明らかです。しかし、私の特定のケースでは、選択の余地はありませんでした。他の人が同じ原因で同じ奇妙なUIImagePickerControllerカメラの動作を経験している可能性が高いと思うので、何が起こっているのかを説明する非常に簡単なサンプルコードを作成しました。

ここで見つけることができます: https://github.com/idamediafoundry/CameraTest

ViewControllerには2つのシンプルなボタンが表示されます。 1つはUIImagePickerControllerを呼び出してカメラを表示し、もう1つは簡単なタスクを実行していくつかのGCD操作を開始します。カメラを開くだけで、すべてが正常に機能します。最初に操作を開始してからカメラを開くと、黒いプレビューの問題が発生します。

繰り返しますが、メインスレッド以外ではUIKitを呼び出さないでください。しかし、このルールに違反すると、後でメインスレッドでまったく異なるフローの一部としてカメラを開くときに、カメラが誤動作するのは正常ではないと思います。

お役に立てれば。

13
Bart

これと同じ問題が発生しましたが、アプリは写真へのアクセスを許可するアラートを表示せず、[設定]-> [プライバシー]-> [写真]に許可を求めたとして表示されませんでした。許可なしに黒い画面を表示するだけです。

私はついにこれをinfo.plistまでたどりました。

enter image description here

「バンドル表示名」キーをinfo.plistに追加し、値を空白のままにすると、許可アラートは表示されません。権限アラートはこの値をプルしてアラートに表示するようです。空白のままにすると、アラートは表示されません。

値なしでこれをplistに含めると、黒いプレビューが発生する可能性があります。

編集:私はいくつかのデバイスでこの問題を経験しましたが、他のデバイスでは発生しませんでした。テストしたiPhone 6デバイスの3つすべてをテストすると、iPhone 5sはアラートを表示せず、黒い画面でハングしました。 iPhone4sとiPhone6S +はアラートを表示し、期待どおりに機能しました。

5
digitalHound

第一に、この問題は部分的にAppleのせいであり、開発者のせいで、おそらく開発者側のほうが多いようです。ネイティブカメラアプリと自分のアプリでのUIImagePickerControllerカメラモードの使用を切り替えることで、アプリで黒いプレビュー画像を生成することができました。一貫性はありませんでしたが、これらの手順を約5〜15回繰り返し実行すると、最終的には黒のプレビューになります。

一方、私は自分のコードをリファクタリングすることでこの問題に対処することができました。他の人がAVFoundationで行ったように、カスタムカメラを構築する必要はありませんでした。むしろ、コードからすべての潜在的/有効なメモリリークを削除しました。必ずInstrumentsでアプリをテストし、リークを取り除きます。 UIImagePickerControllerもクリーンアップします。これは、ARCを使用するかどうかによって異なる場合があります。私のリファクタリングの後、黒のプレビューの問題はなくなりました。アプリのメモリリークが原因で、しばらくするとビデオプレビューが黒くなると思います。

最後になりましたが、ライブプレビューストリームから画像をデコードするためにAVFoundationを使用するzxingスキャナーを使用する別のアプリがありました...これは修正が非常に難しく、ARCとnon-arc(zxing non-arc)が混在していました。ビュー/ UIViewController階層がはるかに複雑で、AVFoundationセッションを含む実際のオブジェクトをdeallocに取得することが重要だったため、さらに多くのコードをリファクタリングする必要がありました。リファクタリングの1日後、この問題は解消されたので、はい、メモリリークをプラグインすることが、iOS7での黒い画像プレビューの問題の両方の私の場合の答えでした。

2
simplatek

私の場合、いくつかのメソッドをメインスレッドに移動する必要がありました。

私のアプリは新しいコンテキストで新しい画像を作成します。別のスレッドで新しいコンテキストを作成し、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
});

これがお役に立てば幸いです:)

1
xarly

まず、アプリにカメラへのアクセス許可があるかどうかを確認します。アプリでカメラを初めて起動したときに「いいえ」オプションを押したと思います。次に、1つのことを行います。 [設定]-> [プライバシー]-> [カメラ]に移動し、そこでアプリを選択して、オンがオフになっているかどうかを確認します。これで、アプリでカメラにアクセスできます。

1
user3540000

これはiOS7の問題のようです。アプリ内から画像ギャラリーから写真をアップロードしてからカメラを開こうとすると、黒い画面が表示されるという同様の状況に直面しました。