1. taketomato

    Posted

    taketomato
Changes in title
+Photos Framework を使って画像を一意に管理する
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,128 @@
+iOS8で `Photos Framework` が追加されました。
+`Photos Framework` は「写真.app」や「iCloud」の写真/ビデオに対し、読み書きやプロパティの編集、変更の監視などができます。
+`App Extension`が追加されたのもあり、写真やビデオを複数のアプリで扱うための機能が用意されていいるようです。
+
+## 写真.appと画像をやりとりするサンプルを作成してみました
+`Photos Framework` では、 主に3つの階層があってその上でデータをやりとりすると理解しています。
+基本的な読み書きでは、`PHAssetColleciton`と`PHAsset`を扱うことになります。
+
+|クラス|なにを扱うのか|
+|:--|:--|
+|PHCollectionList|PHAssetCollectionの集まり|
+|PHAssetCollection|カメラロール自体やユーザ作成のフォルダ、モーメントの年など|
+|PHAsset|写真やビデオ自体|
+
+### アルバムから画像を取得して UIImageView に表示する
+````Objective-C:
+- (void)readImage {
+ // PHAssetCollection を取得します
+ PHAssestCollection * myAlbum = [self getMyAlbum];
+
+ // PHAsset をフェッチします
+ PHFetchResult *assets = [PHAsset fetchAssetsInAssetCollection:myAlbum options:nil];
+
+ // フェッチ結果から assets を取り出します
+ NSArray * assetArray = [self getAssets:assets];
+
+ // asset を使って、UIImageView をランダムに更新します
+ [self updateImageViewWithAsset:assetArray[arc4random() % assets.count]];
+}
+
+- (PHAssetCollection *)getMyAlbum {
+ // ユーザ作成のアルバム一覧を指定して、PHAssetCollection をフェッチします
+ PHFetchResult *assetCollections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum
+ subtype:PHAssetCollectionSubtypeAlbumRegular
+ options:nil];
+
+ // [My Album]の AssetCollection を取得します
+ __block PHAssetCollection * myAlbum;
+ [assetCollections enumerateObjectsUsingBlock:^(PHAssetCollection *album, NSUInteger idx, BOOL *stop) {
+ if ([album.localizedTitle isEqualToString:@"My Album"]) {
+ myAlbum = album;
+ *stop = YES;
+ }
+ }];
+
+ return myAlbum;
+}
+
+- (NSArray *)getAssets:(PHFetchResult *)fetch {
+ // フェッチ結果を配列に格納します
+ __block NSMutableArray * assetArray = NSMutableArray.new;
+ [fetch enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop) {
+ [assetArray addObject:asset];
+ }];
+ return assetArray;
+}
+
+- (void)updateImageViewWithAsset:(PHAsset *)asset {
+ typeof(self) __weak wself = self;
+ [[PHImageManager defaultManager] requestImageForAsset:asset
+ targetSize:CGSizeMake(300,300)
+ contentMode:PHImageContentModeAspectFill
+ options:nil
+ resultHandler:^(UIImage *result, NSDictionary *info) {
+ if (result) {
+ // imageVivew を更新します
+ wself.imageView.image = result;
+ }
+ }];
+}
+````
+
+### アルバムに画像を保存する
+「写真.app」へ変更を要求する場合は、`xxxChangeRequest`というクラスを使用します。
+保存するときに、`identifier`が取得できます。これを使って画像を取り出すこともできます。
+
+````Objective-C:
+- (void)addNewAssetWithImage:(UIImage *)image toAlbum:(PHAssetCollection *)album
+{
+ [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
+ // PHAssetChangeRequest を作ります
+ PHAssetChangeRequest *createAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
+
+ // PHAssetCollectionChangeRequest を作ります
+ PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:album];
+
+ // placeholder を取得して、PHAssetCollection に asset を追加します
+ PHObjectPlaceholder * placeHolder = [createAssetRequest placeholderForCreatedAsset];
+ [albumChangeRequest addAssets:@[ placeHolder ]];
+
+ // placeholder から取得できる identifier を
+ // 保存しておくと後から画像を一意に取得することができます
+ NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
+ [defaults setObject:placeHolder.localIdentifier forKey:kAssetIdentifier];
+ [defaults synchronize];
+
+ } completionHandler:^(BOOL success, NSError *error) {
+ NSLog(@"Finished adding asset. %@", (success ? @"Success" : error));
+ }];
+}
+````
+
+### 保存した画像をアルバムから Identifier で読み込む
+`getAssets:`と`updateImageViewWithAsset:`は上で記述したメソッドです。
+
+````Objective-C:
+- (void)readImageWidthIdentifier {
+ // Identifier を指定して PHAsset をフェッチします
+ NSString * identifier = [[NSUserDefaults standardUserDefaults]objectForKey:kAssetIdentifier];
+ PHFetchResult *assets = [PHAsset fetchAssetsWithLocalIdentifiers:@[identifier] options:nil];
+
+ // assets を取り出します
+ NSArray * assetArray = [self getAssets:assets];
+
+ // UIImageView を更新します
+ [self updateImageViewWithAsset:assetArray.lastObject];
+}
+````
+
+`ALAssestLibrary` との違いとして、フェッチ結果の取り出しが同期になっているのが使いやすく感じました。
+もっと使いこなせるようになっていきたいですね。
+
+### サンプルコード
+https://github.com/taketomato/photosFWsample
+
+## 参考URL
+[Photos Framework 公式ドキュメント](https://developer.apple.com/library/ios/navigation/#section=Frameworks&topic=Photos)
+[Developers.IO PhotoKit 特集](http://dev.classmethod.jp/referencecat/ios8-api-photokit/)