Как стать автором
Обновить

iOS: работа с галереей (Photos framework)

Время на прочтение3 мин
Количество просмотров16K
Привет, Хабр! В данной статье решил написать о том, как работать с галереей с помощью фреймворка Photos. В этой статье рассмотрим базовые возможности фреймворка: создание альбома, сохранение, удаление и загрузку фото. Если будут положительные отзывы, то в следующих частях напишу про работу с live фото, видео, наложение фильтров, кэш и прочие функции.

Обзор классов


Для начала рассмотрим классы, с которыми предстоит работать. Во фреймворке Photos все классы унаследованы от базового класса PHObject, в котором есть всего лишь одно свойство — localIdentifier.

▍PHAsset


PHAsset представляет собой данные об одном объекте из галереи — фото, видео, live фото и так далее. Важно понимать, что PHAsset это еще не фото, это только информация о нем.

▍PHAssetCollection


Это набор объектов PHAsset. Таким набором может быть альбом, момент, smart album.

▍PHPhotoLibrary


Это класс, который предоставляет доступ на запрос и изменение данных из галереи. Каждый раз, когда мы хотим что-то поменять в галерее, нам надо вызывать метод performChanges(changes: () → Void, completionHandler: (Bool, Error?) → Void).

▍PHAssetCreationRequest


Класс, позволяющий сделать запрос на создание нового объекта(PHAsset) в галерее.

▍PHAssetChangeRequest


Класс, позволяющий сделать запрос на изменение объекта в галерее.

▍PHAssetCollectionChangeRequest


Класс, позволяющий сделать запрос на изменение коллекции объектов в галерее.

▍PHImageManager


Позволяет получить фото или видео ассоциируемое с конкретным PHAsset.

▍PHFetchResult


Представляет обертку над списком PHAsset, полученных в результате запроса.

Создание альбома


Для начала нужно проверить — есть ли альбом с тем имением, с которым мы хотим его создать:

let options = PHFetchOptions()
options.predicate = NSPredicate(format: "title = %@", albumTitle)
let collection = PHAssetCollection.fetchAssetCollections(with: .album, 
                                                         subtype: .any, 
                                                         options: options)
if let album = collection.firstObject {
    // Альбом уже есть, можем его использовать
}

Если альбома нет, то для его создания нам потребуется создать запрос с помощью метода PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: String):

var placeholder: PHObjectPlaceholder?
PHPhotoLibrary.shared().performChanges({
    let request = PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: albumTitle)
    placeholder = request.placeholderForCreatedAssetCollection
}, completionHandler: { (success, error) -> Void in
    if success {
        if let id = placeholder?.localIdentifier {
            let fetchResult = PHAssetCollection.fetchAssetCollections(withLocalIdentifiers: [id], 
                                                                      options: nil)
            if let album = fetchResult.firstObject {
                // Можем использовать альбом
            }
        }
    }
})

PHObjectPlaceholder — это наследник PHObject, который по сути является прокси реального объекта, который был создан(в нашем случае это альбом). Нужен он для того, чтобы получить ID созданного объекта.

Получение списка PHAsset


Итак, мы получили альбом(а точнее PHAssetCollection), который хранит объекты PHAsset. Мы можем получить все PHAsset следующим образом:

let options = PHFetchOptions()
options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: ascending)]

let assets: PHFetchResult<PHAsset> = PHAsset.fetchAssets(in: album, options: options)

Переменная assets будет хранить список PHAsset отсортированный по возрастанию даты создания фото. Конкретный PHAsset мы можем получить, например, так:

if assets.count > 0 {
    let firstAsset = assets[0]
}

Получение UIImage


Чтобы загрузить изображение для конкретного PHAsset нам понадобится класс PHImageManager:

PHImageManager.default().requestImage(for: asset,
                                      targetSize: size,
                                      contentMode: .aspectFill,
                                      options: options) { (image, _) -> Void in
                                          // Можем использовать изображение
                                      }

Сохранение изображения


Для того, чтобы сохранить изображение, надо создать запрос методом PHAssetChangeRequest.creationRequestForAsset(from image: UIImage):

PHPhotoLibrary.shared().performChanges({
    let assetRequest = PHAssetChangeRequest.creationRequestForAsset(from: image)
    let albumChangeRequest = PHAssetCollectionChangeRequest(for: album, assets: assets)
    if let assetPlaceholder = assetRequest.placeholderForCreatedAsset {
        let assetPlaceholders: NSArray = [assetPlaceholder]
        albumChangeRequest?.addAssets(assetPlaceholders)
    }
}, completionHandler: nil)

Удаление PHAsset


Вот мы и добрались до самого сложного. Для удаления PHAsset нам понадобится метод PHAssetChangeRequest.deleteAssets(_ assets: NSFastEnumeration):

PHPhotoLibrary.shared().performChanges({
    PHAssetChangeRequest.deleteAssets(assets as NSFastEnumeration)
}, completionHandler: nil)

Заключение


Я описал базовые возможности фреймворка. В дальнейшем напишу статьи по другим его возможностям. Все что непонятно — спрашивайте в комментариях. Любая критика приветствуется.

Полезные ссылки


» Photos framework reference | Apple
» The Photos Framework | objc.io
Теги:
Хабы:
Всего голосов 9: ↑8 и ↓1+7
Комментарии3

Публикации

Истории

Работа

Swift разработчик
16 вакансий
iOS разработчик
16 вакансий

Ближайшие события

15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань