web-dev-qa-db-ja.com

写真フレームワーク。 requestImageForAssetは2つの結果を返します。画像ビューを設定できません

だから私はSwipeViewライブラリ( https://github.com/nicklockwood/SwipeView )を使用して、iOS8のPhotosフレームワークを使用して画像を表示しています。

ただし、requestImageForAssetを呼び出すと、サムネイルサイズと、必要な大きいサイズの2つの結果が得られます。ただし、大きなイメージは返される時間にロードされないため(非同期と呼ばれます)、小さなイメージが返されます。

このコードの方が意味があります。

    func swipeView(swipeView: SwipeView!, viewForItemAtIndex index: Int, reusingView view: UIView!) -> UIView! {
            let asset: PHAsset = self.photosAsset[index] as PHAsset

    var imageView: UIImageView!

    let screenSize: CGSize = UIScreen.mainScreen().bounds.size
    let targetSize = CGSizeMake(screenSize.width, screenSize.height)


    var options = PHImageRequestOptions()
//        options.deliveryMode = PHImageRequestOptionsDeliveryMode.Opportunistic
    options.resizeMode = PHImageRequestOptionsResizeMode.Exact


    PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: targetSize, contentMode: .AspectFill, options: options, resultHandler: {(result, info)in
        println("huhuhuh")
        println(result.size)
        println(info)
        imageView = UIImageView(image: result)
    })
    println("setting view)
    return imageView
}

ログ出力は次のとおりです。

Enteredhuhuhuh
(33.5,60.0)
SETTING VIEW
huhuhuh
(320.0,568.0)

ご覧のとおり、大きな画像が受信される前に画像ビューを返します。サムネイルを表示しないように、この大きな画像を返すようにするにはどうすればよいですか?

ありがとう。

21
Jonovono

PHImageManagerクラスのヘッダーを読み取ります

-[PHImageRequestOptions isSynchronous]がNO(またはオプションがnil)を返す場合、resultHandlerが1回以上呼び出されることがあります。通常、この場合、resultHandlerは、要求された結果を使用してメインスレッドで非同期的に呼び出されます。ただし、deliveryMode = PHImageRequestOptionsDeliveryModeOpportunisticの場合、画像データがすぐに利用可能であれば、呼び出し側スレッドでresultHandlerを同期的に呼び出すことができます。この最初のパスで返された画像データの品質が不十分である場合、後で「正しい」結果でメインスレッドで非同期にresultHandlerが再度呼び出されます。要求がキャンセルされると、resultHandlerがまったく呼び出されない場合があります。 -[PHImageRequestOptions isSynchronous]がYESを返す場合、resultHandlerは同期して呼び出しスレッドで1回だけ呼び出されます。同期リクエストはキャンセルできません。非同期リクエストのresultHandler。常にメインスレッドで呼び出されます

したがって、あなたがやりたいことは、resultHandlersynchronouslyと呼ばれるようにすることです。

PHImageRequestOptions *option = [PHImageRequestOptions new];
option.synchronous = YES;

[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:target contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage *result, NSDictionary *info) {
        //this block will be called synchronously
}];

したがって、メソッドを終了する前にブロックが呼び出されます

幸運を!

78
Tony

デフォルトでは、requestImageForAssetは非同期として機能します。したがって、メソッドでは、イメージが取得される前でもreturnステートメントが実行されます。だから私の提案は、imageViewを返す代わりに、imageViewに渡す必要があるという点でimageViewを渡します:

func swipeView(swipeView: SwipeView!, viewForItemAtIndex index: Int, reusingView view: UIView!, yourImageView: UIImageView)
{
    let asset: PHAsset = self.photosAsset[index] as PHAsset

    var imageView: UIImageView! = yourImageView;

    let screenSize: CGSize = UIScreen.mainScreen().bounds.size
    let targetSize = CGSizeMake(screenSize.width, screenSize.height)


    var options = PHImageRequestOptions()
    options.resizeMode = PHImageRequestOptionsResizeMode.Exact

    PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: targetSize, contentMode: .AspectFill, options: options, resultHandler: {(result, info)in
        imageView.image = result;
    })
}

注:

もう1つのオプションは、resultHandlerからの結果イメージを使用して通知を起動することです。しかし、私は上記の方法を好みます。

詳細については PHImageManager を参照してください。

4
Midhun MP

resultHandler:ブロックには、PHImageResultIsDegradedKeyキーのブール値を含む情報ディクショナリがあります。これは、結果の画像が要求された画像の低品質の代替であるかどうかを示します。

ドキュメントの内容は次のとおりです。

PHImageResultIsDegradedKey:結果画像が要求された画像の低品質の代替であるかどうかを示すブール値。 (NSNumber)

YESの場合、Photosはまだ高品質の画像を提供できなかったため、resultHandlerブロックの結果パラメーターには低品質の画像が含まれています。要求で指定したPHImageRequestOptionsオブジェクトの設定に応じて、Photosは結果ハンドラーブロックを再度呼び出して、より高品質の画像を提供する場合があります。

4
O Fenômeno

Appleこのメソッドのドキュメント here。 で彼らが言っていることで:

非同期リクエストの場合、Photosは結果ハンドラーブロックを複数回呼び出すことがあります。写真は最初にブロックを呼び出して、高品質の画像を準備している間に一時的に表示するのに適した低品質の画像を提供します。(低品質の画像データの場合がすぐに利用できる場合、メソッドが戻る前に最初の呼び出しが発生する可能性があります。)

あなたの場合、元のサイズの画像を取得するには時間がかかるかもしれません。それ以外の場合、あなたのコードは私には問題ないようです。

1
Mrunal

ImageViewをブロック内で書き換えるのではなく、画像を設定するだけで、すべてが期待どおりに動作するはずです。 2つの画像が表示されないようにするには、割り当てる前に画像のサイズを確認できます。

var imageView =  UIImageView()
...
...
        PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: targetSize, contentMode: .AspectFill, options: options, resultHandler: {(result, info)in
                println("huhuhuh")
                println(result.size)
                println(info)
                if result.size.width > 1000 &&  result.size.height > 1000 { // add any size you want 
                     imageView.setImage(result)
                }
            })
1
sage444

以下のオプションを使用、Swift 3.0

publi var imageRequestOptions: PHImageRequestOptions{
let options = PHImageRequestOptions()
options.version = .current
options.resizeMode = .exact
options.deliveryMode = .highQualityFormat
options.isNetworkAccessAllowed = true
options.isSynchronous = true
return options}
0
Hiren Panchal

これを試してみても非同期に機能します。

[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:target contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage *result, NSDictionary *info) {
    if ([info objectForKey:@"PHImageFileURLKey"]) {
      //your code
    }
}];
0
vaibby