LoginSignup
28
28

More than 5 years have passed since last update.

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

Posted at

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

まずは復習

PhotosFrameworkの基本的なクラスです。

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

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

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

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

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

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 ] ] のような結果が格納されている。

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 を返す

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構造体の配列が取得できます。

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)!
    }

以上になります。

28
28
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
28