iOS8で Photos Framework
が追加されました。
Photos Framework
は「写真.app」や「iCloud」の写真/ビデオに対し、読み書きやプロパティの編集、変更の監視などができます。
App Extension
が追加されたのもあり、写真やビデオを複数のアプリで扱うための機能が用意されています。
写真.appと画像をやりとりするサンプルを作成してみました
Photos Framework
では、 主に3つの階層があってその上でデータをやりとりします。
基本的な読み書きでは、PHAssetColleciton
とPHAsset
を扱うことになります。
クラス | なにを扱うのか |
---|---|
PHCollectionList | PHAssetCollectionの集まり |
PHAssetCollection | カメラロール自体やユーザ作成のフォルダ、モーメントの年など |
PHAsset | 写真やビデオ自体 |
アルバムから画像を取得して UIImageView に表示する
- (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
が取得できます。これを使って画像を取り出すこともできます。
- (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:
は上で記述したメソッドです。
- (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
との違いとして、フェッチ結果の取り出しが同期になっているのが使いやすく感じました。
もっと使いこなせるようになっていきたいですね。
サンプルコード