-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
212 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
ImagePicker.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>IDEDidComputeMac32BitWarning</key> | ||
<true/> | ||
</dict> | ||
</plist> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// | ||
// AsynchronousOperation.swift | ||
// ImagePicker | ||
// | ||
// Created by Peter Stajger on 13/04/2018. | ||
// Copyright © 2018 Inloop. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
/// | ||
/// Provides primitives for wrapping Operation with asynchronous code that can | ||
/// be enqueued in a OperationQueue and run serially. | ||
/// | ||
class AsynchronousOperation : Foundation.Operation { | ||
|
||
var stateFinished: Bool = false { | ||
willSet { willChangeValue(forKey: "isFinished") } | ||
didSet { didChangeValue(forKey: "isFinished") } | ||
} | ||
var stateExecuting: Bool = false { | ||
willSet { willChangeValue(forKey: "isExecuting") } | ||
didSet { didChangeValue(forKey: "isExecuting") } | ||
} | ||
|
||
override var isFinished: Bool { | ||
return stateFinished | ||
} | ||
|
||
override var isExecuting: Bool { | ||
return stateExecuting | ||
} | ||
|
||
override var isAsynchronous: Bool { | ||
return true | ||
} | ||
|
||
override func main() { | ||
if isCancelled { | ||
completeOperation() | ||
} | ||
else { | ||
stateExecuting = true | ||
execute() | ||
} | ||
} | ||
|
||
func execute() { | ||
fatalError("This method has to be overriden") | ||
} | ||
|
||
func completeOperation() { | ||
if self.stateExecuting == true { | ||
self.stateExecuting = false | ||
} | ||
|
||
if self.stateFinished == false { | ||
self.stateFinished = true | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// | ||
// CollectionViewBatchAnimation.swift | ||
// ImagePicker | ||
// | ||
// Created by Peter Stajger on 13/04/2018. | ||
// Copyright © 2018 Inloop. All rights reserved. | ||
// | ||
|
||
import UIKit | ||
import Photos | ||
|
||
/// | ||
/// Wraps collectionView's `performBatchUpdates` block into AsynchronousOperation. | ||
/// | ||
final class CollectionViewBatchAnimation<ObjectType> : AsynchronousOperation where ObjectType : PHObject { | ||
private let collectionView: UICollectionView | ||
private let sectionIndex: Int | ||
private let changes: PHFetchResultChangeDetails<ObjectType> | ||
|
||
init(collectionView: UICollectionView, sectionIndex: Int, changes: PHFetchResultChangeDetails<ObjectType>) { | ||
self.collectionView = collectionView | ||
self.sectionIndex = sectionIndex | ||
self.changes = changes | ||
} | ||
|
||
override func execute() { | ||
// If we have incremental diffs, animate them in the collection view | ||
collectionView.performBatchUpdates({ [unowned self] in | ||
|
||
// For indexes to make sense, updates must be in this order: | ||
// delete, insert, reload, move | ||
if let removed = self.changes.removedIndexes, removed.isEmpty == false { | ||
self.collectionView.deleteItems(at: removed.map({ IndexPath(item: $0, section: self.sectionIndex) })) | ||
} | ||
if let inserted = changes.insertedIndexes, inserted.isEmpty == false { | ||
self.collectionView.insertItems(at: inserted.map({ IndexPath(item: $0, section: self.sectionIndex) })) | ||
} | ||
if let changed = changes.changedIndexes, changed.isEmpty == false { | ||
self.collectionView.reloadItems(at: changed.map({ IndexPath(item: $0, section: self.sectionIndex) })) | ||
} | ||
changes.enumerateMoves { fromIndex, toIndex in | ||
self.collectionView.moveItem(at: IndexPath(item: fromIndex, section: self.sectionIndex), to: IndexPath(item: toIndex, section: self.sectionIndex)) | ||
} | ||
}, completion: { finished in | ||
self.completeOperation() | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// | ||
// CollectionViewUpdatesCoordinator.swift | ||
// ImagePicker | ||
// | ||
// Created by Peter Stajger on 13/04/2018. | ||
// Copyright © 2018 Inloop. All rights reserved. | ||
// | ||
|
||
import UIKit | ||
import Photos | ||
|
||
/// | ||
/// Makes sure that all updates are performed in a serial queue, especially batch animations. This | ||
/// will make sure that reloadData() will never be called durring batch updates animations, which | ||
/// will prevent collection view from crashing on internal incosistency. | ||
/// | ||
final class CollectionViewUpdatesCoordinator { | ||
deinit { | ||
log("deinit: \(String(describing: self))") | ||
} | ||
|
||
private let collectionView: UICollectionView | ||
|
||
private var serialMainQueue: OperationQueue = { | ||
let queue = OperationQueue() | ||
queue.maxConcurrentOperationCount = 1 | ||
queue.underlyingQueue = DispatchQueue.main | ||
return queue | ||
}() | ||
|
||
init(collectionView: UICollectionView) { | ||
self.collectionView = collectionView | ||
} | ||
|
||
/// Provides opportunuty to update collectionView's dataSource in underlaying queue. | ||
func performDataSourceUpdate(updates: @escaping ()->Void) { | ||
serialMainQueue.addOperation(updates) | ||
} | ||
|
||
/// Updates collection view. | ||
func performChanges<PHAsset>(_ changes: PHFetchResultChangeDetails<PHAsset>, inSection: Int) { | ||
if changes.hasIncrementalChanges { | ||
let operation = CollectionViewBatchAnimation(collectionView: collectionView, sectionIndex: inSection, changes: changes) | ||
serialMainQueue.addOperation(operation) | ||
} | ||
else { | ||
serialMainQueue.addOperation { [unowned self] in | ||
self.collectionView.reloadData() | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.