読者です 読者をやめる 読者になる 読者になる

Think Big Act Local

iPhone開発を軸にブレブレの記事を書いていきます。

Photos frameworkを使ってiPhoneアルバム内の写真を取得・削除する+α

iOS iPhone Swift アプリ Photo

先日、ALPACAという写真整理アプリを同僚とリリースしました。

iOS 8から追加されたPhotos framworkを使った、アルバムを爆速で整理できるアプリです。その道程で色々と勉強になったので、メモがてらエントリを書いてみます。

Photos frameworkとは

Photos framework はiOS 8から新たに追加されたフレームワークです。
Assets Library を置き換えるもので、Aseets Library でできる写真の取得はもちろん、検索や削除などが新たにできるようになりました。

Photos frameworkを使ってみる

それでは実装を追っていきます。まずはimportから。

import Photos 

以下の変数も定義しておきます。

var photoAssets = [PHAsset]()

アルバム内の写真を取得する

f:id:himaratsu:20141111204902p:plain
UIはCollectionViewを使って作っています

画像をすべて取得するには以下のように記述します。

private func getAllPhotosInfo() {
    photoAssets = []
    
    // 画像をすべて取得
    var assets: PHFetchResult = PHAsset.fetchAssetsWithMediaType(.Image, options: nil)
    assets.enumerateObjectsUsingBlock { (asset, index, stop) -> Void in
        self.photoAssets.append(asset as PHAsset)
    }
    println(photoAssets)
}

fetchAssetsWithMediaTypeで欲しいメディアの種類を指定し、リクエストします。指定できるタイプは以下の4種類です。

enum PHAssetMediaType : Int {
    case Unknown
    case Image
    case Video
    case Audio
}

検索の条件を加える

日付の範囲を絞ったり、ソートして取得するにはPHFetchOptionsで指定します。
例えば日時の新しい順に並べるには、以下のようになります:

private func getAllSortedPhotosInfo() {
    photoAssets = []
    
    // ソート条件を指定
    var options = PHFetchOptions()
    options.sortDescriptors = [
        NSSortDescriptor(key: "creationDate", ascending: false)
    ]
    
    var assets: PHFetchResult = PHAsset.fetchAssetsWithMediaType(.Image, options: options)
    assets.enumerateObjectsUsingBlock { (asset, index, stop) -> Void in
        self.photoAssets.append(asset as PHAsset)
    }
    println(photoAssets)
}

上記の例ではfetchAssetsWithMediaTypeをコールしてますが、他にも色々なfetchの方法があります。詳しくは公式ドキュメントをご参照ください https://developer.apple.com/library/IOs/documentation/Photos/Reference/PHAsset_Class/index.html#//apple_ref/doc/uid/TP40014383-CH1-SW2

画像を表示する

上記で取得したPHAssetをつかって画像を表示してみましょう。

let manager: PHImageManager = PHImageManager()
manager.requestImageForAsset(asset,
    targetSize: CGSizeMake(70, 70),
    contentMode: .AspectFill,
    options: nil) { (image, info) -> Void in
        // 取得したimageをUIImageViewなどで表示する
}

PHImageManagerを使ってリクエストし、取得した情報をUIImageViewなどに表示すればOKです。
この resultHandler は場合によって複数回コールされます。大きなサイズの写真を表示するときに時間がかかるため、まずサムネを表示→実際のサイズ表示 と、フレームワークの粋な計らいのようです。これを防ぎたい場合は以下のQiitaが参考になります。

画像を削除する

画像を端末から削除するには以下のように実装します。

private func deleteFirstImage() {
    let delTargetAsset = photoAssets.first as PHAsset?
    if delTargetAsset != nil {
        PHPhotoLibrary.sharedPhotoLibrary().performChanges({ () -> Void in
                // 削除などの変更はこのblocks内でリクエストする
                PHAssetChangeRequest.deleteAssets([delTargetAsset!])
            }, completionHandler: { (success, error) -> Void in
                // 完了時の処理をここに記述
        })
    }
}

削除を実行すると以下のような確認アラートが表示されます。

f:id:himaratsu:20141111205153p:plain

Delete(日本語環境では「許可」)を選択すると写真が削除されます。

削除後30日までは復元可

削除した写真はすぐに消去されず、30日はゴミ箱に残ります。

f:id:himaratsu:20141111205257p:plain

上記は「写真」アプリの「アルバム > 最近削除した項目」の画面です。
写真ごとに削除されるまでの日数が表示されており、これが0日になると完全に削除されます。

f:id:himaratsu:20141111203648p:plain

写真を選択して右上の「Revert」ボタンを押すと上の写真の画面になり、
「Revert 3 photos」を選択すると写真がアルバムに復元されます。

写真アクセスの許可を取得する

許可を求めるシステムアラートを表示する

f:id:himaratsu:20141111205949p:plain

初めて写真を取得する際、「"あなたのアプリ名"が写真への許可を求めています」 と表示されます。この表示のタイミングを自分でコントロールするにはPHPhotoLibrary.requestAuthorization{...}を呼び出します。詳しくは以下の記事が参考になります。

許可されていない場合は設定画面に遷移させる

アルバム系アプリや写真加工アプリの場合、写真へのアクセスが拒否されていると困ることが多いかと思います。

その場合はURL Schemeで設定画面へ遷移させ、許可してもらいましょう(iOS 8以降)。

// 設定画面へ遷移する
let url = NSURL(string: UIApplicationOpenSettingsURLString)
UIApplication.sharedApplication().openURL(url!)

f:id:himaratsu:20141111211037p:plain

↑こういうアラートを表示するなどして、

f:id:himaratsu:20141111210600p:plain

↑上記のURL Schemeで設定画面へ遷移。

一度「拒否」すると自分で設定画面に辿り着くのは困難ですので、こういう助け舟も用意しておきたいですね。

以上となります。

ソースコード

今回紹介したコードはこちらからDLできます。

github.com

まとめ

iOS 8からの新しいフレームワーク「Photos framework」の使い方でした。
これまでより自由度が高くて、いろいろな写真関連のアプリが作れそうですね!

参考リンク

おすすめ本

たのしいSwiftプログラミング―[iOS 8&Xcode 6対応]

たのしいSwiftプログラミング―[iOS 8&Xcode 6対応]

詳解 Swift

詳解 Swift