[Swift]PhotosFrameworkを使ってカメラロールから画像を年別月別に取り出してみる

SwiftでPhotosFrameworkを使ってカメラロールから画像を取得する処理を書いてみました。
Swiftはまだあまり書いていないので、文法的に微妙なところがあるかもしれません。

## まずは復習
PhotosFrameworkの基本的なクラスです。

|クラス|なにを扱うのか|
|:--|:--|
|PHCollectionList|PHAssetCollectionの集まり|
|PHAssetCollection|カメラロール自体やユーザ作成のフォルダ、モーメントの年など|
|PHAsset|画像やビデオ自体|
|PHFetchResult|fetch結果を格納する|

PHAssetCollectionやPHAssetのfetch結果をPHFetchResultに格納し、enumerateObjectsUsingBlockで中身を取り出すのが基本的なアプローチになります。

## 画像を年別月別で配列に格納するサンプル

フォルダ別ではなく、年別に画像を取得する場合 Moment という概念でアクセスしていくことになります。

### 冒頭でPhotosをインポートします

```Swift:Sample.swift
import Photos
```

### MomentList ( =PHCollectionList) を取得します

fetchCollectionListsWithType の type に MomentList、subType に Any を指定すると、
各年のPHAssetCollectionが1つだけ入ったPHCollectionListと、各年のPHAssetCollectionListがすべて入ったPHCollectionListが取得できます。

例)カメラロールに2015年、2014年、2013年に撮影した画像が入っている場合、
PHFetchResultには [ [ 2015 ] , [ 2014 ] , [ 2013 ] , [ 2015,2014,2013 ] ] のような結果が格納されている。

```Swift:Sample.swift
    // モーメントリストを取得する
    private func getMomentList() -> [PHCollectionList] {
        let fetchResult: PHFetchResult = PHCollectionList.fetchCollectionListsWithType(.MomentList, subtype: .Any, options: nil)
        var momentLists = [PHCollectionList]()
        fetchResult.enumerateObjectsUsingBlock { (moment, idx, stop) -> Void in
            momentLists.append(moment as! PHCollectionList)
        }
        return momentLists
    }
```

### MomentList から Moment ( =PHAssetCollection) を取得します

self.getMoment(momentLists[0]) のような形で momentList の1つを渡し、moment を取得します。

例) [ 2015 ] = PHCollectionList を渡し、[ 2015 ] = PHAssetCollection を返す

```Swift:Sample.swift
    // モーメントを取得する
    private func getMoment(momentList: PHCollectionList) -> [PHAssetCollection] {
        let fetchResult: PHFetchResult = PHAssetCollection.fetchMomentsInMomentList(momentList, options: nil)
        var moments = [PHAssetCollection]()
        if fetchResult.count == 1 {
            fetchResult.enumerateObjectsUsingBlock{ (moment, idx, stop) -> Void in
                moments.append(moment as! PHAssetCollection)
            }
        }
        return moments
    }
```

### Momentから画像を月別に配列に格納します

self.getPhotosByMonth(moments[0]) のような形で moment の1つを渡し、画像を月別に取得します。
これで[PHAsset]の配列を格納したPhotos構造体の配列が取得できます。

```Swift:Sample.swift

    struct Photos {
        var exist: Bool = false
        var photos: [PHAsset] = []
    }

    // 写真を月別に取得する
    private func getPhotosByMonth(moment: PHAssetCollection) -> [Photos] {

        // 年の文字列を取得する
        let formatter = NSDateFormatter.new()
        formatter.dateFormat = "yyyy"
        let year = formatter.stringFromDate(moment.startDate)

        var photosByMonth = [Photos]()

        for var i = 1 ; i <= 12 ; i++ {
            // 月初日と月末日を生成します
            let month = NSString(format:"%02d", i) as String
            let fromDate = self.getDateFromString(year, month: month, day: "01")
            let toDate = self.getMonthEndingDate(fromDate!)

            // オプションを指定してフェッチします
            let fetchOption = PHFetchOptions.new()
            fetchOption.predicate = NSPredicate(format: "(creationDate >= %@) and (creationDate) < %@", fromDate!, toDate)
            fetchOption.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
            
            let fetchResult: PHFetchResult = PHAsset.fetchAssetsInAssetCollection(moment, options: fetchOption)
            var photos = Photos()
            if fetchResult.count != 0 {
                photos.exist = true
                fetchResult.enumerateObjectsUsingBlock { (photo, idx, stop) -> Void in
                    photos.photos.append(photo as! PHAsset)
                }
            }
            else {
                photos.exist = false
            }
            photosByMonth.append(photos)
        }
        return photosByMonth
    }

    private func getDateFromString(year: String, month: String, day: String) -> NSDate? {
        let formatter = NSDateFormatter.new()
        formatter.calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)!  // 24時間表示対策
        formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
        formatter.dateFormat = "yyyyMMdd"
        let dateString = year + month + day
        return formatter.dateFromString(dateString)
    }
    
    private func getMonthEndingDate(beginningDate: NSDate) -> NSDate {
        let calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)!
        calendar.timeZone = NSTimeZone(forSecondsFromGMT: 0)
        var comp = calendar.components(
            NSCalendarUnit.CalendarUnitYear
                | NSCalendarUnit.CalendarUnitMonth
                | NSCalendarUnit.CalendarUnitDay
                | NSCalendarUnit.CalendarUnitHour
                | NSCalendarUnit.CalendarUnitMinute
                | NSCalendarUnit.CalendarUnitSecond
            , fromDate:beginningDate)
        comp.hour = 23
        comp.minute = 59
        comp.second = 59
        let range = calendar.rangeOfUnit(NSCalendarUnit.CalendarUnitDay, inUnit: NSCalendarUnit.CalendarUnitMonth, forDate: beginningDate)
        comp.day = range.length
        return calendar.dateFromComponents(comp)!
    }

```

以上になります。