Skip to content

Instantly share code, notes, and snippets.

@piercifani
Last active October 13, 2016 05:11
Show Gist options
  • Save piercifani/6975feda8664e4d828b2581dda941847 to your computer and use it in GitHub Desktop.
Save piercifani/6975feda8664e4d828b2581dda941847 to your computer and use it in GitHub Desktop.
Crash on observing NSProgress
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var observer: ProgressObserver?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let task = SyncAllInteractor.syncAll()
task.upon {
print($0)
}
observer = ProgressObserver(progress: task.progress, onUpdate: { (progress) in
print(progress.fractionCompleted)
})
return true
}
}
// MARK:- Make Tasks Great Again
import Foundation
import Deferred
class SyncAllInteractor: NSObject {
typealias SyncHandler = (NSError?) -> Void
static func syncAll() -> Task<()> {
return syncFolder(folderID: "69")
}
static func sync(items: [Item]) -> [Task<()>] {
return items.map { (item) in
if item.isFolder {
return self.syncFolder(folder: item as! Folder)
} else {
return self.sync(file: item as! File)
}
}
}
static func syncFolder(folderID: String) -> Task<()> {
return fetchFolderInfo(folderID: folderID).andThen(upon: DispatchQueue.any()) { (items) in
return sync(items: items).allSucceeded()
}
}
static func syncFolder(folder: Folder) -> Task<()> {
return syncFolder(folderID: folder.modelID)
}
static func sync(file: File) -> Task<()> {
let deferred = Deferred<TaskResult<()>>()
DispatchQueue.global().async {
deferred.fill(with: .success(()))
}
let progress = Progress(totalUnitCount: 1)
progress.isPausable = false
progress.isCancellable = true
progress.cancellationHandler = {
//NO OP
print("Attempt to cancel")
}
return Task(future: Future(deferred), progress: progress)
}
static func fetchFolderInfo(folderID: String) -> Task<[Item]> {
let deferred = Deferred<TaskResult<[Item]>>()
DispatchQueue.global().async {
let items = [File(), File(), File(), File(), File()]
deferred.fill(with: .success((items)))
}
let progress = Progress(totalUnitCount: 1)
progress.isPausable = false
progress.isCancellable = true
progress.cancellationHandler = {
//NO OP
print("Attempt to cancel")
}
return Task(future: Future(deferred), progress: progress)
}
}
//MARK: Model
protocol Item {
var modelID: String { get }
var isFolder: Bool { get }
var isFile: Bool { get }
}
struct File: Item {
var modelID: String = String.random()
let isFolder: Bool = false
let isFile: Bool = true
}
struct Folder: Item {
var modelID: String = String.random()
let isFolder: Bool = true
let isFile: Bool = false
}
extension String {
static func random(length: Int = 20) -> String {
let base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var randomString: String = ""
for _ in 0..<length {
let randomValue = arc4random_uniform(UInt32(base.characters.count))
randomString += "\(base[base.index(base.startIndex, offsetBy: Int(randomValue))])"
}
return randomString
}
}
//MARK: - ProgressObserver
public class ProgressObserver: NSObject {
fileprivate let onUpdate: (Progress) -> Void
fileprivate let progress: Progress
public init(progress: Progress, onUpdate: @escaping (Progress) -> Void) {
self.progress = progress
self.onUpdate = onUpdate
super.init()
progress.addObserver(self, forKeyPath: "fractionCompleted", options: .new, context: nil)
}
override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let progress = object as? Progress , progress == self.progress {
DispatchQueue.main.async {
self.onUpdate(progress)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment