[iOS 8] PhotoKit 12 – 位置情報付の写真をフォトライブラリに複数枚追加する

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

位置情報付の写真を「写真アプリ」上のフォトライブラリに追加するサンプルプロジェクトを作ってみました。

https://github.com/hirayaCM/AddPhotosSample

アルバムアプリ等の開発で、シミュレータでのデバックを行う時などを想定しています。 シミュレータには元々5枚程度しか写真が入っていないので、枚数がもっと欲しい方や、位置情報付の写真が欲しい方にピッタリです。

↓こんな感じで位置情報付きの写真をフォトライブラリに追加できます。

ios8-photokit12-00

素材ファイルについて

当サンプルプロジェクトでは、以下のようなJSONファイルを基に写真ファイルを読み込むようにしてあります。 (JSONファイル/jpgファイルをXcodeプロジェクトにバンドルさせておきます。)

[
    {
        "imageName": "001.jpg",
        "latitude": 35.70208,
        "longitude": 139.767935
    },
    {
        "imageName": "002.jpg",
        "latitude": 35.697431,
        "longitude": 139.774696
    },
    {
        "imageName": "003.jpg",
        "latitude": 35.700722,
        "longitude": 139.697358
    },
    {
        "imageName": "004.jpg",
        "latitude": 35.715298,
        "longitude": 139.772757
    },
    {
         "imageName": "005.jpg",
         "latitude": 35.549393,
         "longitude": 139.779839
    }
]

実装

写真の取り込みが目的なのでFirstViewController(UIViewControllerのサブクラス)クラスにゴリゴリ書いてます。

[18行目〜] viewDidLoadメソッド

viewDidLoadメソッド内でcheckAuthorizationStatusメソッドを呼んでいます。

[111行目〜] checkAuthorizationStatusメソッド

アルバムへのアクセスが許可されていれば、createAlbumメソッドを呼んでいます。

[27行目〜] createAlbumメソッド

指定の名前のアルバムが未作成であれば作成し、addAssetsメソッドを呼んでいます。

[53行目〜] addAssetsメソッド

JSONファイルからNSDictionaryを作成し、1要素ごとにaddAssetWithAssetInfoメソッドを呼んでいます。

[65行目〜] addAssetWithAssetInfo:メソッド

引数のNSDictionaryからPHAssetを作成し、フォトライブラリに追加しています。また、追加したPHAssetに位置情報を付加しています。

#import "FirstViewController.h"

@import Photos;
@import CoreLocation;

static NSString * const AlbumTitle = @"ContainLocationInfo";

@interface FirstViewController ()

@property (nonatomic, strong) PHAssetCollection *assetCollection;

@end

@implementation FirstViewController

#pragma mark -  methods

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self checkAuthorizationStatus];
}

#pragma mark -  methods

- (void)createAlbum
{
    PHFetchOptions *options = [PHFetchOptions new];
    options.predicate = [NSPredicate predicateWithFormat:@"localizedTitle == %@", AlbumTitle];
    PHFetchResult *albums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:options];
    
    if (albums.count > 0) {
        // Album is exist
        self.assetCollection = albums[0];
        [self addAssets];
    } else {
        // Create new album.
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:AlbumTitle];
        } completionHandler:^(BOOL success, NSError *error) {
            if (!success) {
                NSLog(@"Error creating AssetCollection: %@", error);
            } else {
                PHFetchResult *albums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:options];
                self.assetCollection = albums[0];
                [self addAssets];
            }
        }];
    }
}

- (void)addAssets
{
    // Read asset infomation from JSON file
    NSString *path = [[NSBundle mainBundle] pathForResource:@"assetInfo" ofType:@"json"];
    NSData *jsonData = [NSData dataWithContentsOfFile:path options:kNilOptions error:nil];
    NSArray *assetInfoList = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:nil];
    
    for (NSDictionary *assetInfo in assetInfoList) {
        [self addAssetWithAssetInfo:assetInfo];
    }
}

- (void)addAssetWithAssetInfo:(NSDictionary *)assetInfo
{
    __block NSString *localIdentifier;
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        // Create PHAsset from UIImage
        NSString *imageName = assetInfo[@"imageName"];
        PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:[UIImage imageNamed:imageName]];
        
        PHObjectPlaceholder *assetPlaceholder = assetChangeRequest.placeholderForCreatedAsset;
        localIdentifier = assetPlaceholder.localIdentifier;
        
        // Add PHAsset to PHAssetCollection
        PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:self.assetCollection];
        [assetCollectionChangeRequest addAssets:@[assetPlaceholder]];
        
    } completionHandler:^(BOOL success, NSError *error) {
        if (!success) {
            NSLog(@"creating Asset Error: %@", error);
        } else {
            NSLog(@"creating Asset Success");
            PHFetchResult *assets = [PHAsset fetchAssetsWithLocalIdentifiers:@[localIdentifier] options:nil];
            PHAsset *asset = assets[0];
            
            NSNumber *latitude = assetInfo[@"latitude"];
            NSNumber *longitude = assetInfo[@"longitude"];
            
            if (latitude && longitude) {
                // add location data
                CLLocation *location = [[CLLocation alloc]initWithLatitude:latitude.doubleValue longitude:longitude.doubleValue];
                if ([asset canPerformEditOperation:PHAssetEditOperationProperties]) {
                    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
                        PHAssetChangeRequest *request = [PHAssetChangeRequest changeRequestForAsset:asset];
                        [request setLocation:location];
                    } completionHandler:^(BOOL success, NSError *error) {
                        if (success) {
                            NSLog(@"%s add location data success", __PRETTY_FUNCTION__);
                        }
                    }];
                }
            } else {
                NSLog(@"latitude or longitude value is nil");
            }
        }
    }];
}

- (void)checkAuthorizationStatus
{
    PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
    switch (status) {
        case PHAuthorizationStatusAuthorized:
            // The user has explicitly granted your app access to the photo library.
            NSLog(@"%s authorizationStatus is PHAuthorizationStatusAuthorized", __PRETTY_FUNCTION__);
            [self createAlbum];
            break;
            
        case PHAuthorizationStatusNotDetermined:
        {
            // Explicit user permission is required for photo library access, but the user has not yet granted or denied such permission.
            NSLog(@"%s authorizationStatus is PHAuthorizationStatusNotDetermined", __PRETTY_FUNCTION__);
            
            // Requests the user’s permission, if needed, for accessing the Photos library.
            [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status){
                [self createAlbum];
            }];
        }
            break;
            
        case PHAuthorizationStatusRestricted:
            NSLog(@"%s authorizationStatus is PHAuthorizationStatusRestricted", __PRETTY_FUNCTION__);
            break;
            
        case PHAuthorizationStatusDenied:
            NSLog(@"%s authorizationStatus is PHAuthorizationStatusDenied", __PRETTY_FUNCTION__);
            break;
    }
}

@end

まとめ

本記事は、位置情報付の写真をフォトライブラリに追加する実装例の紹介でした。サンプルプロジェクトは以下のリポジトリで公開しています。

https://github.com/hirayaCM/AddPhotosSample