しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

Phones.frameworkで端末の写真の取得・保存・削除

Phones.frameworkを使って、端末の写真の取得・保存・削除を試してみました。

写真を操作する前にInfo.plistにNSPhotoLibraryUsageDescriptionに写真を操作する理由を記述します。
これがないとアプリがクラッシュします。

f:id:llcc:20170925143607p:plain

取得

端末写真をUIImageとして取得する処理は下の通りです。
PHAsset.fetchAssetsでPHAssetを取得、PHImageManagerと取得したPHAssetを使ってUIImageを読み込んでいます。

import UIKit
import Photos

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let options = PHFetchOptions()
        let result = PHAsset.fetchAssets(with: .image, options: options)
        if let asset = result.firstObject {
            PHImageManager.default().requestImage(for: asset, targetSize: CGSize(width: asset.pixelWidth, height: asset.pixelHeight), contentMode: .aspectFill, options: nil, resultHandler: { image, options in
                
                let imageView = UIImageView(image: image)
                imageView.frame.origin.x = (self.view.frame.width - imageView.frame.width) / 2
                self.view.addSubview(imageView)
            })
        }
    }
}

起動すると写真が表示されていることが分かります。

f:id:llcc:20170925144344p:plain

fetchAssetsの戻り値は下のようなメソッドを持っています。

let result = PHAsset.fetchAssets(with: .image, options: PHFetchOptions())
result.count // → 件数
result.object(at: 0) // → 0番目の要素(PHAsset)
result.objects(at: [0, 1, 2]) // → 0, 1, 2番目の要素の配列
result.countOfAssets(with: .audio) // → audioアセットの数を取得

取得の際はソート・NSPredicateを使った絞り込み・取得件数の指定も可能です。

let options = PHFetchOptions()
options.sortDescriptors = [
    NSSortDescriptor(key: "creationDate", ascending: false)
]
options.predicate = NSPredicate(format: "pixelWidth < 2000")
options.fetchLimit = 1
let result = PHAsset.fetchAssets(with: .image, options: options)

削除

削除処理は下の通りです。
PHAssetChangeRequestのdeleteAssetsメソッドにPHAssetを渡す事で削除します。

if !asset.canPerform(.delete) {
    return
}

PHPhotoLibrary.shared().performChanges({
    PHAssetChangeRequest.deleteAssets(NSArray(array: [asset]))
}, completionHandler: { _, _ in
    // 削除後の処理
})

削除の前に、自動で下のダイアログが表示されます。

f:id:llcc:20170925145353p:plain

PHAssetChangeRequestのdeleteAssetsですが、performChangesメソッドを使わずに呼び出すと下のようなエラーになります。

// 単独で呼ぶと下のようなエラー
PHAssetChangeRequest.deleteAssets(NSArray(array: [asset]))

// 'NSInternalInconsistencyException', reason: 'This method can only be called from inside of -[PHPhotoLibrary performChanges:completionHandler:] or -[PHPhotoLibrary performChangesAndWait:error:]'

保存

保存は下の通りです。
PHAssetChangeRequestのcreationRequestForAssetにUIImageを渡す事で端末への保存ができます。

let image = UIImage()

PHPhotoLibrary.shared().performChanges({
    PHAssetChangeRequest.creationRequestForAsset(from: image)
}, completionHandler: { _, _ in
    // 作成後の処理
})