Commit 8d6ceb3e by Daniel Dahan

issue-479: added delegation methods for incremental changes in PhotoLibrary

parent 8bd39698
...@@ -97,9 +97,39 @@ public protocol PhotoLibraryDelegate { ...@@ -97,9 +97,39 @@ public protocol PhotoLibraryDelegate {
/** /**
A delegation method that is executed when there is a change in the A delegation method that is executed when there is a change in the
fetchResult object. fetchResult object.
- Parameter photoLibrary: A reference to the PhotoLibrary.
- Parameter fetchBeforeChanges: A PHFetchResult<PHObject> before changes.
- Parameter fetchAfterChanges: A PHFetchResult<PHObject> after changes.
*/ */
@objc @objc
optional func photoLibrary(photoLibrary: PhotoLibrary, fetchBeforeChanges: PHFetchResult<PHObject>, fetchAfterChanges: PHFetchResult<PHObject>) optional func photoLibrary(photoLibrary: PhotoLibrary, fetchBeforeChanges: PHFetchResult<PHObject>, fetchAfterChanges: PHFetchResult<PHObject>)
/**
A delegation method that is executed when there are moved objects.
- Parameter photoLibrary: A reference to the PhotoLibrary.
- Parameter removed indexes: An IndexSet of the removed indexes.
- Parameter for objects: An Array of PHObjects that have been removed.
*/
@objc
optional func photoLibrary(photoLibrary: PhotoLibrary, removed indexes: IndexSet, for objects: [PHObject])
/**
A delegation method that is executed when there are newly inserted objects.
- Parameter photoLibrary: A reference to the PhotoLibrary.
- Parameter inserted indexes: An IndexSet of the inserted indexes.
- Parameter for objects: An Array of PHObjects that have been inserted.
*/
@objc
optional func photoLibrary(photoLibrary: PhotoLibrary, inserted indexes: IndexSet, for objects: [PHObject])
/**
A delegation method that is executed when there are changed objects.
- Parameter photoLibrary: A reference to the PhotoLibrary.
- Parameter removed indexes: An IndexSet of the changed indexes.
- Parameter for objects: An Array of PHObjects that have been changed.
*/
@objc
optional func photoLibrary(photoLibrary: PhotoLibrary, changed indexes: IndexSet, for objects: [PHObject])
} }
@objc(PhotoLibrary) @objc(PhotoLibrary)
...@@ -107,17 +137,27 @@ public class PhotoLibrary: NSObject { ...@@ -107,17 +137,27 @@ public class PhotoLibrary: NSObject {
/// A reference to the PHCachingImageManager. /// A reference to the PHCachingImageManager.
public private(set) lazy var cachingImageManager = PHCachingImageManager() public private(set) lazy var cachingImageManager = PHCachingImageManager()
/// A reference to the currently fetched album. /// A reference to the collection PHFetchResult.
public private(set) var fetchResult: PHFetchResult<PHAssetCollection>? public private(set) var collectionFetchResult: PHFetchResult<PHAssetCollection>?
/// An array of PHFetchResult<PHAsset> types.
public private(set) var assetFetchResults: [PHFetchResult<PHAsset>]!
/// The assets used in the album. /// The assets used in the album.
public private(set) var collections: [PhotoLibraryDataSource]! { public private(set) var collections: [PhotoLibraryDataSource]! {
willSet { willSet {
guard .authorized == authorizationStatus else {
return
}
cachingImageManager.stopCachingImagesForAllAssets() cachingImageManager.stopCachingImagesForAllAssets()
} }
didSet { didSet {
cachingImageManager.allowsCachingHighQualityImages = true guard .authorized == authorizationStatus else {
return
}
for dataSource in collections { for dataSource in collections {
cachingImageManager.startCachingImages(for: dataSource.assets, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFit, options: nil) cachingImageManager.startCachingImages(for: dataSource.assets, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFit, options: nil)
} }
...@@ -202,10 +242,11 @@ public class PhotoLibrary: NSObject { ...@@ -202,10 +242,11 @@ public class PhotoLibrary: NSObject {
let options = PHFetchOptions() let options = PHFetchOptions()
options.includeHiddenAssets = true options.includeHiddenAssets = true
options.includeAllBurstAssets = true options.includeAllBurstAssets = true
options.wantsIncrementalChangeDetails = false options.wantsIncrementalChangeDetails = true
s.fetchResult = PHAssetCollection.fetchAssetCollections(with: type, subtype: subtype, options: options) s.collectionFetchResult = PHAssetCollection.fetchAssetCollections(with: type, subtype: subtype, options: options)
s.fetchResult?.enumerateObjects(options: [.concurrent]) { [weak self] (collection, _, _) in
s.collectionFetchResult?.enumerateObjects(options: [.concurrent]) { [weak self] (collection, _, _) in
guard let s = self else { guard let s = self else {
return return
} }
...@@ -215,11 +256,14 @@ public class PhotoLibrary: NSObject { ...@@ -215,11 +256,14 @@ public class PhotoLibrary: NSObject {
options.sortDescriptors = [descriptor] options.sortDescriptors = [descriptor]
options.includeHiddenAssets = true options.includeHiddenAssets = true
options.includeAllBurstAssets = true options.includeAllBurstAssets = true
options.wantsIncrementalChangeDetails = true
var assets = [PHAsset]() var assets = [PHAsset]()
PHAsset.fetchAssets(in: collection, options: options).enumerateObjects(options: []) { (asset, _, _) in let result = PHAsset.fetchAssets(in: collection, options: options)
result.enumerateObjects(options: []) { (asset, _, _) in
assets.append(asset) assets.append(asset)
} }
s.assetFetchResults.append(result)
s.collections.append(PhotoLibraryDataSource(collection: collection, assets: assets)) s.collections.append(PhotoLibraryDataSource(collection: collection, assets: assets))
} }
...@@ -228,10 +272,16 @@ public class PhotoLibrary: NSObject { ...@@ -228,10 +272,16 @@ public class PhotoLibrary: NSObject {
/// A method used to prepare the instance object. /// A method used to prepare the instance object.
private func prepare() { private func prepare() {
prepareAssetFetchResults()
prepareCollections() prepareCollections()
prepareChangeObservers() prepareChangeObservers()
} }
/// Prepares the collectionFetchResult.
private func prepareAssetFetchResults() {
assetFetchResults = [PHFetchResult<PHAsset>]()
}
/// Prepares the collections. /// Prepares the collections.
private func prepareCollections() { private func prepareCollections() {
collections = [PhotoLibraryDataSource]() collections = [PhotoLibraryDataSource]()
...@@ -309,34 +359,56 @@ extension PhotoLibrary: PHPhotoLibraryChangeObserver { ...@@ -309,34 +359,56 @@ extension PhotoLibrary: PHPhotoLibraryChangeObserver {
photo library. photo library.
*/ */
public func photoLibraryDidChange(_ changeInfo: PHChange) { public func photoLibraryDidChange(_ changeInfo: PHChange) {
// Notify about the general change. DispatchQueue.main.async { [weak self] in
delegate?.photoLibrary?(photoLibrary: self, didChange: changeInfo)
// Notifiy about specific changes.
fetchResult?.enumerateObjects(options: .concurrent) { [weak self, changeInfo = changeInfo] (collection, _, _) in
guard let s = self else { guard let s = self else {
return return
} }
guard let details = changeInfo.changeDetails(for: collection) else { // Notify about the general change.
return s.delegate?.photoLibrary?(photoLibrary: s, didChange: changeInfo)
}
guard let afterChanges = details.objectAfterChanges else { // Notifiy about specific changes.
return s.collectionFetchResult?.enumerateObjects(options: .concurrent) { [weak self, changeInfo = changeInfo] (collection, _, _) in
guard let s = self else {
return
}
guard let details = changeInfo.changeDetails(for: collection) else {
return
}
guard let afterChanges = details.objectAfterChanges else {
return
}
s.delegate?.photoLibrary?(photoLibrary: s, beforeChanges: details.objectBeforeChanges, afterChanges: afterChanges, assetContentChanged: details.assetContentChanged, objectWasDeleted: details.objectWasDeleted)
} }
s.delegate?.photoLibrary?(photoLibrary: s, beforeChanges: details.objectBeforeChanges, afterChanges: afterChanges, assetContentChanged: details.assetContentChanged, objectWasDeleted: details.objectWasDeleted) s.assetFetchResults.forEach { [weak self] (result) in
} guard let s = self else {
return
guard let result = fetchResult as? PHFetchResult<AnyObject> else { }
return
} if let details = changeInfo.changeDetails(for: result as! PHFetchResult<AnyObject>) {
s.delegate?.photoLibrary?(photoLibrary: s, fetchBeforeChanges: details.fetchResultBeforeChanges, fetchAfterChanges: details.fetchResultAfterChanges)
guard let details = changeInfo.changeDetails(for: result) else {
return guard details.hasIncrementalChanges else {
return
}
if let removedIndexes = details.removedIndexes {
s.delegate?.photoLibrary?(photoLibrary: s, removed: removedIndexes, for: details.removedObjects)
}
if let insertedIndexes = details.insertedIndexes {
s.delegate?.photoLibrary?(photoLibrary: s, inserted: insertedIndexes, for: details.insertedObjects)
}
if let changedIndexes = details.changedIndexes {
s.delegate?.photoLibrary?(photoLibrary: s, changed: changedIndexes, for: details.changedObjects)
}
}
}
} }
delegate?.photoLibrary?(photoLibrary: self, fetchBeforeChanges: details.fetchResultBeforeChanges, fetchAfterChanges: details.fetchResultAfterChanges)
} }
} }
...@@ -39,15 +39,6 @@ public class PhotoLibraryController: UIViewController, PhotoLibraryDelegate { ...@@ -39,15 +39,6 @@ public class PhotoLibraryController: UIViewController, PhotoLibraryDelegate {
preparePhotoLibrary() preparePhotoLibrary()
} }
/**
Executes an authorization request with an optional completion block.
- Parameter completion: An optional completion block that is executed when
authorization status is determined.
*/
public func authorizePhotoLibrary(_ completion: ((PHAuthorizationStatus) -> Void)? = nil) {
photoLibrary.requestAuthorization(completion)
}
/// Prepares the photoLibrary. /// Prepares the photoLibrary.
private func preparePhotoLibrary() { private func preparePhotoLibrary() {
photoLibrary = PhotoLibrary() photoLibrary = PhotoLibrary()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment