Commit 658026d5 by Daniel Dahan

updated initial PhotoLibrary codebase to include a caching instance as well as…

updated initial PhotoLibrary codebase to include a caching instance as well as collection dictionary
parent 9da25cb1
......@@ -172,6 +172,7 @@
96E3C39C1D3A1CC20086A024 /* Offset.swift in Headers */ = {isa = PBXBuildFile; fileRef = 968C99461D377849000074FF /* Offset.swift */; settings = {ATTRIBUTES = (Public, ); }; };
96E3C39E1D3A1D0C0086A024 /* BasicAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96E3C39D1D3A1D0C0086A024 /* BasicAnimation.swift */; };
96EA9A431D4E68F80052C74D /* PhotoLibrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96EA9A421D4E68F80052C74D /* PhotoLibrary.swift */; };
96EA9A4B1D4E7A430052C74D /* PhotoLibraryController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96EA9A4A1D4E7A430052C74D /* PhotoLibraryController.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
......@@ -283,6 +284,7 @@
96E3C3931D397AE90086A024 /* Material+UIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Material+UIView.swift"; sourceTree = "<group>"; };
96E3C39D1D3A1D0C0086A024 /* BasicAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasicAnimation.swift; sourceTree = "<group>"; };
96EA9A421D4E68F80052C74D /* PhotoLibrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoLibrary.swift; sourceTree = "<group>"; };
96EA9A4A1D4E7A430052C74D /* PhotoLibraryController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoLibraryController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -652,6 +654,7 @@
isa = PBXGroup;
children = (
96EA9A421D4E68F80052C74D /* PhotoLibrary.swift */,
96EA9A4A1D4E7A430052C74D /* PhotoLibraryController.swift */,
);
name = PhotoLibrary;
sourceTree = "<group>";
......@@ -946,6 +949,7 @@
96BCB7BA1CB40DC500C806FE /* CollectionView.swift in Sources */,
96BCB7A31CB40DC500C806FE /* CapturePreview.swift in Sources */,
96BCB7BC1CB40DC500C806FE /* CollectionViewDataSource.swift in Sources */,
96EA9A4B1D4E7A430052C74D /* PhotoLibraryController.swift in Sources */,
96E3C3941D397AE90086A024 /* Material+UIView.swift in Sources */,
96BCB7C71CB40DC500C806FE /* KeyframeAnimation.swift in Sources */,
96BCB7BE1CB40DC500C806FE /* CollectionViewLayout.swift in Sources */,
......
......@@ -78,16 +78,40 @@ public protocol PhotoLibraryDelegate {
optional func photoLibrary(photoLibrary: PhotoLibrary, didChange changeInfo: PHChange)
/**
Get changes objects in album.
A delegation method that is executed when changes are detected.
- Parameter photoLibrary: A reference to the PhotoLibrary.
- Parameter object: A PHObject instance.
- Parameter beforeChanges: A PHObject before changes.
- Parameter afterChanges: A PHObject after changes.
- Parameter assetContentChanged: A Bool that is true if the image or video content for this
object has changed.
- Parameter objectWasDeleted: A Bool that is true if the object was deleted.
*/
@objc
optional func photoLibrary(photoLibrary: PhotoLibrary, afterChanges object: PHObject)
optional func photoLibrary(photoLibrary: PhotoLibrary, beforeChanges: PHObject, afterChanges: PHObject, assetContentChanged: Bool, objectWasDeleted: Bool)
}
@objc(PhotoLibrary)
public class PhotoLibrary: NSObject {
/// A reference to the PHCachingImageManager.
public private(set) lazy var cachingImageManager = PHCachingImageManager()
/// A reference to the currently fetched album.
public private(set) var fetchResult: PHFetchResult<PHAssetCollection>?
/// The assets used in the album.
public private(set) var collections: [PHAssetCollection: [PHAsset]]! {
willSet {
cachingImageManager.stopCachingImagesForAllAssets()
}
didSet {
cachingImageManager.allowsCachingHighQualityImages = true
for (_, assets) in collections {
cachingImageManager.startCachingImages(for: assets, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFit, options: nil)
}
}
}
/// A reference to a PhotoLibraryDelegate.
public weak var delegate: PhotoLibraryDelegate?
......@@ -107,16 +131,6 @@ public class PhotoLibrary: NSObject {
prepare()
}
/// A method used to prepare the instance object.
public func prepare() {
prepareChangeObservers()
}
/// A method used to enable change observation.
public func prepareChangeObservers() {
PHPhotoLibrary.shared().register(self)
}
/**
A method to request authorization from the user to enable photo library access. In order
for this to work, set the "Privacy - Photo Library Usage Description" value in the
......@@ -154,29 +168,83 @@ public class PhotoLibrary: NSObject {
}
}
public func moments(in momentList: PHCollectionList, options: PHFetchOptions?) -> [PHAssetCollection] {
var v = [PHAssetCollection]()
PHAssetCollection.fetchMoments(inMomentList: momentList, options: options).enumerateObjects(options: EnumerationOptions.concurrent) { (collection, _, _) in
v.append(collection)
/**
Fetch different PHAssetCollections asynchronously based on different types and subtypes
with an optional completion block.
- Parameter type: A PHAssetCollectionType.
- Parameter subtype: A PHAssetCollectionSubtype.
- Parameter completion: An optional completion block.
*/
public func fetch(type: PHAssetCollectionType, subtype: PHAssetCollectionSubtype, completion: ([PHAssetCollection: [PHAsset]]) -> Void) {
DispatchQueue.global(attributes: DispatchQueue.GlobalAttributes.qosDefault).async { [weak self, type = type, subtype = subtype, completion = completion] in
guard let s = self else {
return
}
defer {
DispatchQueue.main.async { [weak self] in
completion(s.collections)
}
return v
}
public func fetch(with type: PHAssetCollectionType, subtype: PHAssetCollectionSubtype, options: PHFetchOptions?) -> PHFetchResult<PHAssetCollection> {
let result = PHAssetCollection.fetchAssetCollections(with: type, subtype: subtype, options: options)
return result
let options = PHFetchOptions()
options.includeHiddenAssets = true
options.includeAllBurstAssets = true
options.wantsIncrementalChangeDetails = false
s.fetchResult = PHAssetCollection.fetchAssetCollections(with: type, subtype: subtype, options: options)
s.fetchResult?.enumerateObjects(options: []) { [weak self] (collection, _, _) in
guard let s = self else {
return
}
public func performChanges(_ changeBlock: () -> Void, completionHandler: ((Bool, NSError?) -> Void)? = nil) {
PHPhotoLibrary.shared().performChanges(changeBlock, completionHandler: completionHandler)
let options = PHFetchOptions()
let descriptor = SortDescriptor(key: "creationDate", ascending: false)
options.sortDescriptors = [descriptor]
options.includeHiddenAssets = true
options.includeAllBurstAssets = true
var assets = [PHAsset]()
PHAsset.fetchAssets(in: collection, options: options).enumerateObjects(options: []) { (asset, _, _) in
assets.append(asset)
}
public func assets(in album: PHAssetCollection, options: PHFetchOptions?) -> [PHAsset] {
var v = [PHAsset]()
PHAsset.fetchAssets(in: album, options: options).enumerateObjects(options: []) { (asset, _, _) in
v.append(asset)
s.collections[collection] = assets
}
}
return v
}
/// A method used to prepare the instance object.
private func prepare() {
prepareCollections()
prepareChangeObservers()
}
/// Prepares the collections.
private func prepareCollections() {
collections = [PHAssetCollection: [PHAsset]]()
}
/// A method used to enable change observation.
private func prepareChangeObservers() {
PHPhotoLibrary.shared().register(self)
}
// public func moments(in momentList: PHCollectionList, options: PHFetchOptions?) -> [PHAssetCollection] {
// var v = [PHAssetCollection]()
// PHAssetCollection.fetchMoments(inMomentList: momentList, options: options).enumerateObjects(options: EnumerationOptions.concurrent) { (collection, _, _) in
// v.append(collection)
// }
// return v
// }
//
// public func fetch(with type: PHAssetCollectionType, subtype: PHAssetCollectionSubtype, options: PHFetchOptions?) -> PHFetchResult<PHAssetCollection> {
// let result = PHAssetCollection.fetchAssetCollections(with: type, subtype: subtype, options: options)
// return result
// }
//
public func performChanges(_ changeBlock: () -> Void, completionHandler: ((Bool, NSError?) -> Void)? = nil) {
PHPhotoLibrary.shared().performChanges(changeBlock, completionHandler: completionHandler)
}
public func image(for asset: PHAsset, targetSize: CGSize, contentMode: PHImageContentMode, options: PHImageRequestOptions?, completion: (UIImage?, [NSObject: AnyObject]?) -> Void) -> PHImageRequestID {
......@@ -192,18 +260,6 @@ public class PhotoLibrary: NSObject {
}
}
/// Albums.
extension PhotoLibrary {
/**
Creates an album with a given title.
- Parameter album title: A String.
- Returns: A PHObjectPlaceholder.
*/
public func create(album title: String) -> PHObjectPlaceholder {
return PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: title).placeholderForCreatedAssetCollection
}
}
/// PHPhotoLibraryChangeObserver extension.
extension PhotoLibrary: PHPhotoLibraryChangeObserver {
/**
......@@ -211,7 +267,27 @@ extension PhotoLibrary: PHPhotoLibraryChangeObserver {
- Parameter _ changeInstance: A PHChange obejct describing the changes in the
photo library.
*/
public func photoLibraryDidChange(_ changeInstance: PHChange) {
delegate?.photoLibrary?(photoLibrary: self, didChange: changeInstance)
public func photoLibraryDidChange(_ changeInfo: PHChange) {
delegate?.photoLibrary?(photoLibrary: self, didChange: changeInfo)
guard let result = fetchResult else {
return
}
result.enumerateObjects(options: []) { [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)
}
}
}
/*
* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.io>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of CosmicMind nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import Photos
public struct Item {
var album: PHAssetCollection
var assets: [PHAsset]
}
public class PhotoLibraryController: UIViewController, PhotoLibraryDelegate {
/// A reference to a PhotoLibrary.
public private(set) var photoLibrary: PhotoLibrary!
public override func viewDidLoad() {
super.viewDidLoad()
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.
private func preparePhotoLibrary() {
photoLibrary = PhotoLibrary()
photoLibrary.delegate = self
}
}
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