mirror of
https://github.com/samsonjs/Advanced-NSOperations.git
synced 2026-03-25 08:25:47 +00:00
104 lines
4.2 KiB
Swift
104 lines
4.2 KiB
Swift
/*
|
||
Copyright (C) 2015 Apple Inc. All Rights Reserved.
|
||
See LICENSE.txt for this sample’s licensing information
|
||
|
||
Abstract:
|
||
This file sets up the operations to download and parse earthquake data. It will also decide to display an error message, if appropriate.
|
||
*/
|
||
|
||
import CoreData
|
||
|
||
/// A composite `EarthquakeOperation` to both download and parse earthquake data.
|
||
class GetEarthquakesOperation: GroupOperation {
|
||
// MARK: Properties
|
||
|
||
let downloadOperation: DownloadEarthquakesOperation
|
||
let parseOperation: ParseEarthquakesOperation
|
||
|
||
private var hasProducedAlert = false
|
||
|
||
/**
|
||
- parameter context: The `NSManagedObjectContext` into which the parsed
|
||
Earthquakes will be imported.
|
||
|
||
- parameter completionHandler: The handler to call after downloading and
|
||
parsing are complete. This handler will be
|
||
invoked on an arbitrary queue.
|
||
*/
|
||
init(context: NSManagedObjectContext, completionHandler: @escaping () -> Void) {
|
||
let cachesFolder = try! FileManager.default.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
|
||
|
||
let cacheFile = cachesFolder.appendingPathComponent("earthquakes.json")
|
||
|
||
/*
|
||
This operation is made of three child operations:
|
||
1. The operation to download the JSON feed
|
||
2. The operation to parse the JSON feed and insert the elements into the Core Data store
|
||
3. The operation to invoke the completion handler
|
||
*/
|
||
downloadOperation = DownloadEarthquakesOperation(cacheFile: cacheFile)
|
||
parseOperation = ParseEarthquakesOperation(cacheFile: cacheFile, context: context)
|
||
|
||
let finishOperation = EarthquakeBlockOperation(block: { _ in completionHandler() })
|
||
|
||
// These operations must be executed in order
|
||
parseOperation.addDependency(downloadOperation)
|
||
finishOperation.addDependency(parseOperation)
|
||
|
||
super.init(operations: [downloadOperation, parseOperation, finishOperation])
|
||
|
||
name = "Get Earthquakes"
|
||
}
|
||
|
||
override func operationDidFinish(operation: Operation, withErrors errors: [NSError]) {
|
||
if let firstError = errors.first, (operation === downloadOperation || operation === parseOperation) {
|
||
produceAlert(error: firstError)
|
||
}
|
||
}
|
||
|
||
private func produceAlert(error: NSError) {
|
||
/*
|
||
We only want to show the first error, since subsequent errors might
|
||
be caused by the first.
|
||
*/
|
||
if hasProducedAlert { return }
|
||
|
||
let alert = AlertOperation()
|
||
|
||
let errorReason = (error.domain, error.code, error.userInfo[OperationConditionKey] as? String)
|
||
|
||
// These are examples of errors for which we might choose to display an error to the user
|
||
let failedReachability = (OperationErrorDomain, OperationErrorCode.ConditionFailed, ReachabilityCondition.name)
|
||
|
||
let failedJSON = (NSCocoaErrorDomain, NSPropertyListReadCorruptError, nil as String?)
|
||
|
||
switch errorReason {
|
||
case failedReachability:
|
||
// We failed because the network isn't reachable.
|
||
let hostURL = error.userInfo[ReachabilityCondition.hostKey] as! URL
|
||
|
||
alert.title = "Unable to Connect"
|
||
alert.message = "Cannot connect to \(hostURL.host!). Make sure your device is connected to the internet and try again."
|
||
|
||
case failedJSON:
|
||
// We failed because the JSON was malformed.
|
||
alert.title = "Unable to Download"
|
||
alert.message = "Cannot download earthquake data. Try again later."
|
||
|
||
default:
|
||
return
|
||
}
|
||
|
||
produceOperation(operation: alert)
|
||
hasProducedAlert = true
|
||
}
|
||
}
|
||
|
||
// Operators to use in the switch statement.
|
||
private func ~=(lhs: (String, Int, String?), rhs: (String, Int, String?)) -> Bool {
|
||
return lhs.0 ~= rhs.0 && lhs.1 ~= rhs.1 && lhs.2 == rhs.2
|
||
}
|
||
|
||
private func ~=(lhs: (String, OperationErrorCode, String), rhs: (String, Int, String?)) -> Bool {
|
||
return lhs.0 ~= rhs.0 && lhs.1.rawValue ~= rhs.1 && lhs.2 == rhs.2
|
||
}
|