From 54235b0a17754d71750fc457b6a6319fb9042b2b Mon Sep 17 00:00:00 2001 From: "k.tatroe" Date: Tue, 4 Oct 2016 10:46:57 -0600 Subject: [PATCH 01/14] Swift 3 updates. --- Horatio/Container/Container.swift | 34 ++--- Horatio/Features/FeatureCondition.swift | 26 ++-- Horatio/Features/FeatureManager.swift | 4 +- Horatio/Features/FeatureSelector.swift | 10 +- Horatio/Features/FeatureSubject.swift | 4 +- Horatio/Features/VendorIDFeatureSubject.swift | 2 +- Horatio/JSON/JSONParsing.swift | 70 +++++----- Horatio/JSON/JSONServiceRequest.swift | 18 +-- .../JSON/JSONServiceResponseProcessor.swift | 26 ++-- Horatio/Operations/AlertOperation.swift | 12 +- Horatio/Operations/BlockObserver.swift | 14 +- Horatio/Operations/BlockOperation.swift | 28 ++-- .../Operations/CKContainer+Operations.swift | 28 ++-- Horatio/Operations/CalendarCondition.swift | 26 ++-- Horatio/Operations/CloudCondition.swift | 14 +- Horatio/Operations/DelayOperation.swift | 34 ++--- .../Operations/Dictionary+Operations.swift | 2 +- .../Operations/ExclusivityController.swift | 24 ++-- Horatio/Operations/GroupOperation.swift | 36 ++--- Horatio/Operations/HealthCondition.swift | 24 ++-- Horatio/Operations/LocationCondition.swift | 40 +++--- Horatio/Operations/LocationOperation.swift | 30 ++-- Horatio/Operations/MutuallyExclusive.swift | 6 +- Horatio/Operations/NSLock+Operations.swift | 2 +- .../Operations/NSOperation+Operations.swift | 6 +- Horatio/Operations/NSURL+CacheFiles.swift | 10 +- Horatio/Operations/NegatedCondition.swift | 14 +- Horatio/Operations/NetworkObserver.swift | 36 ++--- .../Operations/NoCancelledDependencies.swift | 16 +-- Horatio/Operations/Operation.swift | 130 +++++++++--------- Horatio/Operations/OperationCondition.swift | 28 ++-- Horatio/Operations/OperationErrors.swift | 6 +- Horatio/Operations/OperationObserver.swift | 6 +- Horatio/Operations/OperationQueue.swift | 14 +- Horatio/Operations/PassbookCondition.swift | 12 +- Horatio/Operations/PhotosCondition.swift | 18 +-- .../Operations/ReachabilityCondition.swift | 28 ++-- .../RemoteNotificationCondition.swift | 54 ++++---- Horatio/Operations/SilentCondition.swift | 4 +- Horatio/Operations/TimeoutObserver.swift | 20 +-- .../UIUserNotifications+Operations.swift | 8 +- .../Operations/URLSessionTaskOperation.swift | 21 +-- .../UserNotificationCondition.swift | 30 ++-- Horatio/Scheduler/TaskScheduler.swift | 24 ++-- Horatio/Services/Service.swift | 4 +- .../ServiceEndpoint+JSONParsing.swift | 8 +- Horatio/Services/ServiceEndpoint.swift | 22 +-- .../ServiceEndpointPathTransformer.swift | 21 +-- Horatio/Services/ServiceRequest.swift | 22 +-- .../Services/ServiceRequestConfigurator.swift | 22 +-- .../Services/ServiceRequestDecorator.swift | 46 +++---- .../Services/ServiceRequestOperation.swift | 51 +++---- Horatio/Services/ServiceRequestStatus.swift | 34 ++--- Horatio/Services/ServiceSession.swift | 6 +- .../HoratioDemo.xcodeproj/project.pbxproj | 17 ++- .../UserInterfaceState.xcuserstate | Bin 41052 -> 45120 bytes HoratioDemo/HoratioDemo/AppDelegate.swift | 2 +- .../HoratioDemoTests/HoratioDemoTests.swift | 6 +- 58 files changed, 633 insertions(+), 627 deletions(-) diff --git a/Horatio/Container/Container.swift b/Horatio/Container/Container.swift index e99d767..9d2bc5a 100644 --- a/Horatio/Container/Container.swift +++ b/Horatio/Container/Container.swift @@ -35,17 +35,17 @@ import Foundation if let bridge = Container.resolve(ParkServiceBridge.self) { } */ -public class Container { +open class Container { static internal var sharedContainer = Container() - private var services = [ContainerItemKey: ContainerItemType]() + fileprivate var services = [ContainerItemKey: ContainerItemType]() - public func register(serviceType: T.Type, name: String? = nil, factory: Resolvable -> T) -> ContainerEntry { + open func register(_ serviceType: T.Type, name: String? = nil, factory: (Resolvable) -> T) -> ContainerEntry { return registerFactory(serviceType, factory: factory, name: name) } - internal func registerFactory(serviceType: T.Type, factory: Factory, name: String?) -> ContainerEntry { - let key = ContainerItemKey(factoryType: factory.dynamicType, name: name) + internal func registerFactory(_ serviceType: T.Type, factory: Factory, name: String?) -> ContainerEntry { + let key = ContainerItemKey(factoryType: type(of: factory), name: name) let entry = ContainerEntry(serviceType: serviceType, factory: factory) services[key] = entry @@ -53,24 +53,24 @@ public class Container { return entry } - static public func register(serviceType: T.Type, name: String? = nil, factory: Resolvable -> T) -> ContainerEntry { + static open func register(_ serviceType: T.Type, name: String? = nil, factory: (Resolvable) -> T) -> ContainerEntry { return sharedContainer.register(serviceType, name: name, factory: factory) } } extension Container : Resolvable { - public func resolve(serviceType: T.Type, name: String? = nil) -> T? { - typealias FactoryType = Resolvable -> T + public func resolve(_ serviceType: T.Type, name: String? = nil) -> T? { + typealias FactoryType = (Resolvable) -> T return resolveFactory(name) { (factory: FactoryType) in factory(self) } } - static public func resolve(serviceType: T.Type, name: String? = nil) -> T? { + static public func resolve(_ serviceType: T.Type, name: String? = nil) -> T? { return sharedContainer.resolve(serviceType, name: name) } - internal func resolveFactory(name: String?, invoker: Factory -> T) -> T? { + internal func resolveFactory(_ name: String?, invoker: (Factory) -> T) -> T? { let key = ContainerItemKey(factoryType: Factory.self, name: name) if let entry = services[key] as? ContainerEntry { @@ -84,7 +84,7 @@ extension Container : Resolvable { return nil } - private func resolveEntry(entry: ContainerEntry, key: ContainerItemKey, invoker: Factory -> T) -> T { + fileprivate func resolveEntry(_ entry: ContainerEntry, key: ContainerItemKey, invoker: (Factory) -> T) -> T { let resolvedInstance = invoker(entry.factory as! Factory) return resolvedInstance @@ -95,13 +95,13 @@ extension Container : Resolvable { public typealias FunctionType = Any public protocol Resolvable { - func resolve(serviceType: T.Type, name: String?) -> T? + func resolve(_ serviceType: T.Type, name: String?) -> T? } internal struct ContainerItemKey { - private let factoryType: FunctionType.Type - private let name: String? + fileprivate let factoryType: FunctionType.Type + fileprivate let name: String? internal init(factoryType: FunctionType.Type, name: String? = nil) { self.factoryType = factoryType @@ -112,7 +112,7 @@ internal struct ContainerItemKey { extension ContainerItemKey : Hashable { var hashValue: Int { - return String(factoryType).hashValue ^ (name?.hashValue ?? 0) + return String(describing: factoryType).hashValue ^ (name?.hashValue ?? 0) } } @@ -123,8 +123,8 @@ func == (lhs: ContainerItemKey, rhs: ContainerItemKey) -> Bool { internal typealias ContainerItemType = Any -public class ContainerEntry : ContainerItemType { - private let serviceType: T.Type +open class ContainerEntry : ContainerItemType { + fileprivate let serviceType: T.Type let factory: FunctionType var instance: Any? = nil diff --git a/Horatio/Features/FeatureCondition.swift b/Horatio/Features/FeatureCondition.swift index 188252b..1b85fc4 100644 --- a/Horatio/Features/FeatureCondition.swift +++ b/Horatio/Features/FeatureCondition.swift @@ -9,7 +9,7 @@ import Foundation Determines whether a feature is currently available to a given `FeatureSubject`. */ protocol FeatureCondition { - func isMet(subject: FeatureSubject?) -> Bool + func isMet(_ subject: FeatureSubject?) -> Bool } @@ -19,7 +19,7 @@ protocol FeatureCondition { class DateFeatureCondition: FeatureCondition { // MARK: - Initialization - init(startDate: NSDate? = nil, endDate: NSDate? = nil) { + init(startDate: Date? = nil, endDate: Date? = nil) { self.startDate = startDate self.endDate = endDate } @@ -29,17 +29,17 @@ class DateFeatureCondition: FeatureCondition { // MARK: - - func isMet(subject: FeatureSubject?) -> Bool { - let currentDate = NSDate() + func isMet(_ subject: FeatureSubject?) -> Bool { + let currentDate = Date() if let startDate = startDate { - if currentDate.compare(startDate) == NSComparisonResult.OrderedAscending { + if currentDate.compare(startDate) == ComparisonResult.orderedAscending { return false } } if let endDate = endDate { - if currentDate.compare(endDate) == NSComparisonResult.OrderedDescending { + if currentDate.compare(endDate) == ComparisonResult.orderedDescending { return false } } @@ -50,8 +50,8 @@ class DateFeatureCondition: FeatureCondition { // MARK: - Private - private let startDate: NSDate? - private let endDate: NSDate? + fileprivate let startDate: Date? + fileprivate let endDate: Date? } @@ -71,14 +71,14 @@ class InverseFeatureCondition: FeatureCondition { // MARK: - - func isMet(subject: FeatureSubject?) -> Bool { + func isMet(_ subject: FeatureSubject?) -> Bool { return !condition.isMet(subject) } // MARK: - Private - private let condition: FeatureCondition + fileprivate let condition: FeatureCondition } @@ -98,13 +98,13 @@ class AndFeatureCondition: FeatureCondition { // MARK: - - func isMet(subject: FeatureSubject?) -> Bool { + func isMet(_ subject: FeatureSubject?) -> Bool { return lhs.isMet(subject) && rhs.isMet(subject) } // MARK: - Private - private let lhs: FeatureCondition - private let rhs: FeatureCondition + fileprivate let lhs: FeatureCondition + fileprivate let rhs: FeatureCondition } diff --git a/Horatio/Features/FeatureManager.swift b/Horatio/Features/FeatureManager.swift index b438db9..bca311e 100644 --- a/Horatio/Features/FeatureManager.swift +++ b/Horatio/Features/FeatureManager.swift @@ -12,7 +12,7 @@ import Foundation environments). */ protocol FeatureProvider { - func feature(named: String) -> Feature? + func feature(_ named: String) -> Feature? func activeSubject() -> FeatureSubject? } @@ -79,5 +79,5 @@ class StaticFeature: Feature { // MARK: - Private - private let staticValue: FeatureValue + fileprivate let staticValue: FeatureValue } diff --git a/Horatio/Features/FeatureSelector.swift b/Horatio/Features/FeatureSelector.swift index 9935b71..e680709 100644 --- a/Horatio/Features/FeatureSelector.swift +++ b/Horatio/Features/FeatureSelector.swift @@ -11,7 +11,7 @@ import Foundation */ protocol FeatureSelector { /// Returns the selector's mapped value in the range [0, 1) for a given subject and feature. - func select(feature: Feature, subject: FeatureSubject?) -> Double? + func select(_ feature: Feature, subject: FeatureSubject?) -> Double? } @@ -24,7 +24,7 @@ class WeightedFeatureSelector: FeatureSelector { // MARK: - func select(feature: Feature, subject: FeatureSubject? = nil) -> Double? { + func select(_ feature: Feature, subject: FeatureSubject? = nil) -> Double? { guard let subject = subject else { return nil } let hashValue = "\(feature.identifier).\(subject.identifier)".hashValue @@ -35,7 +35,7 @@ class WeightedFeatureSelector: FeatureSelector { // MARK: - Private - private func normalize(value: Int) -> Double { + fileprivate func normalize(_ value: Int) -> Double { return Double(value) / Double(Int.max) } } @@ -55,12 +55,12 @@ class FixedFeatureSelector: FeatureSelector { // MARK: - func select(feature: Feature, subject: FeatureSubject?) -> Double? { + func select(_ feature: Feature, subject: FeatureSubject?) -> Double? { return weight } // MARK: - Private - private let weight: Double + fileprivate let weight: Double } diff --git a/Horatio/Features/FeatureSubject.swift b/Horatio/Features/FeatureSubject.swift index 8f10d5b..864eda2 100644 --- a/Horatio/Features/FeatureSubject.swift +++ b/Horatio/Features/FeatureSubject.swift @@ -34,7 +34,7 @@ class RandomFeatureSubject: FeatureSubject { // MARK: - Private - private static func generateRandomIdentifier(length: Int) -> String { + fileprivate static func generateRandomIdentifier(_ length: Int) -> String { let allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" let count = UInt32(allowed.characters.count) @@ -43,7 +43,7 @@ class RandomFeatureSubject: FeatureSubject { for _ in (0 ..< length) { let random = Int(arc4random_uniform(count)) - let c = allowed[allowed.startIndex.advancedBy(random)] + let c = allowed[allowed.characters.index(allowed.startIndex, offsetBy: random)] identifier += String(c) } diff --git a/Horatio/Features/VendorIDFeatureSubject.swift b/Horatio/Features/VendorIDFeatureSubject.swift index 043de85..ddbb216 100644 --- a/Horatio/Features/VendorIDFeatureSubject.swift +++ b/Horatio/Features/VendorIDFeatureSubject.swift @@ -16,6 +16,6 @@ class VendorIDFeatureSubject: FeatureSubject { // MARK: - Initialization init() { - self.identifier = UIDevice.currentDevice().identifierForVendor?.UUIDString ?? "" + self.identifier = UIDevice.current.identifierForVendor?.uuidString ?? "" } } diff --git a/Horatio/JSON/JSONParsing.swift b/Horatio/JSON/JSONParsing.swift index e5dde3b..880aad1 100644 --- a/Horatio/JSON/JSONParsing.swift +++ b/Horatio/JSON/JSONParsing.swift @@ -9,7 +9,7 @@ public typealias JSONObject = [String : AnyObject] /// Options for parsing and validating JSON using the `JSONParser` class. -public struct JSONParsingOptions: OptionSetType { +public struct JSONParsingOptions: OptionSet { public let rawValue: Int /// No options set. @@ -31,23 +31,23 @@ public struct JSONParsingOptions: OptionSetType { Normalizes values from JSON objects, with options for allowing for conversion from unexpected value types and missing values. */ -public class JSONParser { - public static func parseIdentifier(value: AnyObject?, options: JSONParsingOptions = .none) -> String? { +open class JSONParser { + open static func parseIdentifier(_ value: AnyObject?, options: JSONParsingOptions = .none) -> String? { if let stringValue = JSONParser.parseString(value) { - return stringValue.lowercaseString + return stringValue.lowercased() } return nil } - public static func parseString(value: AnyObject?, options: JSONParsingOptions = .none) -> String? { + open static func parseString(_ value: AnyObject?, options: JSONParsingOptions = .none) -> String? { if let stringValue = value as? String { return stringValue.stringByDecodingJavascriptEntities() } if options.contains(.allowConversion) { if let numberValue = value as? NSNumber { - return String(numberValue) + return String(describing: numberValue) } } @@ -58,7 +58,7 @@ public class JSONParser { return nil } - public static func parseInt(value: AnyObject?, options: JSONParsingOptions = .none) -> Int? { + open static func parseInt(_ value: AnyObject?, options: JSONParsingOptions = .none) -> Int? { if let intValue = value as? Int { return intValue } @@ -80,7 +80,7 @@ public class JSONParser { return nil } - public static func parseDouble(value: AnyObject?, options: JSONParsingOptions = .none) -> Double? { + open static func parseDouble(_ value: AnyObject?, options: JSONParsingOptions = .none) -> Double? { if let doubleValue = value as? Double { return doubleValue } @@ -102,7 +102,7 @@ public class JSONParser { return nil } - public static func parseBool(value: AnyObject?, options: JSONParsingOptions = .none) -> Bool? { + open static func parseBool(_ value: AnyObject?, options: JSONParsingOptions = .none) -> Bool? { if let boolValue = value as? Bool { return boolValue } @@ -113,7 +113,7 @@ public class JSONParser { } if let stringValue = value as? String { - if stringValue.lowercaseString == "true" || stringValue == "1" { + if stringValue.lowercased() == "true" || stringValue == "1" { return true } @@ -128,7 +128,7 @@ public class JSONParser { return nil } - public static func parseArray(value: AnyObject?, options: JSONParsingOptions = .none) -> [AnyObject]? { + open static func parseArray(_ value: AnyObject?, options: JSONParsingOptions = .none) -> [AnyObject]? { if let arrayValue = value as? [AnyObject] { return arrayValue } @@ -152,7 +152,7 @@ public class JSONParser { return nil } - public static func parseObject(value: AnyObject?, options: JSONParsingOptions = .none) -> JSONObject? { + open static func parseObject(_ value: AnyObject?, options: JSONParsingOptions = .none) -> JSONObject? { if let objectValue = value as? [String : AnyObject] { return objectValue } @@ -172,15 +172,15 @@ public class JSONParser { return nil } - public static func parseISO8601Date(value: AnyObject?, options: JSONParsingOptions = .none) -> NSDate? { + open static func parseISO8601Date(_ value: AnyObject?, options: JSONParsingOptions = .none) -> Date? { if let dateString = JSONParser.parseString(value, options: options) { - if let dateValue = NSDate.dateFromISO8601String(dateString) { + if let dateValue = Date.dateFromISO8601String(dateString) { return dateValue } } if options.contains(.allowEmpty) { - return NSDate() + return Date() } return nil @@ -188,22 +188,22 @@ public class JSONParser { } public protocol JSONParsing { - func updateFromJSONRepresentation(data: JSONObject) + func updateFromJSONRepresentation(_ data: JSONObject) - static func isValidJSONRepresentation (data: JSONObject) -> Bool + static func isValidJSONRepresentation (_ data: JSONObject) -> Bool } extension String { func stringByDecodingJavascriptEntities() -> String { - func decodeHexValue(string: String, base: Int32) -> Character? { + func decodeHexValue(_ string: String, base: Int32) -> Character? { let code = UInt32(strtoul(string, nil, base)) - return Character(UnicodeScalar(code)) + return Character(UnicodeScalar(code)!) } - func decodeEntity(entity: String) -> Character? { + func decodeEntity(_ entity: String) -> Character? { if entity.hasPrefix("\\x") || entity.hasPrefix("\\u") { - return decodeHexValue(entity.substringFromIndex(entity.startIndex.advancedBy(2)), base: 16) + return decodeHexValue(entity.substring(from: entity.characters.index(entity.startIndex, offsetBy: 2)), base: 16) } return nil @@ -215,17 +215,17 @@ extension String { let entityBeacons = ["\\x", "\\u"] for beacon in entityBeacons { - while let entityRange = self.rangeOfString(beacon, range: position ..< endIndex) { - result += self[position ..< entityRange.startIndex] - position = entityRange.startIndex + while let entityRange = self.range(of: beacon, range: position ..< endIndex) { + result += self[position ..< entityRange.lowerBound] + position = entityRange.lowerBound let entityLength = (beacon == "\\u") ? 4 : 2 - let entity = self[position ..< position.advancedBy(entityLength)] + let entity = self[position ..< self.characters.index(position, offsetBy: entityLength)] if let decodedEntity = decodeEntity(entity) { result.append(decodedEntity) } else { - result.appendContentsOf(entity) + result.append(entity) } } } @@ -237,22 +237,22 @@ extension String { } -extension NSDate { +extension Date { struct ISO8601Support { - static let formatter: NSDateFormatter = { - let formatter = NSDateFormatter() - formatter.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierISO8601) - formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") - formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0) + static let formatter: DateFormatter = { + let formatter = DateFormatter() + formatter.calendar = Calendar(identifier: Calendar.Identifier.iso8601) + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.timeZone = TimeZone(secondsFromGMT: 0) formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ" return formatter }() } - public static func dateFromISO8601String(string: String) -> NSDate? { - return ISO8601Support.formatter.dateFromString(string) + public static func dateFromISO8601String(_ string: String) -> Date? { + return ISO8601Support.formatter.date(from: string) } - public var iso8601String: String { return ISO8601Support.formatter.stringFromDate(self) } + public var iso8601String: String { return ISO8601Support.formatter.string(from: self) } } diff --git a/Horatio/JSON/JSONServiceRequest.swift b/Horatio/JSON/JSONServiceRequest.swift index 87fe6a2..12f1a90 100644 --- a/Horatio/JSON/JSONServiceRequest.swift +++ b/Horatio/JSON/JSONServiceRequest.swift @@ -6,7 +6,7 @@ import Foundation -public class JSONBodyServiceRequestConfigurator: ServiceRequestConfigurator { +open class JSONBodyServiceRequestConfigurator: ServiceRequestConfigurator { let parameters: JSONObject public init(parameters: JSONObject) { @@ -15,11 +15,11 @@ public class JSONBodyServiceRequestConfigurator: ServiceRequestConfigurator { // MARK: - public func endpointPathTransformers(serviceRequest: ServiceRequest) -> [ServiceEndpointPathTransformer] { + open func endpointPathTransformers(_ serviceRequest: ServiceRequest) -> [ServiceEndpointPathTransformer] { return [ServiceEndpointPathTransformer]() } - public func urlRequestDecorators(serviceRequest: ServiceRequest) -> [ServiceRequestDecorator] { + open func urlRequestDecorators(_ serviceRequest: ServiceRequest) -> [ServiceRequestDecorator] { var decorators = [ServiceRequestDecorator]() decorators.append(JSONHeadersServiceRequestDecorator()) @@ -35,7 +35,7 @@ public class JSONBodyServiceRequestConfigurator: ServiceRequestConfigurator { /** Adds HTTP headers indicating the response is expected (and allowed) to be in JSON format. */ -public class JSONHeadersServiceRequestDecorator: ServiceRequestDecorator { +open class JSONHeadersServiceRequestDecorator: ServiceRequestDecorator { public init() { } @@ -45,7 +45,7 @@ public class JSONHeadersServiceRequestDecorator: ServiceRequestDecorator { // MARK: - public func compose(urlRequest: NSMutableURLRequest) { + open func compose(_ urlRequest: NSMutableURLRequest) { urlRequest.setValue("application/json, text/javascript, */*; q=0.01", forHTTPHeaderField:"Accept") urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") } @@ -55,7 +55,7 @@ public class JSONHeadersServiceRequestDecorator: ServiceRequestDecorator { /** Applies its parameters in a JSON object in the body of the HTTP request. */ -public class JSONBodyParametersServiceRequestDecorator: ServiceRequestDecorator { +open class JSONBodyParametersServiceRequestDecorator: ServiceRequestDecorator { // MARK: - Properties let parameters: JSONObject @@ -72,10 +72,10 @@ public class JSONBodyParametersServiceRequestDecorator: ServiceRequestDecorator // MARK: - public func compose(urlRequest: NSMutableURLRequest) { + open func compose(_ urlRequest: NSMutableURLRequest) { do { - let data = try NSJSONSerialization.dataWithJSONObject(parameters, options: .PrettyPrinted) - urlRequest.HTTPBody = data + let data = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) + urlRequest.httpBody = data } catch { } } } diff --git a/Horatio/JSON/JSONServiceResponseProcessor.swift b/Horatio/JSON/JSONServiceResponseProcessor.swift index 75e8278..4971df6 100644 --- a/Horatio/JSON/JSONServiceResponseProcessor.swift +++ b/Horatio/JSON/JSONServiceResponseProcessor.swift @@ -9,19 +9,19 @@ import Foundation Processes JSON data in some way — transforming, storing, or otherwise manipulating the data. */ public protocol JSONProcessor { - func processJSONData(request: ServiceRequest, jsonData: JSONObject, completionBlock: (errors: [NSError]?) -> Void) - func processJSONData(request: ServiceRequest, jsonData: [JSONObject], completionBlock: (errors: [NSError]?) -> Void) + func processJSONData(_ request: ServiceRequest, jsonData: JSONObject, completionBlock: (_ errors: [NSError]?) -> Void) + func processJSONData(_ request: ServiceRequest, jsonData: [JSONObject], completionBlock: (_ errors: [NSError]?) -> Void) } extension JSONProcessor { - func processJSONData(request: ServiceRequest, jsonData: JSONObject, completionBlock: (errors: [NSError]?) -> Void) { - completionBlock(errors: nil) + func processJSONData(_ request: ServiceRequest, jsonData: JSONObject, completionBlock: (_ errors: [NSError]?) -> Void) { + completionBlock(nil) } - func processJSONData(request: ServiceRequest, jsonData: [JSONObject], completionBlock: (errors: [NSError]?) -> Void) { - completionBlock(errors: nil) + func processJSONData(_ request: ServiceRequest, jsonData: [JSONObject], completionBlock: (_ errors: [NSError]?) -> Void) { + completionBlock(nil) } } @@ -31,7 +31,7 @@ extension JSONProcessor { A JSON processor takes a specialized processor for parsing JSON (typically, parsing the JSON into objects and storing those in a local store). */ -public class JSONServiceResponseProcessor: ServiceResponseProcessor { +open class JSONServiceResponseProcessor: ServiceResponseProcessor { // MARK: - Properties let jsonProcessor: JSONProcessor @@ -49,16 +49,16 @@ public class JSONServiceResponseProcessor: ServiceResponseProcessor { // MARK: - public func process(request: ServiceRequest, input: ServiceResponseProcessorParam, completionBlock: (ServiceResponseProcessorParam) -> Void) { - var jsonData: AnyObject? = nil + open func process(_ request: ServiceRequest, input: ServiceResponseProcessorParam, completionBlock: (ServiceResponseProcessorParam) -> Void) { + var jsonData: Any? = nil do { switch input { case .stream(let inputStream): - jsonData = try NSJSONSerialization.JSONObjectWithStream(inputStream, options: .AllowFragments) + jsonData = try JSONSerialization.jsonObject(with: inputStream, options: .allowFragments) case .data(_, let inputData): - jsonData = try NSJSONSerialization.JSONObjectWithData(inputData, options: .AllowFragments) + jsonData = try JSONSerialization.jsonObject(with: inputData, options: .allowFragments) default: completionBlock(input) @@ -80,7 +80,7 @@ public class JSONServiceResponseProcessor: ServiceResponseProcessor { // MARK: - Private - private func processObject(request: ServiceRequest, jsonObject: JSONObject, completionBlock: (ServiceResponseProcessorParam) -> Void) { + fileprivate func processObject(_ request: ServiceRequest, jsonObject: JSONObject, completionBlock: (ServiceResponseProcessorParam) -> Void) { jsonProcessor.processJSONData(request, jsonData: jsonObject, completionBlock: { (errors: [NSError]?) in if let error = errors?.first { @@ -93,7 +93,7 @@ public class JSONServiceResponseProcessor: ServiceResponseProcessor { } - private func processArray(request: ServiceRequest, jsonArray: [JSONObject], completionBlock: (ServiceResponseProcessorParam) -> Void) { + fileprivate func processArray(_ request: ServiceRequest, jsonArray: [JSONObject], completionBlock: (ServiceResponseProcessorParam) -> Void) { jsonProcessor.processJSONData(request, jsonData: jsonArray, completionBlock: { (errors: [NSError]?) in if let error = errors?.first { completionBlock(.error(error)) diff --git a/Horatio/Operations/AlertOperation.swift b/Horatio/Operations/AlertOperation.swift index 5081fcb..5442b46 100644 --- a/Horatio/Operations/AlertOperation.swift +++ b/Horatio/Operations/AlertOperation.swift @@ -11,8 +11,8 @@ import UIKit class AlertOperation: Operation { // MARK: Properties - private let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .Alert) - private let presentationContext: UIViewController? + fileprivate let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .alert) + fileprivate let presentationContext: UIViewController? var title: String? { get { @@ -38,7 +38,7 @@ class AlertOperation: Operation { // MARK: Initialization init(presentationContext: UIViewController? = nil) { - self.presentationContext = presentationContext ?? UIApplication.sharedApplication().keyWindow?.rootViewController + self.presentationContext = presentationContext ?? UIApplication.shared.keyWindow?.rootViewController super.init() @@ -52,7 +52,7 @@ class AlertOperation: Operation { addCondition(MutuallyExclusive()) } - func addAction(title: String, style: UIAlertActionStyle = .Default, handler: AlertOperation -> Void = { _ in }) { + func addAction(_ title: String, style: UIAlertActionStyle = .default, handler: @escaping (AlertOperation) -> Void = { _ in }) { let action = UIAlertAction(title: title, style: style) { [weak self] _ in if let strongSelf = self { handler(strongSelf) @@ -71,12 +71,12 @@ class AlertOperation: Operation { return } - dispatch_async(dispatch_get_main_queue()) { + DispatchQueue.main.async { if self.alertController.actions.isEmpty { self.addAction("OK") } - presentationContext.presentViewController(self.alertController, animated: true, completion: nil) + presentationContext.present(self.alertController, animated: true, completion: nil) } } } diff --git a/Horatio/Operations/BlockObserver.swift b/Horatio/Operations/BlockObserver.swift index 7c4ee81..c557fcc 100644 --- a/Horatio/Operations/BlockObserver.swift +++ b/Horatio/Operations/BlockObserver.swift @@ -15,11 +15,11 @@ import Foundation public struct BlockObserver: OperationObserver { // MARK: Properties - private let startHandler: (Operation -> Void)? - private let produceHandler: ((Operation, NSOperation) -> Void)? - private let finishHandler: ((Operation, [NSError]) -> Void)? + fileprivate let startHandler: ((Operation) -> Void)? + fileprivate let produceHandler: ((Operation, Foundation.Operation) -> Void)? + fileprivate let finishHandler: ((Operation, [NSError]) -> Void)? - public init(startHandler: (Operation -> Void)? = nil, produceHandler: ((Operation, NSOperation) -> Void)? = nil, finishHandler: ((Operation, [NSError]) -> Void)? = nil) { + public init(startHandler: ((Operation) -> Void)? = nil, produceHandler: ((Operation, Foundation.Operation) -> Void)? = nil, finishHandler: ((Operation, [NSError]) -> Void)? = nil) { self.startHandler = startHandler self.produceHandler = produceHandler self.finishHandler = finishHandler @@ -27,15 +27,15 @@ public struct BlockObserver: OperationObserver { // MARK: OperationObserver - public func operationDidStart(operation: Operation) { + public func operationDidStart(_ operation: Operation) { startHandler?(operation) } - public func operation(operation: Operation, didProduceOperation newOperation: NSOperation) { + public func operation(_ operation: Operation, didProduceOperation newOperation: Foundation.Operation) { produceHandler?(operation, newOperation) } - public func operationDidFinish(operation: Operation, errors: [NSError]) { + public func operationDidFinish(_ operation: Operation, errors: [NSError]) { finishHandler?(operation, errors) } } diff --git a/Horatio/Operations/BlockOperation.swift b/Horatio/Operations/BlockOperation.swift index ad29b7c..33af978 100644 --- a/Horatio/Operations/BlockOperation.swift +++ b/Horatio/Operations/BlockOperation.swift @@ -9,11 +9,13 @@ This code shows how to create a simple subclass of Operation. import Foundation /// A closure type that takes a closure as its parameter. -public typealias OperationBlock = (Void -> Void) -> Void +public typealias ContinuationBlockType = (_ error: Error?) -> Void +public typealias BlockType = (_ continueWithError: @escaping ContinuationBlockType) -> Void + /// A sublcass of `Operation` to execute a closure. -public class BlockOperation: Operation { - private let block: OperationBlock? +open class BlockOperation: Operation { + fileprivate let block: BlockType /** The designated initializer. @@ -24,9 +26,10 @@ public class BlockOperation: Operation { will never finish executing. If this parameter is `nil`, the operation will immediately finish. */ - public init(block: OperationBlock? = nil) { + public init(block: @escaping BlockType = { continuation in continuation(nil) }) { self.block = block super.init() + name = "Block Operation" } /** @@ -37,23 +40,18 @@ public class BlockOperation: Operation { the designated initializer). The operation will be automatically ended after the `mainQueueBlock` is executed. */ - convenience public init(mainQueueBlock: dispatch_block_t) { + public convenience init(mainQueueBlock: @escaping ()->()) { self.init(block: { continuation in - dispatch_async(dispatch_get_main_queue()) { + DispatchQueue.main.async { mainQueueBlock() - continuation() + continuation(nil) } }) } - override public func execute() { - guard let block = block else { - finish() - return - } - - block { - self.finish() + open override func execute() { + if !isCancelled { + block { error in self.finish([error as! NSError]) } } } } diff --git a/Horatio/Operations/CKContainer+Operations.swift b/Horatio/Operations/CKContainer+Operations.swift index cba3187..44be018 100644 --- a/Horatio/Operations/CKContainer+Operations.swift +++ b/Horatio/Operations/CKContainer+Operations.swift @@ -24,7 +24,7 @@ extension CKContainer { operation fails. If the verification was successful, this value will be `nil`. */ - func verifyPermission(permission: CKApplicationPermissions, requestingIfNecessary shouldRequest: Bool = false, completion: NSError? -> Void) { + func verifyPermission(_ permission: CKApplicationPermissions, requestingIfNecessary shouldRequest: Bool = false, completion: @escaping (NSError?) -> Void) { verifyAccountStatus(self, permission: permission, shouldRequest: shouldRequest, completion: completion) } } @@ -33,39 +33,39 @@ extension CKContainer { Make these helper functions instead of helper methods, so we don't pollute `CKContainer`. */ -private func verifyAccountStatus(container: CKContainer, permission: CKApplicationPermissions, shouldRequest: Bool, completion: NSError? -> Void) { - container.accountStatusWithCompletionHandler { accountStatus, accountError in - if accountStatus == .Available { +private func verifyAccountStatus(_ container: CKContainer, permission: CKApplicationPermissions, shouldRequest: Bool, completion: @escaping (NSError?) -> Void) { + container.accountStatus { accountStatus, accountError in + if accountStatus == .available { if permission != [] { verifyPermission(container, permission: permission, shouldRequest: shouldRequest, completion: completion) } else { completion(nil) } } else { - completion(accountError) + completion(accountError as NSError?) } } } -private func verifyPermission(container: CKContainer, permission: CKApplicationPermissions, shouldRequest: Bool, completion: NSError? -> Void) { - container.statusForApplicationPermission(permission) { permissionStatus, permissionError in - if permissionStatus == .Granted { +private func verifyPermission(_ container: CKContainer, permission: CKApplicationPermissions, shouldRequest: Bool, completion: @escaping (NSError?) -> Void) { + container.status(forApplicationPermission: permission) { permissionStatus, permissionError in + if permissionStatus == .granted { completion(nil) - } else if permissionStatus == .InitialState && shouldRequest { + } else if permissionStatus == .initialState && shouldRequest { requestPermission(container, permission: permission, completion: completion) } else { - completion(permissionError) + completion(permissionError as NSError?) } } } -private func requestPermission(container: CKContainer, permission: CKApplicationPermissions, completion: NSError? -> Void) { - dispatch_async(dispatch_get_main_queue()) { +private func requestPermission(_ container: CKContainer, permission: CKApplicationPermissions, completion: @escaping (NSError?) -> Void) { + DispatchQueue.main.async { container.requestApplicationPermission(permission) { requestStatus, requestError in - if requestStatus == .Granted { + if requestStatus == .granted { completion(nil) } else { - completion(requestError) + completion(requestError as NSError?) } } } diff --git a/Horatio/Operations/CalendarCondition.swift b/Horatio/Operations/CalendarCondition.swift index fc25aed..291cf81 100644 --- a/Horatio/Operations/CalendarCondition.swift +++ b/Horatio/Operations/CalendarCondition.swift @@ -21,23 +21,23 @@ public struct CalendarCondition: OperationCondition { self.entityType = entityType } - public func dependencyForOperation(operation: Operation) -> NSOperation? { + public func dependencyForOperation(_ operation: Operation) -> Foundation.Operation? { return CalendarPermissionOperation(entityType: entityType) } - public func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) { - switch EKEventStore.authorizationStatusForEntityType(entityType) { - case .Authorized: - completion(.Satisfied) + public func evaluateForOperation(_ operation: Operation, completion: @escaping (OperationConditionResult) -> Void) { + switch EKEventStore.authorizationStatus(for: entityType) { + case .authorized: + completion(.satisfied) default: // We are not authorized to access entities of this type. - let error = NSError(code: .ConditionFailed, userInfo: [ - OperationConditionKey: self.dynamicType.name, - self.dynamicType.entityTypeKey: entityType.rawValue + let error = NSError(code: .conditionFailed, userInfo: [ + OperationConditionKey: type(of: self).name, + type(of: self).entityTypeKey: entityType.rawValue ]) - completion(.Failed(error)) + completion(.failed(error)) } } } @@ -57,12 +57,12 @@ private class CalendarPermissionOperation: Operation { } override func execute() { - let status = EKEventStore.authorizationStatusForEntityType(entityType) + let status = EKEventStore.authorizationStatus(for: entityType) switch status { - case .NotDetermined: - dispatch_async(dispatch_get_main_queue()) { - self.store.requestAccessToEntityType(self.entityType) { granted, error in + case .notDetermined: + DispatchQueue.main.async { + self.store.requestAccess(to: self.entityType) { granted, error in self.finish() } } diff --git a/Horatio/Operations/CloudCondition.swift b/Horatio/Operations/CloudCondition.swift index 50a5a0b..429df06 100644 --- a/Horatio/Operations/CloudCondition.swift +++ b/Horatio/Operations/CloudCondition.swift @@ -36,22 +36,22 @@ struct CloudContainerCondition: OperationCondition { self.permission = permission } - func dependencyForOperation(operation: Operation) -> NSOperation? { + func dependencyForOperation(_ operation: Operation) -> Foundation.Operation? { return CloudKitPermissionOperation(container: container, permission: permission) } - func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) { + func evaluateForOperation(_ operation: Operation, completion: @escaping (OperationConditionResult) -> Void) { container.verifyPermission(permission, requestingIfNecessary: false) { error in if let error = error { - let conditionError = NSError(code: .ConditionFailed, userInfo: [ - OperationConditionKey: self.dynamicType.name, - self.dynamicType.containerKey: self.container, + let conditionError = NSError(code: .conditionFailed, userInfo: [ + OperationConditionKey: type(of: self).name, + type(of: self).containerKey: self.container, NSUnderlyingErrorKey: error ]) - completion(.Failed(conditionError)) + completion(.failed(conditionError)) } else { - completion(.Satisfied) + completion(.satisfied) } } } diff --git a/Horatio/Operations/DelayOperation.swift b/Horatio/Operations/DelayOperation.swift index 0b262f6..b1547a4 100644 --- a/Horatio/Operations/DelayOperation.swift +++ b/Horatio/Operations/DelayOperation.swift @@ -20,39 +20,39 @@ import Foundation If the interval is negative, or the `NSDate` is in the past, then this operation immediately finishes. */ -public class DelayOperation: Operation { +open class DelayOperation: Operation { // MARK: Types - private enum Delay { - case Interval(NSTimeInterval) - case Date(NSDate) + fileprivate enum Delay { + case interval(TimeInterval) + case date(Foundation.Date) } // MARK: Properties - private let delay: Delay + fileprivate let delay: Delay // MARK: Initialization - public init(interval: NSTimeInterval) { - delay = .Interval(interval) + public init(interval: TimeInterval) { + delay = .interval(interval) super.init() } - public init(until date: NSDate) { - delay = .Date(date) + public init(until date: Date) { + delay = .date(date) super.init() } - override public func execute() { - let interval: NSTimeInterval + override open func execute() { + let interval: TimeInterval // Figure out how long we should wait for. switch delay { - case .Interval(let theInterval): + case .interval(let theInterval): interval = theInterval - case .Date(let date): + case .date(let date): interval = date.timeIntervalSinceNow } @@ -61,16 +61,16 @@ public class DelayOperation: Operation { return } - let when = dispatch_time(DISPATCH_TIME_NOW, Int64(interval * Double(NSEC_PER_SEC))) - dispatch_after(when, dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) { + let when = DispatchTime.now() + Double(Int64(interval * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) + DispatchQueue.global(qos: DispatchQoS.QoSClass.default).asyncAfter(deadline: when) { // If we were cancelled, then finish() has already been called. - if !self.cancelled { + if !self.isCancelled { self.finish() } } } - override public func cancel() { + override open func cancel() { super.cancel() // Cancelling the operation means we don't want to wait anymore. self.finish() diff --git a/Horatio/Operations/Dictionary+Operations.swift b/Horatio/Operations/Dictionary+Operations.swift index 9d9c930..24ef2d7 100644 --- a/Horatio/Operations/Dictionary+Operations.swift +++ b/Horatio/Operations/Dictionary+Operations.swift @@ -19,7 +19,7 @@ extension Dictionary { be used as the key for the value in the `Dictionary`. If the closure returns `nil`, then the value will be omitted from the `Dictionary`. */ - init(sequence: Sequence, keyMapper: Value -> Key?) { + init(sequence: Sequence, keyMapper: (Value) -> Key?) where Sequence.Iterator.Element == Value { self.init() for item in sequence { diff --git a/Horatio/Operations/ExclusivityController.swift b/Horatio/Operations/ExclusivityController.swift index ca90301..9583cca 100644 --- a/Horatio/Operations/ExclusivityController.swift +++ b/Horatio/Operations/ExclusivityController.swift @@ -14,13 +14,13 @@ import Foundation We use a singleton because mutual exclusivity must be enforced across the entire app, regardless of the `OperationQueue` on which an `Operation` was executed. */ -public class ExclusivityController { +open class ExclusivityController { static let sharedExclusivityController = ExclusivityController() - private let serialQueue = dispatch_queue_create("Operations.ExclusivityController", DISPATCH_QUEUE_SERIAL) - private var operations: [String: [Operation]] = [:] + fileprivate let serialQueue = DispatchQueue(label: "Operations.ExclusivityController", attributes: []) + fileprivate var operations: [String: [Operation]] = [:] - private init() { + fileprivate init() { /* A private initializer effectively prevents any other part of the app from accidentally creating an instance. @@ -28,13 +28,13 @@ public class ExclusivityController { } /// Registers an operation as being mutually exclusive - public func addOperation(operation: Operation, categories: [String]) { + open func addOperation(_ operation: Operation, categories: [String]) { /* This needs to be a synchronous operation. If this were async, then we might not get around to adding dependencies until after the operation had already begun, which would be incorrect. */ - dispatch_sync(serialQueue) { + serialQueue.sync { for category in categories { self.noqueue_addOperation(operation, category: category) } @@ -42,8 +42,8 @@ public class ExclusivityController { } /// Unregisters an operation from being mutually exclusive. - public func removeOperation(operation: Operation, categories: [String]) { - dispatch_async(serialQueue) { + open func removeOperation(_ operation: Operation, categories: [String]) { + serialQueue.async { for category in categories { self.noqueue_removeOperation(operation, category: category) } @@ -53,7 +53,7 @@ public class ExclusivityController { // MARK: Operation Management - private func noqueue_addOperation(operation: Operation, category: String) { + fileprivate func noqueue_addOperation(_ operation: Operation, category: String) { var operationsWithThisCategory = operations[category] ?? [] if let last = operationsWithThisCategory.last { @@ -65,13 +65,13 @@ public class ExclusivityController { operations[category] = operationsWithThisCategory } - private func noqueue_removeOperation(operation: Operation, category: String) { + fileprivate func noqueue_removeOperation(_ operation: Operation, category: String) { let matchingOperations = operations[category] guard var operationsWithThisCategory = matchingOperations else { return } - if let index = operationsWithThisCategory.indexOf(operation) { - operationsWithThisCategory.removeAtIndex(index) + if let index = operationsWithThisCategory.index(of: operation) { + operationsWithThisCategory.remove(at: index) operations[category] = operationsWithThisCategory } } diff --git a/Horatio/Operations/GroupOperation.swift b/Horatio/Operations/GroupOperation.swift index 1abb3fa..cb42c79 100644 --- a/Horatio/Operations/GroupOperation.swift +++ b/Horatio/Operations/GroupOperation.swift @@ -21,20 +21,20 @@ import Foundation subsequent operations (still within the outer `GroupOperation`) that will all be executed before the rest of the operations in the initial chain of operations. */ -public class GroupOperation: Operation { - private let internalQueue = OperationQueue() - private let finishingOperation = NSBlockOperation(block: {}) +open class GroupOperation: Operation { + fileprivate let internalQueue = OperationQueue() + fileprivate let finishingOperation = Foundation.BlockOperation(block: {}) - private var aggregatedErrors = [NSError]() + fileprivate var aggregatedErrors = [NSError]() - public convenience init(operations: NSOperation...) { + public convenience init(operations: Foundation.Operation...) { self.init(operations: operations) } - public init(operations: [NSOperation]) { + public init(operations: [Foundation.Operation]) { super.init() - internalQueue.suspended = true + internalQueue.isSuspended = true internalQueue.delegate = self @@ -43,17 +43,17 @@ public class GroupOperation: Operation { } } - override public func cancel() { + override open func cancel() { internalQueue.cancelAllOperations() super.cancel() } - override public func execute() { - internalQueue.suspended = false + override open func execute() { + internalQueue.isSuspended = false internalQueue.addOperation(finishingOperation) } - public func addOperation(operation: NSOperation) { + open func addOperation(_ operation: Foundation.Operation) { internalQueue.addOperation(operation) } @@ -62,18 +62,18 @@ public class GroupOperation: Operation { Errors aggregated through this method will be included in the final array of errors reported to observers and to the `finished(_:)` method. */ - final public func aggregateError(error: NSError) { + final public func aggregateError(_ error: NSError) { aggregatedErrors.append(error) } - public func operationDidFinish(operation: NSOperation, withErrors errors: [NSError]) { + open func operationDidFinish(_ operation: Foundation.Operation, withErrors errors: [NSError]) { // For use by subclassers. } } extension GroupOperation: OperationQueueDelegate { - final public func operationQueue(operationQueue: OperationQueue, willAddOperation operation: NSOperation) { - assert(!finishingOperation.finished && !finishingOperation.executing, "cannot add new operations to a group after the group has completed") + final public func operationQueue(_ operationQueue: OperationQueue, willAddOperation operation: Foundation.Operation) { + assert(!finishingOperation.isFinished && !finishingOperation.isExecuting, "cannot add new operations to a group after the group has completed") /* Some operation in this group has produced a new operation to execute. @@ -85,11 +85,11 @@ extension GroupOperation: OperationQueueDelegate { } } - final public func operationQueue(operationQueue: OperationQueue, operationDidFinish operation: NSOperation, withErrors errors: [NSError]) { - aggregatedErrors.appendContentsOf(errors) + final public func operationQueue(_ operationQueue: OperationQueue, operationDidFinish operation: Foundation.Operation, withErrors errors: [NSError]) { + aggregatedErrors.append(contentsOf: errors) if operation === finishingOperation { - internalQueue.suspended = true + internalQueue.isSuspended = true finish(aggregatedErrors) } else { operationDidFinish(operation, withErrors: errors) diff --git a/Horatio/Operations/HealthCondition.swift b/Horatio/Operations/HealthCondition.swift index 7bb0a4b..f3325d3 100644 --- a/Horatio/Operations/HealthCondition.swift +++ b/Horatio/Operations/HealthCondition.swift @@ -38,7 +38,7 @@ struct HealthCondition: OperationCondition { readTypes = typesToRead } - func dependencyForOperation(operation: Operation) -> NSOperation? { + func dependencyForOperation(_ operation: Operation) -> Foundation.Operation? { guard HKHealthStore.isHealthDataAvailable() else { return nil } @@ -50,7 +50,7 @@ struct HealthCondition: OperationCondition { return HealthPermissionOperation(shareTypes: shareTypes, readTypes: readTypes) } - func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) { + func evaluateForOperation(_ operation: Operation, completion: @escaping (OperationConditionResult) -> Void) { guard HKHealthStore.isHealthDataAvailable() else { failed(shareTypes, completion: completion) return @@ -68,25 +68,25 @@ struct HealthCondition: OperationCondition { write data to HealthKit. */ let unauthorizedShareTypes = shareTypes.filter { shareType in - return store.authorizationStatusForType(shareType) != .SharingAuthorized + return store.authorizationStatus(for: shareType) != .sharingAuthorized } if !unauthorizedShareTypes.isEmpty { failed(Set(unauthorizedShareTypes), completion: completion) } else { - completion(.Satisfied) + completion(.satisfied) } } // Break this out in to its own method so we don't clutter up the evaluate... method. - private func failed(unauthorizedShareTypes: Set, completion: OperationConditionResult -> Void) { - let error = NSError(code: .ConditionFailed, userInfo: [ - OperationConditionKey: self.dynamicType.name, - self.dynamicType.healthDataAvailable: HKHealthStore.isHealthDataAvailable(), - self.dynamicType.unauthorizedShareTypesKey: unauthorizedShareTypes + fileprivate func failed(_ unauthorizedShareTypes: Set, completion: (OperationConditionResult) -> Void) { + let error = NSError(code: .conditionFailed, userInfo: [ + OperationConditionKey: type(of: self).name, + type(of: self).healthDataAvailable: HKHealthStore.isHealthDataAvailable(), + type(of: self).unauthorizedShareTypesKey: unauthorizedShareTypes ]) - completion(.Failed(error)) + completion(.failed(error)) } } @@ -110,14 +110,14 @@ private class HealthPermissionOperation: Operation { } override func execute() { - dispatch_async(dispatch_get_main_queue()) { + DispatchQueue.main.async { let store = HKHealthStore() /* This method is smart enough to not re-prompt for access if access has already been granted. */ - store.requestAuthorizationToShareTypes(self.shareTypes, readTypes: self.readTypes) { completed, error in + store.requestAuthorization(toShare: self.shareTypes, read: self.readTypes) { completed, error in self.finish() } } diff --git a/Horatio/Operations/LocationCondition.swift b/Horatio/Operations/LocationCondition.swift index ef389fc..9ab19de 100644 --- a/Horatio/Operations/LocationCondition.swift +++ b/Horatio/Operations/LocationCondition.swift @@ -15,8 +15,8 @@ public struct LocationCondition: OperationCondition { enum has more case values than are necessary for our purposes. */ public enum Usage { - case WhenInUse - case Always + case whenInUse + case always } public static let name = "Location" @@ -30,11 +30,11 @@ public struct LocationCondition: OperationCondition { self.usage = usage } - public func dependencyForOperation(operation: Operation) -> NSOperation? { + public func dependencyForOperation(_ operation: Operation) -> Foundation.Operation? { return LocationPermissionOperation(usage: usage) } - public func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) { + public func evaluateForOperation(_ operation: Operation, completion: @escaping (OperationConditionResult) -> Void) { let enabled = CLLocationManager.locationServicesEnabled() let actual = CLLocationManager.authorizationStatus() @@ -42,11 +42,11 @@ public struct LocationCondition: OperationCondition { // There are several factors to consider when evaluating this condition switch (enabled, usage, actual) { - case (true, _, .AuthorizedAlways): + case (true, _, .authorizedAlways): // The service is enabled, and we have "Always" permission -> condition satisfied. break - case (true, .WhenInUse, .AuthorizedWhenInUse): + case (true, .whenInUse, .authorizedWhenInUse): /* The service is enabled, and we have and need "WhenInUse" permission -> condition satisfied. @@ -62,17 +62,17 @@ public struct LocationCondition: OperationCondition { The last case would happen if this condition were wrapped in a `SilentCondition`. */ - error = NSError(code: .ConditionFailed, userInfo: [ - OperationConditionKey: self.dynamicType.name, - self.dynamicType.locationServicesEnabledKey: enabled, - self.dynamicType.authorizationStatusKey: Int(actual.rawValue) + error = NSError(code: .conditionFailed, userInfo: [ + OperationConditionKey: type(of: self).name, + type(of: self).locationServicesEnabledKey: enabled, + type(of: self).authorizationStatusKey: Int(actual.rawValue) ]) } if let error = error { - completion(.Failed(error)) + completion(.failed(error)) } else { - completion(.Satisfied) + completion(.satisfied) } } } @@ -101,8 +101,8 @@ private class LocationPermissionOperation: Operation { need to handle the "upgrade" (.WhenInUse -> .Always) case. */ switch (CLLocationManager.authorizationStatus(), usage) { - case (.NotDetermined, _), (.AuthorizedWhenInUse, .Always): - dispatch_async(dispatch_get_main_queue()) { + case (.notDetermined, _), (.authorizedWhenInUse, .always): + DispatchQueue.main.async { self.requestPermission() } @@ -111,31 +111,31 @@ private class LocationPermissionOperation: Operation { } } - private func requestPermission() { + fileprivate func requestPermission() { manager = CLLocationManager() manager?.delegate = self let key: String switch usage { - case .WhenInUse: + case .whenInUse: key = "NSLocationWhenInUseUsageDescription" manager?.requestWhenInUseAuthorization() - case .Always: + case .always: key = "NSLocationAlwaysUsageDescription" manager?.requestAlwaysAuthorization() } // This is helpful when developing the app. - assert(NSBundle.mainBundle().objectForInfoDictionaryKey(key) != nil, "Requesting location permission requires the \(key) key in your Info.plist") + assert(Bundle.main.object(forInfoDictionaryKey: key) != nil, "Requesting location permission requires the \(key) key in your Info.plist") } } extension LocationPermissionOperation: CLLocationManagerDelegate { - @objc func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) { - if manager == self.manager && executing && status != .NotDetermined { + @objc func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { + if manager == self.manager && isExecuting && status != .notDetermined { finish() } } diff --git a/Horatio/Operations/LocationOperation.swift b/Horatio/Operations/LocationOperation.swift index edc841f..ecc9900 100644 --- a/Horatio/Operations/LocationOperation.swift +++ b/Horatio/Operations/LocationOperation.swift @@ -15,25 +15,25 @@ import CoreLocation prompt for `WhenInUse` location authorization, if the app does not already have it. */ -public class LocationOperation: Operation, CLLocationManagerDelegate { +open class LocationOperation: Operation, CLLocationManagerDelegate { // MARK: Properties - private let accuracy: CLLocationAccuracy - private var manager: CLLocationManager? - private let handler: CLLocation -> Void + fileprivate let accuracy: CLLocationAccuracy + fileprivate var manager: CLLocationManager? + fileprivate let handler: (CLLocation) -> Void // MARK: Initialization - public init(accuracy: CLLocationAccuracy, locationHandler: CLLocation -> Void) { + public init(accuracy: CLLocationAccuracy, locationHandler: @escaping (CLLocation) -> Void) { self.accuracy = accuracy self.handler = locationHandler super.init() - addCondition(LocationCondition(usage: .WhenInUse)) + addCondition(LocationCondition(usage: .whenInUse)) addCondition(MutuallyExclusive()) } - override public func execute() { - dispatch_async(dispatch_get_main_queue()) { + override open func execute() { + DispatchQueue.main.async { /* `CLLocationManager` needs to be created on a thread with an active run loop, so for simplicity we do this on the main queue. @@ -47,30 +47,30 @@ public class LocationOperation: Operation, CLLocationManagerDelegate { } } - override public func cancel() { - dispatch_async(dispatch_get_main_queue()) { + override open func cancel() { + DispatchQueue.main.async { self.stopLocationUpdates() super.cancel() } } - private func stopLocationUpdates() { + fileprivate func stopLocationUpdates() { manager?.stopUpdatingLocation() manager = nil } // MARK: CLLocationManagerDelegate - public func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { - if let location = locations.last where location.horizontalAccuracy <= accuracy { + open func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { + if let location = locations.last , location.horizontalAccuracy <= accuracy { stopLocationUpdates() handler(location) finish() } } - public func locationManager(manager: CLLocationManager, didFailWithError error: NSError) { + open func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { stopLocationUpdates() - finishWithError(error) + finishWithError(error as NSError?) } } diff --git a/Horatio/Operations/MutuallyExclusive.swift b/Horatio/Operations/MutuallyExclusive.swift index 4ee1400..a18fbe6 100644 --- a/Horatio/Operations/MutuallyExclusive.swift +++ b/Horatio/Operations/MutuallyExclusive.swift @@ -20,12 +20,12 @@ public struct MutuallyExclusive: OperationCondition { public init() { } - public func dependencyForOperation(operation: Operation) -> NSOperation? { + public func dependencyForOperation(_ operation: Operation) -> Foundation.Operation? { return nil } - public func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) { - completion(.Satisfied) + public func evaluateForOperation(_ operation: Operation, completion: @escaping (OperationConditionResult) -> Void) { + completion(.satisfied) } } diff --git a/Horatio/Operations/NSLock+Operations.swift b/Horatio/Operations/NSLock+Operations.swift index 53a00cf..d8de622 100644 --- a/Horatio/Operations/NSLock+Operations.swift +++ b/Horatio/Operations/NSLock+Operations.swift @@ -9,7 +9,7 @@ import Foundation extension NSLock { - func withCriticalScope(@noescape block: Void -> T) -> T { + func withCriticalScope(_ block: (Void) -> T) -> T { lock() let value = block() unlock() diff --git a/Horatio/Operations/NSOperation+Operations.swift b/Horatio/Operations/NSOperation+Operations.swift index bd2286f..4381146 100644 --- a/Horatio/Operations/NSOperation+Operations.swift +++ b/Horatio/Operations/NSOperation+Operations.swift @@ -8,12 +8,12 @@ A convenient extension to Foundation.NSOperation. import Foundation -extension NSOperation { +extension Foundation.Operation { /** Add a completion block to be executed after the `NSOperation` enters the "finished" state. */ - func addCompletionBlock(block: Void -> Void) { + func addCompletionBlock(_ block: @escaping (Void) -> Void) { if let existing = completionBlock { /* If we already have a completion block, we construct a new one by @@ -29,7 +29,7 @@ extension NSOperation { } /// Add multiple depdendencies to the operation. - func addDependencies(dependencies: [NSOperation]) { + func addDependencies(_ dependencies: [Foundation.Operation]) { for dependency in dependencies { addDependency(dependency) } diff --git a/Horatio/Operations/NSURL+CacheFiles.swift b/Horatio/Operations/NSURL+CacheFiles.swift index 456d95d..1ef0883 100644 --- a/Horatio/Operations/NSURL+CacheFiles.swift +++ b/Horatio/Operations/NSURL+CacheFiles.swift @@ -6,13 +6,13 @@ import Foundation -extension NSURL { - static func cacheFile(named name: String, searchPathDirectory: NSSearchPathDirectory = .CachesDirectory) -> NSURL { - let cachesDirectory = try! NSFileManager.defaultManager().URLForDirectory(searchPathDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true) +extension URL { + static func cacheFile(named name: String, searchPathDirectory: FileManager.SearchPathDirectory = .cachesDirectory) -> URL { + let cachesDirectory = try! FileManager.default.url(for: searchPathDirectory, in: .userDomainMask, appropriateFor: nil, create: true) // swiftlint:disable:previous force_try - let cacheFileURL = cachesDirectory.URLByAppendingPathComponent(name) + let cacheFileURL = cachesDirectory.appendingPathComponent(name) - return cacheFileURL! + return cacheFileURL } } diff --git a/Horatio/Operations/NegatedCondition.swift b/Horatio/Operations/NegatedCondition.swift index 95fb390..702646d 100644 --- a/Horatio/Operations/NegatedCondition.swift +++ b/Horatio/Operations/NegatedCondition.swift @@ -32,23 +32,23 @@ public struct NegatedCondition: OperationCondition { self.condition = condition } - public func dependencyForOperation(operation: Operation) -> NSOperation? { + public func dependencyForOperation(_ operation: Operation) -> Foundation.Operation? { return condition.dependencyForOperation(operation) } - public func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) { + public func evaluateForOperation(_ operation: Operation, completion: @escaping (OperationConditionResult) -> Void) { condition.evaluateForOperation(operation) { result in if result.error == nil { // If the composed condition failed, then this one succeeded. - completion(.Satisfied) + completion(.satisfied) } else { // If the composed condition succeeded, then this one failed. - let error = NSError(code: .ConditionFailed, userInfo: [ - OperationConditionKey: self.dynamicType.name, - self.dynamicType.negatedConditionKey: self.condition.dynamicType.name + let error = NSError(code: .conditionFailed, userInfo: [ + OperationConditionKey: type(of: self).name, + type(of: self).negatedConditionKey: type(of: self.condition).name ]) - completion(.Failed(error)) + completion(.failed(error)) } } } diff --git a/Horatio/Operations/NetworkObserver.swift b/Horatio/Operations/NetworkObserver.swift index 1f421df..ca77493 100644 --- a/Horatio/Operations/NetworkObserver.swift +++ b/Horatio/Operations/NetworkObserver.swift @@ -20,17 +20,17 @@ public struct NetworkObserver: OperationObserver { // MARK: - public func operationDidStart(operation: Operation) { - dispatch_async(dispatch_get_main_queue()) { + public func operationDidStart(_ operation: Operation) { + DispatchQueue.main.async { // increment the network indicator's "retain count" NetworkIndicatorController.sharedIndicatorController.networkActivityDidStart() } } - public func operation(operation: Operation, didProduceOperation newOperation: NSOperation) { } + public func operation(_ operation: Operation, didProduceOperation newOperation: Foundation.Operation) { } - public func operationDidFinish(operation: Operation, errors: [NSError]) { - dispatch_async(dispatch_get_main_queue()) { + public func operationDidFinish(_ operation: Operation, errors: [NSError]) { + DispatchQueue.main.async { // Decrement the network indicator's "reference count". NetworkIndicatorController.sharedIndicatorController.networkActivityDidEnd() } @@ -44,14 +44,14 @@ private class NetworkIndicatorController { static let sharedIndicatorController = NetworkIndicatorController() - private var activityCount = 0 + fileprivate var activityCount = 0 - private var visibilityTimer: Timer? + fileprivate var visibilityTimer: Timer? // MARK: Methods func networkActivityDidStart() { - assert(NSThread.isMainThread(), "Altering network activity indicator state can only be done on the main thread.") + assert(Thread.isMainThread, "Altering network activity indicator state can only be done on the main thread.") activityCount += 1 @@ -59,14 +59,14 @@ private class NetworkIndicatorController { } func networkActivityDidEnd() { - assert(NSThread.isMainThread(), "Altering network activity indicator state can only be done on the main thread.") + assert(Thread.isMainThread, "Altering network activity indicator state can only be done on the main thread.") activityCount -= 1 updateIndicatorVisibility() } - private func updateIndicatorVisibility() { + fileprivate func updateIndicatorVisibility() { if activityCount > 0 { showIndicator() } else { @@ -81,21 +81,21 @@ private class NetworkIndicatorController { } } - private func showIndicator() { + fileprivate func showIndicator() { visibilityTimer?.cancel() visibilityTimer = nil #if os(iOS) - UIApplication.sharedApplication().networkActivityIndicatorVisible = true + UIApplication.shared.isNetworkActivityIndicatorVisible = true #endif } - private func hideIndicator() { + fileprivate func hideIndicator() { visibilityTimer?.cancel() visibilityTimer = nil #if os(iOS) - UIApplication.sharedApplication().networkActivityIndicatorVisible = false + UIApplication.shared.isNetworkActivityIndicatorVisible = false #endif } } @@ -104,14 +104,14 @@ private class NetworkIndicatorController { class Timer { // MARK: Properties - private var isCancelled = false + fileprivate var isCancelled = false // MARK: Initialization - init(interval: NSTimeInterval, handler: dispatch_block_t) { - let when = dispatch_time(DISPATCH_TIME_NOW, Int64(interval * Double(NSEC_PER_SEC))) + init(interval: TimeInterval, handler: @escaping ()->()) { + let when = DispatchTime.now() + Double(Int64(interval * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) - dispatch_after(when, dispatch_get_main_queue()) { [weak self] in + DispatchQueue.main.asyncAfter(deadline: when) { [weak self] in if self?.isCancelled == true { handler() } diff --git a/Horatio/Operations/NoCancelledDependencies.swift b/Horatio/Operations/NoCancelledDependencies.swift index d7a0492..28d5c63 100644 --- a/Horatio/Operations/NoCancelledDependencies.swift +++ b/Horatio/Operations/NoCancelledDependencies.swift @@ -22,24 +22,24 @@ public struct NoCancelledDependencies: OperationCondition { // No op. } - public func dependencyForOperation(operation: Operation) -> NSOperation? { + public func dependencyForOperation(_ operation: Operation) -> Foundation.Operation? { return nil } - public func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) { + public func evaluateForOperation(_ operation: Operation, completion: @escaping (OperationConditionResult) -> Void) { // Verify that all of the dependencies executed. - let cancelled = operation.dependencies.filter { $0.cancelled } + let cancelled = operation.dependencies.filter { $0.isCancelled } if !cancelled.isEmpty { // At least one dependency was cancelled; the condition was not satisfied. - let error = NSError(code: .ConditionFailed, userInfo: [ - OperationConditionKey: self.dynamicType.name, - self.dynamicType.cancelledDependenciesKey: cancelled + let error = NSError(code: .conditionFailed, userInfo: [ + OperationConditionKey: type(of: self).name, + type(of: self).cancelledDependenciesKey: cancelled ]) - completion(.Failed(error)) + completion(.failed(error)) } else { - completion(.Satisfied) + completion(.satisfied) } } } diff --git a/Horatio/Operations/Operation.swift b/Horatio/Operations/Operation.swift index 9e13443..5937186 100644 --- a/Horatio/Operations/Operation.swift +++ b/Horatio/Operations/Operation.swift @@ -14,57 +14,57 @@ import Foundation extended readiness requirements, as well as notify many interested parties about interesting operation state changes */ -public class Operation: NSOperation { +open class Operation: Foundation.Operation { // use the KVO mechanism to indicate that changes to "state" affect other properties as well class func keyPathsForValuesAffectingIsReady() -> Set { - return ["state"] + return ["state" as NSObject] } class func keyPathsForValuesAffectingIsExecuting() -> Set { - return ["state"] + return ["state" as NSObject] } class func keyPathsForValuesAffectingIsFinished() -> Set { - return ["state"] + return ["state" as NSObject] } class func keyPathsForValuesAffectingIsCancelled() -> Set { - return ["state"] + return ["state" as NSObject] } // MARK: State Management - private enum State: Int, Comparable { + fileprivate enum State: Int, Comparable { /// The initial state of an `Operation`. - case Initialized + case initialized /// The `Operation` is ready to begin evaluating conditions. - case Pending + case pending /// The `Operation` is evaluating conditions. - case EvaluatingConditions + case evaluatingConditions /** The `Operation`'s conditions have all been satisfied, and it is ready to execute. */ - case Ready + case ready /// The `Operation` is executing. - case Executing + case executing /** Execution of the `Operation` has finished, but it has not yet notified the queue of this. */ - case Finishing + case finishing /// The `Operation` has finished executing. - case Finished + case finished /// The `Operation` has been cancelled. - case Cancelled + case cancelled } /** @@ -72,13 +72,13 @@ public class Operation: NSOperation { if appropriate. */ func willEnqueue() { - state = .Pending + state = .pending } /// Private storage for the `state` property that will be KVO observed. - private var _state = State.Initialized + fileprivate var _state = State.initialized - private var state: State { + fileprivate var state: State { get { return _state } @@ -86,75 +86,75 @@ public class Operation: NSOperation { set(newState) { // Manually fire the KVO notifications for state change, since this is "private". - willChangeValueForKey("state") + willChangeValue(forKey: "state") switch (_state, newState) { - case (.Cancelled, _): + case (.cancelled, _): break // cannot leave the cancelled state - case (.Finished, _): + case (.finished, _): break // cannot leave the finished state default: assert(_state != newState, "Performing invalid cyclic state transition.") _state = newState } - didChangeValueForKey("state") + didChangeValue(forKey: "state") } } // Here is where we extend our definition of "readiness". - override public var ready: Bool { + override open var isReady: Bool { switch state { - case .Pending: - if super.ready { + case .pending: + if super.isReady { evaluateConditions() } return false - case .Ready: - return super.ready + case .ready: + return super.isReady default: return false } } - public var userInitiated: Bool { + open var userInitiated: Bool { get { - return qualityOfService == .UserInitiated + return qualityOfService == .userInitiated } set { - assert(state < .Executing, "Cannot modify userInitiated after execution has begun.") + assert(state < .executing, "Cannot modify userInitiated after execution has begun.") - qualityOfService = newValue ? .UserInitiated : .Default + qualityOfService = newValue ? .userInitiated : .default } } - override public var executing: Bool { - return state == .Executing + override open var isExecuting: Bool { + return state == .executing } - override public var finished: Bool { - return state == .Finished + override open var isFinished: Bool { + return state == .finished } - override public var cancelled: Bool { - return state == .Cancelled + override open var isCancelled: Bool { + return state == .cancelled } - private func evaluateConditions() { - assert(state == .Pending, "evaluateConditions() was called out-of-order") + fileprivate func evaluateConditions() { + assert(state == .pending, "evaluateConditions() was called out-of-order") - state = .EvaluatingConditions + state = .evaluatingConditions OperationConditionEvaluator.evaluate(conditions, operation: self) { failures in if failures.isEmpty { // If there were no errors, we may proceed. - self.state = .Ready + self.state = .ready } else { - self.state = .Cancelled + self.state = .cancelled self.finish(failures) } } @@ -162,24 +162,24 @@ public class Operation: NSOperation { // MARK: Observers and Conditions - private(set) var conditions = [OperationCondition]() + fileprivate(set) var conditions = [OperationCondition]() - public func addCondition(condition: OperationCondition) { - assert(state < .EvaluatingConditions, "Cannot modify conditions after execution has begun.") + open func addCondition(_ condition: OperationCondition) { + assert(state < .evaluatingConditions, "Cannot modify conditions after execution has begun.") conditions.append(condition) } - private(set) var observers = [OperationObserver]() + fileprivate(set) var observers = [OperationObserver]() - public func addObserver(observer: OperationObserver) { - assert(state < .Executing, "Cannot modify observers after execution has begun.") + open func addObserver(_ observer: OperationObserver) { + assert(state < .executing, "Cannot modify observers after execution has begun.") observers.append(observer) } - override public func addDependency(operation: NSOperation) { - assert(state <= .Executing, "Dependencies cannot be modified after execution has begun.") + override open func addDependency(_ operation: Foundation.Operation) { + assert(state <= .executing, "Dependencies cannot be modified after execution has begun.") super.addDependency(operation) } @@ -191,9 +191,9 @@ public class Operation: NSOperation { print(name + " started") } - assert(state == .Ready, "This operation must be performed on an operation queue.") + assert(state == .ready, "This operation must be performed on an operation queue.") - state = .Executing + state = .executing for observer in observers { observer.operationDidStart(self) @@ -212,26 +212,26 @@ public class Operation: NSOperation { finished its execution, and that operations dependent on yours can re-evaluate their readiness state. */ - public func execute() { - print("\(self.dynamicType) must override `execute()`.") + open func execute() { + print("\(type(of: self)) must override `execute()`.") finish() } - private var _internalErrors = [NSError]() - override public func cancel() { + fileprivate var _internalErrors = [NSError]() + override open func cancel() { cancelWithError() } - public func cancelWithError(error: NSError? = nil) { + open func cancelWithError(_ error: NSError? = nil) { if let error = error { _internalErrors.append(error) } - state = .Cancelled + state = .cancelled } - final func produceOperation(operation: NSOperation) { + final func produceOperation(_ operation: Foundation.Operation) { for observer in observers { observer.operation(self, didProduceOperation: operation) } @@ -247,7 +247,7 @@ public class Operation: NSOperation { for how an error from an `NSURLSession` is passed along via the `finishWithError()` method. */ - final public func finishWithError(error: NSError?) { + final public func finishWithError(_ error: NSError?) { if let error = error { finish([error]) } else { @@ -259,11 +259,11 @@ public class Operation: NSOperation { A private property to ensure we only notify the observers once that the operation has finished. */ - private var hasFinishedAlready = false - final public func finish(errors: [NSError] = []) { + fileprivate var hasFinishedAlready = false + final public func finish(_ errors: [NSError] = []) { if !hasFinishedAlready { hasFinishedAlready = true - state = .Finishing + state = .finishing let combinedErrors = _internalErrors + errors finished(combinedErrors) @@ -272,7 +272,7 @@ public class Operation: NSOperation { observer.operationDidFinish(self, errors: combinedErrors) } - state = .Finished + state = .finished } } @@ -282,11 +282,11 @@ public class Operation: NSOperation { this method to potentially inform the user about an error when trying to bring up the Core Data stack. */ - public func finished(errors: [NSError]) { + open func finished(_ errors: [NSError]) { // No op. } - override public func waitUntilFinished() { + override open func waitUntilFinished() { /* Waiting on operations is almost NEVER the right thing to do. It is usually superior to use proper locking constructs, such as `dispatch_semaphore_t` diff --git a/Horatio/Operations/OperationCondition.swift b/Horatio/Operations/OperationCondition.swift index a2bab33..d31c0f4 100644 --- a/Horatio/Operations/OperationCondition.swift +++ b/Horatio/Operations/OperationCondition.swift @@ -41,10 +41,10 @@ public protocol OperationCondition { expressing that as multiple conditions. Alternatively, you could return a single `GroupOperation` that executes multiple operations internally. */ - func dependencyForOperation(operation: Operation) -> NSOperation? + func dependencyForOperation(_ operation: Operation) -> Foundation.Operation? /// Evaluate the condition, to see if it has been satisfied or not. - func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) + func evaluateForOperation(_ operation: Operation, completion: @escaping (OperationConditionResult) -> Void) } /** @@ -52,11 +52,11 @@ public protocol OperationCondition { failed with an error. */ public enum OperationConditionResult { - case Satisfied - case Failed(NSError) + case satisfied + case failed(NSError) var error: NSError? { - if case .Failed(let error) = self { + if case .failed(let error) = self { return error } @@ -67,23 +67,23 @@ public enum OperationConditionResult { // MARK: Evaluate Conditions public struct OperationConditionEvaluator { - public static func evaluate(conditions: [OperationCondition], operation: Operation, completion: [NSError] -> Void) { + public static func evaluate(_ conditions: [OperationCondition], operation: Operation, completion: @escaping ([NSError]) -> Void) { // Check conditions. - let conditionGroup = dispatch_group_create() + let conditionGroup = DispatchGroup() - var results = [OperationConditionResult?](count: conditions.count, repeatedValue: nil) + var results = [OperationConditionResult?](repeating: nil, count: conditions.count) // Ask each condition to evaluate and store its result in the "results" array. - for (index, condition) in conditions.enumerate() { - dispatch_group_enter(conditionGroup) + for (index, condition) in conditions.enumerated() { + conditionGroup.enter() condition.evaluateForOperation(operation) { result in results[index] = result - dispatch_group_leave(conditionGroup) + conditionGroup.leave() } } // After all the conditions have evaluated, this block will execute. - dispatch_group_notify(conditionGroup, dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) { + conditionGroup.notify(queue: DispatchQueue.global(qos: DispatchQoS.QoSClass.default)) { // Aggregate the errors that occurred, in order. var failures = results.flatMap { $0?.error } @@ -91,8 +91,8 @@ public struct OperationConditionEvaluator { If any of the conditions caused this operation to be cancelled, check for that. */ - if operation.cancelled { - failures.append(NSError(code: .ConditionFailed)) + if operation.isCancelled { + failures.append(NSError(code: .conditionFailed)) } completion(failures) diff --git a/Horatio/Operations/OperationErrors.swift b/Horatio/Operations/OperationErrors.swift index 8be69f1..fb754a4 100644 --- a/Horatio/Operations/OperationErrors.swift +++ b/Horatio/Operations/OperationErrors.swift @@ -14,12 +14,12 @@ let OperationErrorDomain = "OperationErrors" // swiftlint:enable variable_name enum OperationErrorCode: Int { - case ConditionFailed = 1 - case ExecutionFailed = 2 + case conditionFailed = 1 + case executionFailed = 2 } extension NSError { - convenience init(code: OperationErrorCode, userInfo: [NSObject: AnyObject]? = nil) { + convenience init(code: OperationErrorCode, userInfo: [AnyHashable: Any]? = nil) { self.init(domain: OperationErrorDomain, code: code.rawValue, userInfo: userInfo) } } diff --git a/Horatio/Operations/OperationObserver.swift b/Horatio/Operations/OperationObserver.swift index 68b203d..cd7d3ad 100644 --- a/Horatio/Operations/OperationObserver.swift +++ b/Horatio/Operations/OperationObserver.swift @@ -15,15 +15,15 @@ import Foundation public protocol OperationObserver { /// Invoked immediately prior to the `Operation`'s `execute()` method. - func operationDidStart(operation: Operation) + func operationDidStart(_ operation: Operation) /// Invoked when `Operation.produceOperation(_:)` is executed. - func operation(operation: Operation, didProduceOperation newOperation: NSOperation) + func operation(_ operation: Operation, didProduceOperation newOperation: Foundation.Operation) /** Invoked as an `Operation` finishes, along with any errors produced during execution (or readiness evaluation). */ - func operationDidFinish(operation: Operation, errors: [NSError]) + func operationDidFinish(_ operation: Operation, errors: [NSError]) } diff --git a/Horatio/Operations/OperationQueue.swift b/Horatio/Operations/OperationQueue.swift index e122d47..26b775b 100644 --- a/Horatio/Operations/OperationQueue.swift +++ b/Horatio/Operations/OperationQueue.swift @@ -19,8 +19,8 @@ import Foundation `OperationQueue` and uses it to manage dependencies. */ @objc public protocol OperationQueueDelegate: NSObjectProtocol { - optional func operationQueue(operationQueue: OperationQueue, willAddOperation operation: NSOperation) - optional func operationQueue(operationQueue: OperationQueue, operationDidFinish operation: NSOperation, withErrors errors: [NSError]) + @objc optional func operationQueue(_ operationQueue: OperationQueue, willAddOperation operation: Foundation.Operation) + @objc optional func operationQueue(_ operationQueue: OperationQueue, operationDidFinish operation: Foundation.Operation, withErrors errors: [NSError]) } /** @@ -31,10 +31,10 @@ import Foundation - Extracting generated dependencies from operation conditions - Setting up dependencies to enforce mutual exclusivity */ -@objc public class OperationQueue: NSOperationQueue { +@objc open class OperationQueue: Foundation.OperationQueue { weak var delegate: OperationQueueDelegate? - override public func addOperation(operation: NSOperation) { + override open func addOperation(_ operation: Foundation.Operation) { if let op = operation as? Operation { // Set up a `BlockObserver` to invoke the `OperationQueueDelegate` method. let delegate = BlockObserver( @@ -66,9 +66,9 @@ import Foundation dependencies to enforce mutual exclusivity. */ let concurrencyCategories: [String] = op.conditions.flatMap { condition in - if !condition.dynamicType.isMutuallyExclusive { return nil } + if !type(of: condition).isMutuallyExclusive { return nil } - return "\(condition.dynamicType)" + return "\(type(of: condition))" } if !concurrencyCategories.isEmpty { @@ -108,7 +108,7 @@ import Foundation super.addOperation(operation) } - override public func addOperations(operations: [NSOperation], waitUntilFinished wait: Bool) { + override open func addOperations(_ operations: [Foundation.Operation], waitUntilFinished wait: Bool) { /* The base implementation of this method does not call `addOperation()`, so we'll call it ourselves. diff --git a/Horatio/Operations/PassbookCondition.swift b/Horatio/Operations/PassbookCondition.swift index d575c68..2979aea 100644 --- a/Horatio/Operations/PassbookCondition.swift +++ b/Horatio/Operations/PassbookCondition.swift @@ -18,7 +18,7 @@ struct PassbookCondition: OperationCondition { init() { } - func dependencyForOperation(operation: Operation) -> NSOperation? { + func dependencyForOperation(_ operation: Operation) -> Foundation.Operation? { /* There's nothing you can do to make Passbook available if it's not on your device. @@ -26,15 +26,15 @@ struct PassbookCondition: OperationCondition { return nil } - func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) { + func evaluateForOperation(_ operation: Operation, completion: @escaping (OperationConditionResult) -> Void) { if PKPassLibrary.isPassLibraryAvailable() { - completion(.Satisfied) + completion(.satisfied) } else { - let error = NSError(code: .ConditionFailed, userInfo: [ - OperationConditionKey: self.dynamicType.name + let error = NSError(code: .conditionFailed, userInfo: [ + OperationConditionKey: type(of: self).name ]) - completion(.Failed(error)) + completion(.failed(error)) } } } diff --git a/Horatio/Operations/PhotosCondition.swift b/Horatio/Operations/PhotosCondition.swift index 7ef94d8..064f59d 100644 --- a/Horatio/Operations/PhotosCondition.swift +++ b/Horatio/Operations/PhotosCondition.swift @@ -18,21 +18,21 @@ public struct PhotosCondition: OperationCondition { public init() { } - public func dependencyForOperation(operation: Operation) -> NSOperation? { + public func dependencyForOperation(_ operation: Operation) -> Foundation.Operation? { return PhotosPermissionOperation() } - public func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) { + public func evaluateForOperation(_ operation: Operation, completion: @escaping (OperationConditionResult) -> Void) { switch PHPhotoLibrary.authorizationStatus() { - case .Authorized: - completion(.Satisfied) + case .authorized: + completion(.satisfied) default: - let error = NSError(code: .ConditionFailed, userInfo: [ - OperationConditionKey: self.dynamicType.name + let error = NSError(code: .conditionFailed, userInfo: [ + OperationConditionKey: type(of: self).name ]) - completion(.Failed(error)) + completion(.failed(error)) } } } @@ -50,8 +50,8 @@ private class PhotosPermissionOperation: Operation { override func execute() { switch PHPhotoLibrary.authorizationStatus() { - case .NotDetermined: - dispatch_async(dispatch_get_main_queue()) { + case .notDetermined: + DispatchQueue.main.async { PHPhotoLibrary.requestAuthorization { status in self.finish() } diff --git a/Horatio/Operations/ReachabilityCondition.swift b/Horatio/Operations/ReachabilityCondition.swift index 615ed43..48a58a9 100644 --- a/Horatio/Operations/ReachabilityCondition.swift +++ b/Horatio/Operations/ReachabilityCondition.swift @@ -19,28 +19,28 @@ public struct ReachabilityCondition: OperationCondition { public static let name = "Reachability" public static let isMutuallyExclusive = false - let host: NSURL + let host: URL - public init(host: NSURL) { + public init(host: URL) { self.host = host } - public func dependencyForOperation(operation: Operation) -> NSOperation? { + public func dependencyForOperation(_ operation: Operation) -> Foundation.Operation? { return nil } - public func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) { + public func evaluateForOperation(_ operation: Operation, completion: @escaping (OperationConditionResult) -> Void) { ReachabilityController.requestReachability(host) { reachable in if reachable { - completion(.Satisfied) + completion(.satisfied) } else { - let error = NSError(code: .ConditionFailed, userInfo: [ - OperationConditionKey: self.dynamicType.name, - self.dynamicType.hostKey: self.host + let error = NSError(code: .conditionFailed, userInfo: [ + OperationConditionKey: type(of: self).name, + type(of: self).hostKey: self.host ]) - completion(.Failed(error)) + completion(.failed(error)) } } } @@ -51,16 +51,16 @@ public struct ReachabilityCondition: OperationCondition { private class ReachabilityController { static var reachabilityRefs = [String: SCNetworkReachability]() - static let reachabilityQueue = dispatch_queue_create("Operations.Reachability", DISPATCH_QUEUE_SERIAL) + static let reachabilityQueue = DispatchQueue(label: "Operations.Reachability", attributes: []) - static func requestReachability(url: NSURL, completionHandler: (Bool) -> Void) { + static func requestReachability(_ url: URL, completionHandler: @escaping (Bool) -> Void) { if let host = url.host { - dispatch_async(reachabilityQueue) { + reachabilityQueue.async { var ref = self.reachabilityRefs[host] if ref == nil { let hostString = host as NSString - ref = SCNetworkReachabilityCreateWithName(nil, hostString.UTF8String) + ref = SCNetworkReachabilityCreateWithName(nil, hostString.utf8String!) } if let ref = ref { @@ -75,7 +75,7 @@ private class ReachabilityController { such as whether or not the connection would require VPN, a cellular connection, etc. */ - reachable = flags.contains(.Reachable) + reachable = flags.contains(.reachable) } completionHandler(reachable) } else { diff --git a/Horatio/Operations/RemoteNotificationCondition.swift b/Horatio/Operations/RemoteNotificationCondition.swift index 94422e4..a48510d 100644 --- a/Horatio/Operations/RemoteNotificationCondition.swift +++ b/Horatio/Operations/RemoteNotificationCondition.swift @@ -16,8 +16,8 @@ private let RemoteNotificationName = "RemoteNotificationPermissionNotification" // swiftlint:enable variable_name private enum RemoteRegistrationResult { - case Token(NSData) - case Error(NSError) + case token(Data) + case error(NSError) } /// A condition for verifying that the app has the ability to receive push notifications. @@ -25,14 +25,14 @@ public struct RemoteNotificationCondition: OperationCondition { public static let name = "RemoteNotification" public static let isMutuallyExclusive = false - static func didReceiveNotificationToken(token: NSData) { - NSNotificationCenter.defaultCenter().postNotificationName(RemoteNotificationName, object: nil, userInfo: [ + static func didReceiveNotificationToken(_ token: Data) { + NotificationCenter.default.post(name: Notification.Name(rawValue: RemoteNotificationName), object: nil, userInfo: [ "token": token ]) } - static func didFailToRegister(error: NSError) { - NSNotificationCenter.defaultCenter().postNotificationName(RemoteNotificationName, object: nil, userInfo: [ + static func didFailToRegister(_ error: NSError) { + NotificationCenter.default.post(name: Notification.Name(rawValue: RemoteNotificationName), object: nil, userInfo: [ "error": error ]) } @@ -43,27 +43,27 @@ public struct RemoteNotificationCondition: OperationCondition { self.application = application } - public func dependencyForOperation(operation: Operation) -> NSOperation? { + public func dependencyForOperation(_ operation: Operation) -> Foundation.Operation? { return RemoteNotificationPermissionOperation(application: application, handler: { _ in }) } - public func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) { + public func evaluateForOperation(_ operation: Operation, completion: @escaping (OperationConditionResult) -> Void) { /* Since evaluation requires executing an operation, use a private operation queue. */ RemoteNotificationQueue.addOperation(RemoteNotificationPermissionOperation(application: application) { result in switch result { - case .Token(_): - completion(.Satisfied) + case .token(_): + completion(.satisfied) - case .Error(let underlyingError): - let error = NSError(code: .ConditionFailed, userInfo: [ - OperationConditionKey: self.dynamicType.name, + case .error(let underlyingError): + let error = NSError(code: .conditionFailed, userInfo: [ + OperationConditionKey: type(of: self).name, NSUnderlyingErrorKey: underlyingError ]) - completion(.Failed(error)) + completion(.failed(error)) } }) } @@ -82,9 +82,9 @@ public struct RemoteNotificationCondition: OperationCondition { */ private class RemoteNotificationPermissionOperation: Operation { let application: UIApplication - private let handler: RemoteRegistrationResult -> Void + fileprivate let handler: (RemoteRegistrationResult) -> Void - private init(application: UIApplication, handler: RemoteRegistrationResult -> Void) { + fileprivate init(application: UIApplication, handler: @escaping (RemoteRegistrationResult) -> Void) { self.application = application self.handler = handler @@ -98,24 +98,24 @@ private class RemoteNotificationPermissionOperation: Operation { } override func execute() { - dispatch_async(dispatch_get_main_queue()) { - let notificationCenter = NSNotificationCenter.defaultCenter() + DispatchQueue.main.async { + let notificationCenter = NotificationCenter.default - notificationCenter.addObserver(self, selector: #selector(RemoteNotificationPermissionOperation.didReceiveResponse(_:)), name: RemoteNotificationName, object: nil) + notificationCenter.addObserver(self, selector: #selector(RemoteNotificationPermissionOperation.didReceiveResponse(_:)), name: NSNotification.Name(rawValue: RemoteNotificationName), object: nil) self.application.registerForRemoteNotifications() } } - @objc func didReceiveResponse(notification: NSNotification) { - NSNotificationCenter.defaultCenter().removeObserver(self) + @objc func didReceiveResponse(_ notification: Notification) { + NotificationCenter.default.removeObserver(self) - let userInfo = notification.userInfo + let userInfo = (notification as NSNotification).userInfo - if let token = userInfo?["token"] as? NSData { - handler(.Token(token)) + if let token = userInfo?["token"] as? Data { + handler(.token(token)) } else if let error = userInfo?["error"] as? NSError { - handler(.Error(error)) + handler(.error(error)) } else { fatalError("Received a notification without a token and without an error.") } @@ -129,11 +129,11 @@ private class RemoteNotificationPermissionOperation: Operation { methods necessary to configure it. */ @objc class RemoteNotificationConditionBridge: NSObject { - static func didReceiveNotificationToken(token: NSData) { + static func didReceiveNotificationToken(_ token: Data) { RemoteNotificationCondition.didReceiveNotificationToken(token) } - static func didFailToRegister(error: NSError) { + static func didFailToRegister(_ error: NSError) { RemoteNotificationCondition.didFailToRegister(error) } } diff --git a/Horatio/Operations/SilentCondition.swift b/Horatio/Operations/SilentCondition.swift index e5000d6..5f3015f 100644 --- a/Horatio/Operations/SilentCondition.swift +++ b/Horatio/Operations/SilentCondition.swift @@ -29,12 +29,12 @@ public struct SilentCondition: OperationCondition { self.condition = condition } - public func dependencyForOperation(operation: Operation) -> NSOperation? { + public func dependencyForOperation(_ operation: Operation) -> Foundation.Operation? { // Returning nil means we will never a dependency to be generated. return nil } - public func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) { + public func evaluateForOperation(_ operation: Operation, completion: @escaping (OperationConditionResult) -> Void) { condition.evaluateForOperation(operation, completion: completion) } } diff --git a/Horatio/Operations/TimeoutObserver.swift b/Horatio/Operations/TimeoutObserver.swift index 7281010..10dd981 100644 --- a/Horatio/Operations/TimeoutObserver.swift +++ b/Horatio/Operations/TimeoutObserver.swift @@ -17,28 +17,28 @@ public struct TimeoutObserver: OperationObserver { static let timeoutKey = "Timeout" - private let timeout: NSTimeInterval + fileprivate let timeout: TimeInterval // MARK: Initialization - public init(timeout: NSTimeInterval) { + public init(timeout: TimeInterval) { self.timeout = timeout } // MARK: OperationObserver - public func operationDidStart(operation: Operation) { + public func operationDidStart(_ operation: Operation) { // When the operation starts, queue up a block to cause it to time out. - let when = dispatch_time(DISPATCH_TIME_NOW, Int64(timeout * Double(NSEC_PER_SEC))) + let when = DispatchTime.now() + Double(Int64(timeout * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) - dispatch_after(when, dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) { + DispatchQueue.global(qos: DispatchQoS.QoSClass.default).asyncAfter(deadline: when) { /* Cancel the operation if it hasn't finished and hasn't already been cancelled. */ - if !operation.finished && !operation.cancelled { - let error = NSError(code: .ExecutionFailed, userInfo: [ - self.dynamicType.timeoutKey: self.timeout + if !operation.isFinished && !operation.isCancelled { + let error = NSError(code: .executionFailed, userInfo: [ + type(of: self).timeoutKey: self.timeout ]) operation.cancelWithError(error) @@ -46,11 +46,11 @@ public struct TimeoutObserver: OperationObserver { } } - public func operation(operation: Operation, didProduceOperation newOperation: NSOperation) { + public func operation(_ operation: Operation, didProduceOperation newOperation: Foundation.Operation) { // No op. } - public func operationDidFinish(operation: Operation, errors: [NSError]) { + public func operationDidFinish(_ operation: Operation, errors: [NSError]) { // No op. } } diff --git a/Horatio/Operations/UIUserNotifications+Operations.swift b/Horatio/Operations/UIUserNotifications+Operations.swift index 6f16959..d3611f3 100644 --- a/Horatio/Operations/UIUserNotifications+Operations.swift +++ b/Horatio/Operations/UIUserNotifications+Operations.swift @@ -12,7 +12,7 @@ import UIKit extension UIUserNotificationSettings { /// Check to see if one Settings object is a superset of another Settings object. - func contains(settings: UIUserNotificationSettings) -> Bool { + func contains(_ settings: UIUserNotificationSettings) -> Bool { // our types must contain all of the other types if !types.contains(settings.types) { return false @@ -21,14 +21,14 @@ extension UIUserNotificationSettings { let otherCategories = settings.categories ?? [] let myCategories = categories ?? [] - return myCategories.isSupersetOf(otherCategories) + return myCategories.isSuperset(of: otherCategories) } /** Merge two Settings objects together. `UIUserNotificationCategories` with the same identifier are considered equal. */ - func settingsByMerging(settings: UIUserNotificationSettings) -> UIUserNotificationSettings { + func settingsByMerging(_ settings: UIUserNotificationSettings) -> UIUserNotificationSettings { let mergedTypes = types.union(settings.types) let myCategories = categories ?? [] @@ -42,7 +42,7 @@ extension UIUserNotificationSettings { } let mergedCategories = Set(existingCategoriesByIdentifier.values) - return UIUserNotificationSettings(forTypes: mergedTypes, categories: mergedCategories) + return UIUserNotificationSettings(types: mergedTypes, categories: mergedCategories) } } diff --git a/Horatio/Operations/URLSessionTaskOperation.swift b/Horatio/Operations/URLSessionTaskOperation.swift index 4b2de65..f34ba51 100644 --- a/Horatio/Operations/URLSessionTaskOperation.swift +++ b/Horatio/Operations/URLSessionTaskOperation.swift @@ -21,40 +21,41 @@ private var URLSessionTaksOperationKVOContext = 0 An example usage of `URLSessionTaskOperation` can be seen in the `DownloadEarthquakesOperation`. */ -public class URLSessionTaskOperation: Operation { - let task: NSURLSessionTask +open class URLSessionTaskOperation: Operation { + let task: URLSessionTask - public init(task: NSURLSessionTask) { - assert(task.state == .Suspended, "Tasks must be suspended.") + public init(task: URLSessionTask) { + assert(task.state == .suspended, "Tasks must be suspended.") self.task = task super.init() } - override public func execute() { - assert(task.state == .Suspended, "Task was resumed by something other than \(self).") + override open func execute() { + assert(task.state == .suspended, "Task was resumed by something other than \(self).") task.addObserver(self, forKeyPath: "state", options: [], context: &URLSessionTaksOperationKVOContext) task.resume() } - override public func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer) { + override open func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { guard context == &URLSessionTaksOperationKVOContext else { return } + guard let object = object as? URLSessionTask else { return } - if object === task && keyPath == "state" && task.state == .Completed { + if object === task && keyPath == "state" && task.state == .completed { task.removeObserver(self, forKeyPath: "state") if let error = task.error { - finish([error]) + finish([error as NSError]) } else { finish() } } } - override public func cancel() { + override open func cancel() { task.cancel() super.cancel() } diff --git a/Horatio/Operations/UserNotificationCondition.swift b/Horatio/Operations/UserNotificationCondition.swift index 9b660e0..9ccf022 100644 --- a/Horatio/Operations/UserNotificationCondition.swift +++ b/Horatio/Operations/UserNotificationCondition.swift @@ -18,10 +18,10 @@ public struct UserNotificationCondition: OperationCondition { public enum Behavior { /// Merge the new `UIUserNotificationSettings` with the `currentUserNotificationSettings`. - case Merge + case merge /// Replace the `currentUserNotificationSettings` with the new `UIUserNotificationSettings`. - case Replace + case replace } public static let name = "UserNotification" @@ -48,33 +48,33 @@ public struct UserNotificationCondition: OperationCondition { `application`. You may also specify `.Replace`, which means the `settings` will overwrite the exisiting settings. */ - public init(settings: UIUserNotificationSettings, application: UIApplication, behavior: Behavior = .Merge) { + public init(settings: UIUserNotificationSettings, application: UIApplication, behavior: Behavior = .merge) { self.settings = settings self.application = application self.behavior = behavior } - public func dependencyForOperation(operation: Operation) -> NSOperation? { + public func dependencyForOperation(_ operation: Operation) -> Foundation.Operation? { return UserNotificationPermissionOperation(settings: settings, application: application, behavior: behavior) } - public func evaluateForOperation(operation: Operation, completion: OperationConditionResult -> Void) { + public func evaluateForOperation(_ operation: Operation, completion: @escaping (OperationConditionResult) -> Void) { let result: OperationConditionResult - let current = application.currentUserNotificationSettings() + let current = application.currentUserNotificationSettings switch (current, settings) { case (let current?, let settings) where current.contains(settings): - result = .Satisfied + result = .satisfied default: - let error = NSError(code: .ConditionFailed, userInfo: [ - OperationConditionKey: self.dynamicType.name, - self.dynamicType.currentSettings: current ?? NSNull(), - self.dynamicType.desiredSettings: settings + let error = NSError(code: .conditionFailed, userInfo: [ + OperationConditionKey: type(of: self).name, + type(of: self).currentSettings: current ?? NSNull(), + type(of: self).desiredSettings: settings ]) - result = .Failed(error) + result = .failed(error) } completion(result) @@ -101,13 +101,13 @@ private class UserNotificationPermissionOperation: Operation { } override func execute() { - dispatch_async(dispatch_get_main_queue()) { - let current = self.application.currentUserNotificationSettings() + DispatchQueue.main.async { + let current = self.application.currentUserNotificationSettings let settingsToRegister: UIUserNotificationSettings switch (current, self.behavior) { - case (let currentSettings?, .Merge): + case (let currentSettings?, .merge): settingsToRegister = currentSettings.settingsByMerging(self.settings) default: diff --git a/Horatio/Scheduler/TaskScheduler.swift b/Horatio/Scheduler/TaskScheduler.swift index 33a4242..f37ca83 100644 --- a/Horatio/Scheduler/TaskScheduler.swift +++ b/Horatio/Scheduler/TaskScheduler.swift @@ -8,7 +8,7 @@ import Foundation public protocol ScheduledTaskProvider { var identifier: String { get } - func makeScheduledTasks() -> [NSOperation] + func makeScheduledTasks() -> [Foundation.Operation] } @@ -18,20 +18,20 @@ public protocol ScheduledTaskCoordinator { func scheduleTasks() - func addTaskProvider(provider: ScheduledTaskProvider) - func removeTaskProvider(provider: ScheduledTaskProvider) + func addTaskProvider(_ provider: ScheduledTaskProvider) + func removeTaskProvider(_ provider: ScheduledTaskProvider) } class TimedTaskCoordinator : ScheduledTaskCoordinator { struct Behaviors { - static let TimerInterval: NSTimeInterval = 10.0 + static let TimerInterval: TimeInterval = 10.0 } var providers = [ScheduledTaskProvider]() var isActive = false - var updateTimer: NSTimer? + var updateTimer: Foundation.Timer? // MARK: - Initialization @@ -62,7 +62,7 @@ class TimedTaskCoordinator : ScheduledTaskCoordinator { isActive = true if updateTimer == nil { - updateTimer = NSTimer.scheduledTimerWithTimeInterval(Behaviors.TimerInterval, target: self, selector: #selector(timerFired), userInfo: nil, repeats: true) + updateTimer = Foundation.Timer.scheduledTimer(timeInterval: Behaviors.TimerInterval, target: self, selector: #selector(timerFired), userInfo: nil, repeats: true) } if let updateTimer = updateTimer { @@ -83,25 +83,25 @@ class TimedTaskCoordinator : ScheduledTaskCoordinator { } - func addTaskProvider(provider: ScheduledTaskProvider) { + func addTaskProvider(_ provider: ScheduledTaskProvider) { providers.append(provider) } - func removeTaskProvider(provider: ScheduledTaskProvider) { - guard let index = providers.indexOf({ (testProvider) -> Bool in + func removeTaskProvider(_ provider: ScheduledTaskProvider) { + guard let index = providers.index(where: { (testProvider) -> Bool in return testProvider.identifier == provider.identifier }) else { return } - providers.removeAtIndex(index) + providers.remove(at: index) } // MARK: - Private @objc - private func timerFired(timer: NSTimer) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { + fileprivate func timerFired(_ timer: Foundation.Timer) { + DispatchQueue.global(priority: DispatchQueue.GlobalQueuePriority.default).async { self.scheduleTasks() } } diff --git a/Horatio/Services/Service.swift b/Horatio/Services/Service.swift index b16ab48..50c38e6 100644 --- a/Horatio/Services/Service.swift +++ b/Horatio/Services/Service.swift @@ -13,11 +13,11 @@ import Foundation public protocol Service: class { var sessionHandler: ServiceSessionHandler? { get } - func makeRequest(identifier: String, payload: ServiceRequestPayload?, configurator: ServiceRequestConfigurator?) -> ServiceRequest? + func makeRequest(_ identifier: String, payload: ServiceRequestPayload?, configurator: ServiceRequestConfigurator?) -> ServiceRequest? } extension Service { - public func makeRequest(identifier: String, payload: ServiceRequestPayload?, configurator: ServiceRequestConfigurator?) -> ServiceRequest? { + public func makeRequest(_ identifier: String, payload: ServiceRequestPayload?, configurator: ServiceRequestConfigurator?) -> ServiceRequest? { if let endpointProvider = Container.resolve(ServiceEndpointProvider.self) { if let endpoint = endpointProvider.endpoint(identifier) { let request = ServiceRequest(endpoint: endpoint, payload: payload, configurator: configurator) diff --git a/Horatio/Services/ServiceEndpoint+JSONParsing.swift b/Horatio/Services/ServiceEndpoint+JSONParsing.swift index 266ebb1..9198af4 100644 --- a/Horatio/Services/ServiceEndpoint+JSONParsing.swift +++ b/Horatio/Services/ServiceEndpoint+JSONParsing.swift @@ -26,8 +26,8 @@ extension ServiceEndpoint : JSONParsing { // MARK: - public func updateFromJSONRepresentation(data: JSONObject) { - guard self.dynamicType.isValidJSONRepresentation(data) else { return } + public func updateFromJSONRepresentation(_ data: JSONObject) { + guard type(of: self).isValidJSONRepresentation(data) else { return } if let urlString = JSONParser.parseString(data[JSONKeys.URL]) { urlContainer = .absolutePath(urlString) @@ -35,7 +35,7 @@ extension ServiceEndpoint : JSONParsing { let basePath = JSONParser.parseString(data[JSONKeys.BasePath]) let path = JSONParser.parseString(data[JSONKeys.Path]) - let components = NSURLComponents() + var components = URLComponents() components.scheme = JSONParser.parseString(data[JSONKeys.Scheme]) components.host = JSONParser.parseString(data[JSONKeys.HostName]) components.path = "\(basePath)/\(path)" @@ -48,7 +48,7 @@ extension ServiceEndpoint : JSONParsing { } - public static func isValidJSONRepresentation (data: JSONObject) -> Bool { + public static func isValidJSONRepresentation (_ data: JSONObject) -> Bool { // For now our endpoints only include a url key which we must have guard let _ = JSONParser.parseString(data[JSONKeys.URL], options: .none) else { return false } diff --git a/Horatio/Services/ServiceEndpoint.swift b/Horatio/Services/ServiceEndpoint.swift index 4a6f8c1..e1a63ce 100644 --- a/Horatio/Services/ServiceEndpoint.swift +++ b/Horatio/Services/ServiceEndpoint.swift @@ -30,7 +30,7 @@ public enum ServiceEndpointType : String { but can switch between them as necessary (for example, when switching environments). */ public protocol ServiceEndpointProvider: class { - func endpoint(identifier: String) -> ServiceEndpoint? + func endpoint(_ identifier: String) -> ServiceEndpoint? } @@ -39,7 +39,7 @@ public protocol ServiceEndpointProvider: class { */ enum ServiceEndpointURLContainer { // URL is contained in an `NSURLComponents` object - case components(NSURLComponents) + case components(URLComponents) // URL is contained in a self-contained complete URL case absolutePath(String) @@ -50,17 +50,17 @@ enum ServiceEndpointURLContainer { instances (which can then be turned into `NSURLRequest` instances via the appropriate `Service`). */ -public class ServiceEndpoint { +open class ServiceEndpoint { // MARK: - Properties - public let identifier: String + open let identifier: String var urlContainer: ServiceEndpointURLContainer - public var type: ServiceEndpointType = .get + open var type: ServiceEndpointType = .get - public var isAuthRequired: Bool = false - public var isIdempotent: Bool = true + open var isAuthRequired: Bool = false + open var isIdempotent: Bool = true // MARK: - Initialization @@ -74,7 +74,7 @@ public class ServiceEndpoint { public convenience init(identifier: String, scheme: String, hostName: String, basePath: String, path: String) { self.init(identifier: identifier) - let components = NSURLComponents() + var components = URLComponents() components.scheme = scheme components.host = hostName components.path = "\(basePath)/\(path)" @@ -99,12 +99,12 @@ public class ServiceEndpoint { often, this would be modified by one or more `ServiceEndpointPathTransformer` instances attached to a `ServiceRequest`. */ - public func url() -> NSURL? { + open func url() -> URL? { switch urlContainer { case .components(let components): - return components.URL + return components.url case .absolutePath(let urlString): - return NSURL(string: urlString) + return URL(string: urlString) } } } diff --git a/Horatio/Services/ServiceEndpointPathTransformer.swift b/Horatio/Services/ServiceEndpointPathTransformer.swift index 592fc37..75194b6 100644 --- a/Horatio/Services/ServiceEndpointPathTransformer.swift +++ b/Horatio/Services/ServiceEndpointPathTransformer.swift @@ -11,12 +11,13 @@ import Foundation values. */ public protocol ServiceEndpointPathTransformer: class { - func transformedPath(path: String) -> String + func transformedPath(_ path: String) -> String } extension ServiceEndpointPathTransformer { - func transformedPath(components: NSURLComponents) -> NSURLComponents { - guard let path = components.path, let newComponents = components.copy() as? NSURLComponents else { return components } + func transformedPath(_ components: URLComponents) -> URLComponents { + let path = components.path + guard var newComponents = (components as NSURLComponents).copy() as? URLComponents else { return components } newComponents.path = transformedPath(path) @@ -29,7 +30,7 @@ extension ServiceEndpointPathTransformer { A `EndpointPathTransformer` defined by substitutions; for example, "http://example.com/game_[GAMEID].json". */ -public class SubstitutionsServiceEndpointPathTransformer: ServiceEndpointPathTransformer { +open class SubstitutionsServiceEndpointPathTransformer: ServiceEndpointPathTransformer { // MARK: - Properties let substitutions: [String : String] @@ -46,14 +47,14 @@ public class SubstitutionsServiceEndpointPathTransformer: ServiceEndpointPathTra // MARK: - public func transformedPath(path: String) -> String { + open func transformedPath(_ path: String) -> String { var endpointPath = path for key in substitutions.keys { let identifier = String.init(format: "{%@}", key) if let value = substitutions[key] { - endpointPath = endpointPath.stringByReplacingOccurrencesOfString(identifier, withString: value) + endpointPath = endpointPath.replacingOccurrences(of: identifier, with: value) } } @@ -65,7 +66,7 @@ public class SubstitutionsServiceEndpointPathTransformer: ServiceEndpointPathTra A `EndpointPathTransformer` subclass defined by a RESTful locator chain; for example, "http://example.com/:year/game/:id". */ -public class LocatorChainServiceEndpointPathTransformer: ServiceEndpointPathTransformer { +open class LocatorChainServiceEndpointPathTransformer: ServiceEndpointPathTransformer { // MARK: - Properties let locator: [String] @@ -82,13 +83,13 @@ public class LocatorChainServiceEndpointPathTransformer: ServiceEndpointPathTran // MARK: - public func transformedPath(path: String) -> String { + open func transformedPath(_ path: String) -> String { var endpointPath = path var transformedComponents: [String] = [] var index = 0 - for pathPart in endpointPath.componentsSeparatedByString("/") { + for pathPart in endpointPath.components(separatedBy: "/") { if !pathPart.isEmpty && pathPart.characters[pathPart.startIndex] == ":" { if index < locator.count { // replace the next ":(foo)" with the first locator remaining @@ -109,7 +110,7 @@ public class LocatorChainServiceEndpointPathTransformer: ServiceEndpointPathTran return path } - endpointPath = transformedComponents.joinWithSeparator("/") + endpointPath = transformedComponents.joined(separator: "/") return endpointPath } diff --git a/Horatio/Services/ServiceRequest.swift b/Horatio/Services/ServiceRequest.swift index d021875..0e085c4 100644 --- a/Horatio/Services/ServiceRequest.swift +++ b/Horatio/Services/ServiceRequest.swift @@ -20,11 +20,11 @@ public protocol ServiceRequestPayload { /// An empty service request for requests that require no payload; typealias to a specific payload type to use -public class EmptyServiceRequestPayload: ServiceRequestPayload { +open class EmptyServiceRequestPayload: ServiceRequestPayload { // MARK: - Initializers public init() { - let uuidString = NSUUID().UUIDString + let uuidString = UUID().uuidString self.hashString = "\(uuidString)" } @@ -33,18 +33,18 @@ public class EmptyServiceRequestPayload: ServiceRequestPayload { // MARK: - public func values() -> [String : String] { + open func values() -> [String : String] { return [String : String]() } - public func hashValue() -> Int { + open func hashValue() -> Int { return hashString.hashValue } // MARK: - Private - private let hashString: String + fileprivate let hashString: String } @@ -89,7 +89,7 @@ public struct ServiceRequest { // MARK: - Properties public let endpoint: ServiceEndpoint - public var url: NSURL? + public var url: URL? public let payload: ServiceRequestPayload? let configurator: ServiceRequestConfigurator? @@ -106,7 +106,7 @@ public struct ServiceRequest { if let configurator = configurator { self.url = configurator.configureURL(self) } else { - self.url = endpoint.url() + self.url = endpoint.url() as URL? } } @@ -124,11 +124,11 @@ public struct ServiceRequest { (for example, if the `Service` responsible for this request requires OAuth or other HTTP-request based authentication). */ - public func makeURLRequest(session: ServiceSession?) -> NSURLRequest? { + public func makeURLRequest(_ session: ServiceSession?) -> URLRequest? { guard let url = url else { return nil } - var request = NSMutableURLRequest(URL: url) - request.HTTPMethod = self.endpoint.type.rawValue + var request = NSMutableURLRequest(url: url) + request.httpMethod = self.endpoint.type.rawValue if let configurator = configurator { request = configurator.configureURLRequest(self, urlRequest: request) @@ -138,6 +138,6 @@ public struct ServiceRequest { session.signURLRequest(request) } - return request + return request as URLRequest } } diff --git a/Horatio/Services/ServiceRequestConfigurator.swift b/Horatio/Services/ServiceRequestConfigurator.swift index 3f743f1..ac5e0f8 100644 --- a/Horatio/Services/ServiceRequestConfigurator.swift +++ b/Horatio/Services/ServiceRequestConfigurator.swift @@ -10,24 +10,24 @@ import Foundation concrete implementation might generate a "Create Post" request. */ public protocol ServiceRequestConfigurator: class { - func configureURL(serviceRequest: ServiceRequest) -> NSURL? - func configureURLRequest(serviceRequest: ServiceRequest, urlRequest: NSMutableURLRequest) -> NSMutableURLRequest + func configureURL(_ serviceRequest: ServiceRequest) -> URL? + func configureURLRequest(_ serviceRequest: ServiceRequest, urlRequest: NSMutableURLRequest) -> NSMutableURLRequest - func endpointPathTransformers(serviceRequest: ServiceRequest) -> [ServiceEndpointPathTransformer] - func urlRequestDecorators(serviceRequest: ServiceRequest) -> [ServiceRequestDecorator] + func endpointPathTransformers(_ serviceRequest: ServiceRequest) -> [ServiceEndpointPathTransformer] + func urlRequestDecorators(_ serviceRequest: ServiceRequest) -> [ServiceRequestDecorator] } /// Provides base functionality for implementations of `ServiceRequestConfigurator`. public extension ServiceRequestConfigurator { - public func configureURL(serviceRequest: ServiceRequest) -> NSURL? { + public func configureURL(_ serviceRequest: ServiceRequest) -> URL? { switch serviceRequest.endpoint.urlContainer { case .components(var components): for transformer in endpointPathTransformers(serviceRequest) { components = transformer.transformedPath(components) } - return components.URL + return components.url case .absolutePath(let urlString): var basePath = urlString @@ -36,12 +36,12 @@ public extension ServiceRequestConfigurator { basePath = transformer.transformedPath(basePath) } - return NSURL(string: basePath) + return URL(string: basePath) } } - public func configureURLRequest(serviceRequest: ServiceRequest, urlRequest: NSMutableURLRequest) -> NSMutableURLRequest { + public func configureURLRequest(_ serviceRequest: ServiceRequest, urlRequest: NSMutableURLRequest) -> NSMutableURLRequest { for decorator in urlRequestDecorators(serviceRequest) { decorator.compose(urlRequest) } @@ -55,7 +55,7 @@ public extension ServiceRequestConfigurator { Handles a generic key-value store of entries dropped into the URL as GET or POST parameters, with no endpoint path transformations. */ -public class DictionaryServiceRequestConfigurator: ServiceRequestConfigurator { +open class DictionaryServiceRequestConfigurator: ServiceRequestConfigurator { // MARK: - Properties let parameters: [String : String] @@ -72,11 +72,11 @@ public class DictionaryServiceRequestConfigurator: ServiceRequestConfigurator { // MARK: - public func endpointPathTransformers(serviceRequest: ServiceRequest) -> [ServiceEndpointPathTransformer] { + open func endpointPathTransformers(_ serviceRequest: ServiceRequest) -> [ServiceEndpointPathTransformer] { return [ServiceEndpointPathTransformer]() } - public func urlRequestDecorators(serviceRequest: ServiceRequest) -> [ServiceRequestDecorator] { + open func urlRequestDecorators(_ serviceRequest: ServiceRequest) -> [ServiceRequestDecorator] { let decorator = HTTPParametersBodyServiceRequestDecorator(type: serviceRequest.endpoint.type, parameters: parameters) return [decorator] diff --git a/Horatio/Services/ServiceRequestDecorator.swift b/Horatio/Services/ServiceRequestDecorator.swift index 7251bc3..62d294e 100644 --- a/Horatio/Services/ServiceRequestDecorator.swift +++ b/Horatio/Services/ServiceRequestDecorator.swift @@ -10,14 +10,14 @@ import Foundation to turning the URL request into a fetch. */ public protocol ServiceRequestDecorator: class { - func compose(urlRequest: NSMutableURLRequest) + func compose(_ urlRequest: NSMutableURLRequest) } /** Adds an HTTP header indicating the response can be Gzip compressed. */ -public class AcceptGZIPHeadersServiceRequestDecorator: ServiceRequestDecorator { +open class AcceptGZIPHeadersServiceRequestDecorator: ServiceRequestDecorator { // MARK: - Initializers public init() { } @@ -27,7 +27,7 @@ public class AcceptGZIPHeadersServiceRequestDecorator: ServiceRequestDecorator { // MARK: - public func compose(urlRequest: NSMutableURLRequest) { + open func compose(_ urlRequest: NSMutableURLRequest) { urlRequest.setValue("gzip", forHTTPHeaderField: "Accept-Encoding") } } @@ -37,7 +37,7 @@ public class AcceptGZIPHeadersServiceRequestDecorator: ServiceRequestDecorator { Applies its parameters either as GET parameters or by building a POST body payload as appropriate for the type of request. */ -public class HTTPParametersBodyServiceRequestDecorator: ServiceRequestDecorator { +open class HTTPParametersBodyServiceRequestDecorator: ServiceRequestDecorator { // MARK: - Properties let type: ServiceEndpointType @@ -56,13 +56,13 @@ public class HTTPParametersBodyServiceRequestDecorator: ServiceRequestDecorator // MARK: - public func compose(urlRequest: NSMutableURLRequest) { + open func compose(_ urlRequest: NSMutableURLRequest) { guard !parameters.isEmpty else { return } switch type { case .get: - if let requestURL = urlRequest.URL { - urlRequest.URL = requestURL.urlByAppendingQueryParameters(parameters) + if let requestURL = urlRequest.url { + urlRequest.url = requestURL.urlByAppendingQueryParameters(parameters) } case .post: fallthrough @@ -73,14 +73,14 @@ public class HTTPParametersBodyServiceRequestDecorator: ServiceRequestDecorator var valueStrings = [String]() for (key, value) in parameters { - let encodedValue = value.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) + let encodedValue = value.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) valueStrings.append("\(key)=\(encodedValue)") } - let requestBody = valueStrings.joinWithSeparator("&") + let requestBody = valueStrings.joined(separator: "&") - let data = requestBody.dataUsingEncoding(NSUTF8StringEncoding) - urlRequest.HTTPBody = data + let data = requestBody.data(using: String.Encoding.utf8) + urlRequest.httpBody = data case .header: /// TODO: support HEADER requests @@ -90,18 +90,18 @@ public class HTTPParametersBodyServiceRequestDecorator: ServiceRequestDecorator } -internal extension NSURL { +internal extension URL { /** Provides support for mutating a URL into another by adding query parameters to the URL's existing parameters (or by adding query parameters if none already exist). */ - func urlByAppendingQueryParameters(parameters: [String : String]?) -> NSURL { + func urlByAppendingQueryParameters(_ parameters: [String : String]?) -> URL { guard let parameters = parameters else { return self } - guard let components = NSURLComponents(URL: self, resolvingAgainstBaseURL: false) else { return self } + guard var components = URLComponents(url: self, resolvingAgainstBaseURL: false) else { return self } for (key, value) in parameters { - let encodedValue = value.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) - let queryItem = NSURLQueryItem(name: key, value: encodedValue) + let encodedValue = value.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) + let queryItem = URLQueryItem(name: key, value: encodedValue) if let _ = components.queryItems { components.queryItems?.append(queryItem) @@ -110,7 +110,7 @@ internal extension NSURL { } } - if let url = components.URL { + if let url = components.url { return url } @@ -122,9 +122,9 @@ internal extension NSURL { /** Adds an HTTP header for HTTP Basic authentication. */ -public class HTTPAuthServiceRequestDecorator: ServiceRequestDecorator { - private let username: String - private let password: String +open class HTTPAuthServiceRequestDecorator: ServiceRequestDecorator { + fileprivate let username: String + fileprivate let password: String public init(username: String, password: String) { @@ -133,11 +133,11 @@ public class HTTPAuthServiceRequestDecorator: ServiceRequestDecorator { } - public func compose(urlRequest: NSMutableURLRequest) { + open func compose(_ urlRequest: NSMutableURLRequest) { let credentials = "\(username):\(password)" - if let data = credentials.dataUsingEncoding(NSUTF8StringEncoding) { - let credentials = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions()) + if let data = credentials.data(using: String.Encoding.utf8) { + let credentials = data.base64EncodedString(options: NSData.Base64EncodingOptions()) let value = "Basic \(credentials)" urlRequest.setValue(value, forHTTPHeaderField: "Authorization") diff --git a/Horatio/Services/ServiceRequestOperation.swift b/Horatio/Services/ServiceRequestOperation.swift index 0d89dea..26763f2 100644 --- a/Horatio/Services/ServiceRequestOperation.swift +++ b/Horatio/Services/ServiceRequestOperation.swift @@ -9,7 +9,7 @@ import Foundation Handles downloading and processing of a `ServiceRequest`. Callers provide a `ServiceResponseProcessor` responsible for processing the response once it's successfully fetched. */ -public class FetchServiceResponseOperation: GroupOperation { +open class FetchServiceResponseOperation: GroupOperation { // MARK: - Properties let downloadOperation: DownloadServiceResponseOperation @@ -19,7 +19,7 @@ public class FetchServiceResponseOperation: GroupOperation { // MARK: - Initialization public init(request: ServiceRequest, session: ServiceSession? = nil, responseProcessor: ServiceResponseProcessor) { - let cachesFolder = try! NSFileManager.defaultManager().URLForDirectory(.CachesDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true) + let cachesFolder = try! FileManager.default.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: true) var cacheFileName = FetchServiceResponseOperation.randomCacheFileName() @@ -27,11 +27,11 @@ public class FetchServiceResponseOperation: GroupOperation { cacheFileName = "\(payload.hashValue()).json" } - let cacheFile = cachesFolder.URLByAppendingPathComponent(cacheFileName) + let cacheFile = cachesFolder.appendingPathComponent(cacheFileName) - downloadOperation = DownloadServiceResponseOperation(request: request, session: session, cacheFile: cacheFile!) + downloadOperation = DownloadServiceResponseOperation(request: request, session: session, cacheFile: cacheFile) - parseOperation = ProcessServiceResponseOperation(request: request, responseProcessor: responseProcessor, cacheFile: cacheFile!) + parseOperation = ProcessServiceResponseOperation(request: request, responseProcessor: responseProcessor, cacheFile: cacheFile) parseOperation.addDependency(downloadOperation) super.init(operations: [downloadOperation, parseOperation]) @@ -42,7 +42,7 @@ public class FetchServiceResponseOperation: GroupOperation { // MARK: - Private - private static func randomCacheFileName() -> String { + fileprivate static func randomCacheFileName() -> String { // TODO: use guid or something similar return "cacheFile" } @@ -54,29 +54,32 @@ public class FetchServiceResponseOperation: GroupOperation { storing the downloaded file in a cache file location that continued operations can pick up and manipulate. */ -public class DownloadServiceResponseOperation: GroupOperation { +open class DownloadServiceResponseOperation: GroupOperation { // MARK: - Properties let request: ServiceRequest - let cacheFile: NSURL + let cacheFile: URL // MARK: - Initialization - public init(request: ServiceRequest, session: ServiceSession? = nil, cacheFile: NSURL) { + public init(request: ServiceRequest, session: ServiceSession? = nil, cacheFile: URL) { self.request = request self.cacheFile = cacheFile super.init(operations: []) if let urlRequest = request.makeURLRequest(session) { - if let url = urlRequest.URL { + if let url = urlRequest.url { name = "Download Service Request Operation \(url)" + + let task = URLSession.shared.downloadTask(with: urlRequest, completionHandler: { [weak self] (url, response, error) -> Void in + guard let weakSelf = self else { return } + guard let response = response as? HTTPURLResponse else { weakSelf.finish(); return } - let task = NSURLSession.sharedSession().downloadTaskWithRequest(urlRequest) { url, response, error in - self.downloadFinished(url, response: response as? NSHTTPURLResponse, error: error) - } + weakSelf.downloadFinished(url, response: response, error: error as NSError?) + }) let taskOperation = URLSessionTaskOperation(task: task) addOperation(taskOperation) @@ -87,14 +90,14 @@ public class DownloadServiceResponseOperation: GroupOperation { // MARK: - Private - private func downloadFinished(url: NSURL?, response: NSHTTPURLResponse?, error: NSError?) { + fileprivate func downloadFinished(_ url: URL?, response: HTTPURLResponse?, error: NSError?) { if let localURL = url { do { - try NSFileManager.defaultManager().removeItemAtURL(cacheFile) + try FileManager.default.removeItem(at: cacheFile) } catch { } do { - try NSFileManager.defaultManager().moveItemAtURL(localURL, toURL: cacheFile) + try FileManager.default.moveItem(at: localURL, to: cacheFile) } catch let error as NSError { aggregateError(error) } @@ -112,18 +115,18 @@ public class DownloadServiceResponseOperation: GroupOperation { Uses a provided `ServiceResponseProcessor` to process a response downloaded into a cache file. */ -public class ProcessServiceResponseOperation: Operation { +open class ProcessServiceResponseOperation: Operation { // MARK: - Properties let request: ServiceRequest - let cacheFile: NSURL + let cacheFile: URL let responseProcessor: ServiceResponseProcessor // MARK: - Initialization - public init(request: ServiceRequest, responseProcessor: ServiceResponseProcessor, cacheFile: NSURL) { + public init(request: ServiceRequest, responseProcessor: ServiceResponseProcessor, cacheFile: URL) { self.request = request self.cacheFile = cacheFile @@ -135,8 +138,8 @@ public class ProcessServiceResponseOperation: Operation { // MARK: - Overrides - override public func execute() { - guard let stream = NSInputStream(URL: cacheFile) else { + override open func execute() { + guard let stream = InputStream(url: cacheFile) else { finish() return @@ -178,10 +181,10 @@ public class ProcessServiceResponseOperation: Operation { */ public enum ServiceResponseProcessorParam { /// Initial input is typically a memory-efficient `NSInputStream`. - case stream(NSInputStream) + case stream(InputStream) /// `NSData` can be used to pipe data from one processor to the next. - case data(String, NSData) + case data(String, Data) /// The processor was terminal, with an indication of whether the data was completely processed. case processed(Bool) @@ -197,5 +200,5 @@ public enum ServiceResponseProcessorParam { complete the processing stage of the operation. */ public protocol ServiceResponseProcessor: class { - func process(request: ServiceRequest, input: ServiceResponseProcessorParam, completionBlock: (ServiceResponseProcessorParam) -> Void) + func process(_ request: ServiceRequest, input: ServiceResponseProcessorParam, completionBlock: (ServiceResponseProcessorParam) -> Void) } diff --git a/Horatio/Services/ServiceRequestStatus.swift b/Horatio/Services/ServiceRequestStatus.swift index 90a622e..00bf2a0 100644 --- a/Horatio/Services/ServiceRequestStatus.swift +++ b/Horatio/Services/ServiceRequestStatus.swift @@ -14,10 +14,10 @@ import Foundation public protocol ServiceStatusHandler: class { var statuses: [ServiceEndpointResponseStatus] { get } - func isIdle(identifier: ServiceRequestIdentifier) -> Bool + func isIdle(_ identifier: ServiceRequestIdentifier) -> Bool - func updateStatus(identifier: ServiceRequestIdentifier, status: ServiceEndpointStatus) - func lastStatus(identifier: ServiceRequestIdentifier) -> (ServiceEndpointStatus, NSDate?) + func updateStatus(_ identifier: ServiceRequestIdentifier, status: ServiceEndpointStatus) + func lastStatus(_ identifier: ServiceRequestIdentifier) -> (ServiceEndpointStatus, Date?) } @@ -42,18 +42,18 @@ public enum ServiceEndpointStatus: Int16 { Encapsulates the current state of a fetches against a specific request (`ServiceEndpoint` and `ServiceRequestPayload` combination) in an informal state machine. */ -public class ServiceEndpointResponseStatus { +open class ServiceEndpointResponseStatus { // MARK: - Properties - public let identifier: ServiceRequestIdentifier + open let identifier: ServiceRequestIdentifier - public var updateDate: NSDate + open var updateDate: Date - public var activityState: ServiceEndpointState = .waiting - public var status: ServiceEndpointStatus = .unknown + open var activityState: ServiceEndpointState = .waiting + open var status: ServiceEndpointStatus = .unknown - public var error: NSError? - public var urlResponse: NSURLResponse? + open var error: NSError? + open var urlResponse: URLResponse? // MARK: - Initialization @@ -61,7 +61,7 @@ public class ServiceEndpointResponseStatus { public init(identifier: ServiceRequestIdentifier) { self.identifier = identifier - self.updateDate = NSDate.distantPast() + self.updateDate = Date.distantPast } @@ -72,7 +72,7 @@ public class ServiceEndpointResponseStatus { /** Indicate that this status has moved from Idle to starting a fetch. */ - public func startFetch() { + open func startFetch() { changeState(.fetching) } @@ -82,7 +82,7 @@ public class ServiceEndpointResponseStatus { - parameter response: The `NSURLResponse` that completed, causing the status to transition to the parsing state. */ - public func startParse(response: NSURLResponse? = nil) { + open func startParse(_ response: URLResponse? = nil) { urlResponse = response changeState(.parsing) @@ -94,7 +94,7 @@ public class ServiceEndpointResponseStatus { - parameter completionError: The error that prevented the status from completing successfilly. */ - public func completeWithError(completionError: NSError?) { + open func completeWithError(_ completionError: NSError?) { status = .failure error = completionError @@ -104,7 +104,7 @@ public class ServiceEndpointResponseStatus { /** Indicate that this status has completed successfully. */ - public func completeWithSuccess() { + open func completeWithSuccess() { status = .success changeState(.complete) @@ -113,11 +113,11 @@ public class ServiceEndpointResponseStatus { // MARK: - Private - private func changeState(state: ServiceEndpointState) { + fileprivate func changeState(_ state: ServiceEndpointState) { guard activityState != .complete else { return } guard state != activityState else { return } activityState = state - updateDate = NSDate() + updateDate = Date() } } diff --git a/Horatio/Services/ServiceSession.swift b/Horatio/Services/ServiceSession.swift index 342b51a..770fcab 100644 --- a/Horatio/Services/ServiceSession.swift +++ b/Horatio/Services/ServiceSession.swift @@ -11,7 +11,7 @@ import Foundation public protocol ServiceSessionHandler: class { var activeSession: ServiceSession? { get } - func beginSession(session: ServiceSession) + func beginSession(_ session: ServiceSession) func endSession() } @@ -24,8 +24,8 @@ public protocol ServiceSessionHandler: class { public protocol ServiceSession: class { var isAuthenticated: Bool { get } - func attemptOpen(completion: (Void -> Bool)?) + func attemptOpen(_ completion: ((Void) -> Bool)?) func close() - func signURLRequest(request: NSMutableURLRequest) -> NSMutableURLRequest + func signURLRequest(_ request: NSMutableURLRequest) -> NSMutableURLRequest } diff --git a/HoratioDemo/HoratioDemo.xcodeproj/project.pbxproj b/HoratioDemo/HoratioDemo.xcodeproj/project.pbxproj index 1e22611..7d51bcb 100644 --- a/HoratioDemo/HoratioDemo.xcodeproj/project.pbxproj +++ b/HoratioDemo/HoratioDemo.xcodeproj/project.pbxproj @@ -192,10 +192,10 @@ EDB09D1E1D85BD25000FC309 = { isa = PBXGroup; children = ( - EDB09D5B1D85BF19000FC309 /* Vendor */, EDB09D291D85BD25000FC309 /* HoratioDemo */, EDB09D411D85BD26000FC309 /* HoratioDemoTests */, EDB09D4C1D85BD26000FC309 /* HoratioDemoUITests */, + EDB09D5B1D85BF19000FC309 /* Vendor */, EDB09D281D85BD25000FC309 /* Products */, ); sourceTree = ""; @@ -456,17 +456,20 @@ EDB09D261D85BD25000FC309 = { CreatedOnToolsVersion = 8.0; DevelopmentTeam = 46RFK4MJ8P; + LastSwiftMigration = 0800; ProvisioningStyle = Automatic; }; EDB09D3D1D85BD26000FC309 = { CreatedOnToolsVersion = 8.0; DevelopmentTeam = 46RFK4MJ8P; + LastSwiftMigration = 0800; ProvisioningStyle = Automatic; TestTargetID = EDB09D261D85BD25000FC309; }; EDB09D481D85BD26000FC309 = { CreatedOnToolsVersion = 8.0; DevelopmentTeam = 46RFK4MJ8P; + LastSwiftMigration = 0800; ProvisioningStyle = Automatic; TestTargetID = EDB09D261D85BD25000FC309; }; @@ -741,7 +744,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.mudpotapps.HoratioDemo; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -754,7 +757,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.mudpotapps.HoratioDemo; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -768,7 +771,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.mudpotapps.HoratioDemoTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HoratioDemo.app/HoratioDemo"; }; name = Debug; @@ -783,7 +786,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.mudpotapps.HoratioDemoTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HoratioDemo.app/HoratioDemo"; }; name = Release; @@ -797,7 +800,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.mudpotapps.HoratioDemoUITests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; TEST_TARGET_NAME = HoratioDemo; }; name = Debug; @@ -811,7 +814,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.mudpotapps.HoratioDemoUITests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; TEST_TARGET_NAME = HoratioDemo; }; name = Release; diff --git a/HoratioDemo/HoratioDemo.xcodeproj/project.xcworkspace/xcuserdata/ktatroe.xcuserdatad/UserInterfaceState.xcuserstate b/HoratioDemo/HoratioDemo.xcodeproj/project.xcworkspace/xcuserdata/ktatroe.xcuserdatad/UserInterfaceState.xcuserstate index 1d1938c0a1275d2fdfb32cfb62a9d6a6b25b0141..b97582f01e96bff6d082de4391f64b7106f17a94 100644 GIT binary patch literal 45120 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 i%Js$%8tvF8%crJl<@H+XLL-0Hc_bC>5H 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 M|M>;{GnvW%2b3E{x&QzG diff --git a/HoratioDemo/HoratioDemo/AppDelegate.swift b/HoratioDemo/HoratioDemo/AppDelegate.swift index 62418f1..100f275 100644 --- a/HoratioDemo/HoratioDemo/AppDelegate.swift +++ b/HoratioDemo/HoratioDemo/AppDelegate.swift @@ -51,7 +51,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { error conditions that could cause the creation of the store to fail. */ let container = NSPersistentContainer(name: "HoratioDemo") - container.loadPersistentStoresWithCompletionHandler() { (storeDescription, error) in + container.loadPersistentStores() { (storeDescription, error) in if let error = error as NSError? { // Replace this implementation with code to handle the error appropriately. // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. diff --git a/HoratioDemo/HoratioDemoTests/HoratioDemoTests.swift b/HoratioDemo/HoratioDemoTests/HoratioDemoTests.swift index 755b31b..2612d31 100644 --- a/HoratioDemo/HoratioDemoTests/HoratioDemoTests.swift +++ b/HoratioDemo/HoratioDemoTests/HoratioDemoTests.swift @@ -28,9 +28,9 @@ class HoratioDemoTests: XCTestCase { func testPerformanceExample() { // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } +// self.measure { +// // Put the code you want to measure the time of here. +// } } } From 4876df7a3758f918be6600d6bfadeab5886b3422 Mon Sep 17 00:00:00 2001 From: "k.tatroe" Date: Mon, 31 Oct 2016 11:16:23 -0600 Subject: [PATCH 02/14] More Swift 3 updates. --- .../UIUserNotifications+Operations.swift | 10 ++++++---- .../UserNotificationCondition.swift | 14 ++++++++------ Horatio/Scheduler/TaskScheduler.swift | 2 +- Horatio/Services/ServiceRequest.swift | 2 +- .../HoratioDemo.xcodeproj/project.pbxproj | 8 +++----- .../UserInterfaceState.xcuserstate | Bin 45120 -> 43969 bytes .../xcschemes/HoratioDemo.xcscheme | 2 +- 7 files changed, 20 insertions(+), 18 deletions(-) diff --git a/Horatio/Operations/UIUserNotifications+Operations.swift b/Horatio/Operations/UIUserNotifications+Operations.swift index d3611f3..abfd072 100644 --- a/Horatio/Operations/UIUserNotifications+Operations.swift +++ b/Horatio/Operations/UIUserNotifications+Operations.swift @@ -9,10 +9,12 @@ A convenient extension to UIKit.UIUserNotificationSettings. #if os(iOS) import UIKit + import UserNotifications -extension UIUserNotificationSettings { + +extension UNNotificationSettings { /// Check to see if one Settings object is a superset of another Settings object. - func contains(_ settings: UIUserNotificationSettings) -> Bool { + func contains(_ settings: UNNotificationSettings) -> Bool { // our types must contain all of the other types if !types.contains(settings.types) { return false @@ -28,7 +30,7 @@ extension UIUserNotificationSettings { Merge two Settings objects together. `UIUserNotificationCategories` with the same identifier are considered equal. */ - func settingsByMerging(_ settings: UIUserNotificationSettings) -> UIUserNotificationSettings { + func settingsByMerging(_ settings: UNNotificationSettings) -> UNNotificationSettings { let mergedTypes = types.union(settings.types) let myCategories = categories ?? [] @@ -42,7 +44,7 @@ extension UIUserNotificationSettings { } let mergedCategories = Set(existingCategoriesByIdentifier.values) - return UIUserNotificationSettings(types: mergedTypes, categories: mergedCategories) + return UNNotificationSettings(types: mergedTypes, categories: mergedCategories) } } diff --git a/Horatio/Operations/UserNotificationCondition.swift b/Horatio/Operations/UserNotificationCondition.swift index 9ccf022..380e6aa 100644 --- a/Horatio/Operations/UserNotificationCondition.swift +++ b/Horatio/Operations/UserNotificationCondition.swift @@ -9,7 +9,9 @@ This file shows an example of implementing the OperationCondition protocol. #if os(iOS) import UIKit - +import UserNotifications + + /** A condition for verifying that we can present alerts to the user via `UILocalNotification` and/or remote notifications. @@ -29,7 +31,7 @@ public struct UserNotificationCondition: OperationCondition { public static let desiredSettings = "DesiredUserNotificationSettigns" public static let isMutuallyExclusive = false - let settings: UIUserNotificationSettings + let settings: UNNotificationSettings let application: UIApplication let behavior: Behavior @@ -48,7 +50,7 @@ public struct UserNotificationCondition: OperationCondition { `application`. You may also specify `.Replace`, which means the `settings` will overwrite the exisiting settings. */ - public init(settings: UIUserNotificationSettings, application: UIApplication, behavior: Behavior = .merge) { + public init(settings: UNNotificationSettings, application: UIApplication, behavior: Behavior = .merge) { self.settings = settings self.application = application self.behavior = behavior @@ -86,11 +88,11 @@ public struct UserNotificationCondition: OperationCondition { object with a `UIApplication`, prompting the user for permission if necessary. */ private class UserNotificationPermissionOperation: Operation { - let settings: UIUserNotificationSettings + let settings: UNNotificationSettings let application: UIApplication let behavior: UserNotificationCondition.Behavior - init(settings: UIUserNotificationSettings, application: UIApplication, behavior: UserNotificationCondition.Behavior) { + init(settings: UNNotificationSettings, application: UIApplication, behavior: UserNotificationCondition.Behavior) { self.settings = settings self.application = application self.behavior = behavior @@ -104,7 +106,7 @@ private class UserNotificationPermissionOperation: Operation { DispatchQueue.main.async { let current = self.application.currentUserNotificationSettings - let settingsToRegister: UIUserNotificationSettings + let settingsToRegister: UNNotificationSettings switch (current, self.behavior) { case (let currentSettings?, .merge): diff --git a/Horatio/Scheduler/TaskScheduler.swift b/Horatio/Scheduler/TaskScheduler.swift index f37ca83..34caee9 100644 --- a/Horatio/Scheduler/TaskScheduler.swift +++ b/Horatio/Scheduler/TaskScheduler.swift @@ -101,7 +101,7 @@ class TimedTaskCoordinator : ScheduledTaskCoordinator { @objc fileprivate func timerFired(_ timer: Foundation.Timer) { - DispatchQueue.global(priority: DispatchQueue.GlobalQueuePriority.default).async { + DispatchQueue.global(qos: .default).async { self.scheduleTasks() } } diff --git a/Horatio/Services/ServiceRequest.swift b/Horatio/Services/ServiceRequest.swift index 0e085c4..2282ccf 100644 --- a/Horatio/Services/ServiceRequest.swift +++ b/Horatio/Services/ServiceRequest.swift @@ -135,7 +135,7 @@ public struct ServiceRequest { } if let session = session { - session.signURLRequest(request) + request = session.signURLRequest(request) } return request as URLRequest diff --git a/HoratioDemo/HoratioDemo.xcodeproj/project.pbxproj b/HoratioDemo/HoratioDemo.xcodeproj/project.pbxproj index 7d51bcb..9629044 100644 --- a/HoratioDemo/HoratioDemo.xcodeproj/project.pbxproj +++ b/HoratioDemo/HoratioDemo.xcodeproj/project.pbxproj @@ -56,9 +56,7 @@ EDB09DED1D85BF34000FC309 /* RemoteNotificationCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB09D981D85BF34000FC309 /* RemoteNotificationCondition.swift */; }; EDB09DEE1D85BF34000FC309 /* SilentCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB09D991D85BF34000FC309 /* SilentCondition.swift */; }; EDB09DEF1D85BF34000FC309 /* TimeoutObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB09D9A1D85BF34000FC309 /* TimeoutObserver.swift */; }; - EDB09DF01D85BF34000FC309 /* UIUserNotifications+Operations.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB09D9B1D85BF34000FC309 /* UIUserNotifications+Operations.swift */; }; EDB09DF11D85BF34000FC309 /* URLSessionTaskOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB09D9C1D85BF34000FC309 /* URLSessionTaskOperation.swift */; }; - EDB09DF21D85BF34000FC309 /* UserNotificationCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB09D9D1D85BF34000FC309 /* UserNotificationCondition.swift */; }; EDB09DF91D85BF34000FC309 /* TaskScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB09DA61D85BF34000FC309 /* TaskScheduler.swift */; }; EDB09DFB1D85BF34000FC309 /* Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB09DA91D85BF34000FC309 /* Service.swift */; }; EDB09DFC1D85BF34000FC309 /* ServiceEndpoint+JSONParsing.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB09DAA1D85BF34000FC309 /* ServiceEndpoint+JSONParsing.swift */; }; @@ -450,7 +448,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0800; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 0810; ORGANIZATIONNAME = "Mudpot Apps"; TargetAttributes = { EDB09D261D85BD25000FC309 = { @@ -577,9 +575,7 @@ EDB09DDC1D85BF34000FC309 /* LocationOperation.swift in Sources */, EDB09DE01D85BF34000FC309 /* NoCancelledDependencies.swift in Sources */, EDB09DCA1D85BF34000FC309 /* VendorIDFeatureSubject.swift in Sources */, - EDB09DF01D85BF34000FC309 /* UIUserNotifications+Operations.swift in Sources */, EDB09DC91D85BF34000FC309 /* FeatureSubject.swift in Sources */, - EDB09DF21D85BF34000FC309 /* UserNotificationCondition.swift in Sources */, EDB09DE21D85BF34000FC309 /* NSObject+ThrowingKeyValueObserving.m in Sources */, EDB09DEE1D85BF34000FC309 /* SilentCondition.swift in Sources */, EDB09DD61D85BF34000FC309 /* Dictionary+Operations.swift in Sources */, @@ -658,6 +654,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -709,6 +706,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; diff --git a/HoratioDemo/HoratioDemo.xcodeproj/project.xcworkspace/xcuserdata/ktatroe.xcuserdatad/UserInterfaceState.xcuserstate b/HoratioDemo/HoratioDemo.xcodeproj/project.xcworkspace/xcuserdata/ktatroe.xcuserdatad/UserInterfaceState.xcuserstate index b97582f01e96bff6d082de4391f64b7106f17a94..07fcc45b3cf120b529e89b2998ecbf7b9f6dc64c 100644 GIT binary patch literal 43969 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 Date: Mon, 21 Nov 2016 14:31:15 -0700 Subject: [PATCH 03/14] Several small changes made to Marty Horatio --- Horatio/JSON/JSONParsing.swift | 16 ++++++--- .../DependencySuccessCondition.swift | 33 +++++++++++++++++++ Horatio/Operations/Operation.swift | 12 ++++++- Horatio/Scheduler/TaskScheduler.swift | 16 +++++---- .../Services/ServiceRequestOperation.swift | 25 ++++++++++++-- 5 files changed, 87 insertions(+), 15 deletions(-) create mode 100644 Horatio/Operations/DependencySuccessCondition.swift diff --git a/Horatio/JSON/JSONParsing.swift b/Horatio/JSON/JSONParsing.swift index 880aad1..7d73115 100644 --- a/Horatio/JSON/JSONParsing.swift +++ b/Horatio/JSON/JSONParsing.swift @@ -32,17 +32,23 @@ public struct JSONParsingOptions: OptionSet { types and missing values. */ open class JSONParser { - open static func parseIdentifier(_ value: AnyObject?, options: JSONParsingOptions = .none) -> String? { - if let stringValue = JSONParser.parseString(value) { + open static func parseIdentifier(_ value: AnyObject?, ignoreDefault defaultToIgnore: String? = nil, options: JSONParsingOptions = .none) -> String? { + if let stringValue = JSONParser.parseString(value, ignoreDefault: defaultToIgnore, options: options) { return stringValue.lowercased() } return nil } - - open static func parseString(_ value: AnyObject?, options: JSONParsingOptions = .none) -> String? { + + open static func parseString(_ value: AnyObject?, ignoreDefault defaultToIgnore: String? = nil, options: JSONParsingOptions = .none) -> String? { if let stringValue = value as? String { - return stringValue.stringByDecodingJavascriptEntities() + let decodedString = stringValue.stringByDecodingJavascriptEntities() + + if defaultToIgnore == decodedString { + return nil + } + + return decodedString } if options.contains(.allowConversion) { diff --git a/Horatio/Operations/DependencySuccessCondition.swift b/Horatio/Operations/DependencySuccessCondition.swift new file mode 100644 index 0000000..f08007a --- /dev/null +++ b/Horatio/Operations/DependencySuccessCondition.swift @@ -0,0 +1,33 @@ +// +// Copyright © 2016 Kevin Tatroe. All rights reserved. +// See LICENSE.txt for this sample’s licensing information + +import Foundation + +/// A condition that requires all dependencies to have finished without reporting an error. +public struct DependencySuccessCondition: OperationCondition { + + static let name = "DependencySuccess" + static let isMutuallyExclusive = false + + init() { } + + func dependencyForOperation(_ operation: Operation) -> Foundation.Operation? { + return nil + } + + func evaluateForOperation(_ operation: Operation, completion: (OperationConditionResult) -> Void) { + for dependency in operation.dependencies { + if let fallibleDependency = dependency as? Operation, fallibleDependency.failed { + let error = NSError(code: .conditionFailed, userInfo: [ + OperationConditionKey: type(of: self).name + ]) + + completion(.failed(error)) + return + } + } + + completion(.satisfied) + } +} diff --git a/Horatio/Operations/Operation.swift b/Horatio/Operations/Operation.swift index 5937186..044ed1f 100644 --- a/Horatio/Operations/Operation.swift +++ b/Horatio/Operations/Operation.swift @@ -188,7 +188,7 @@ open class Operation: Foundation.Operation { override final public func start() { if let name = self.name { - print(name + " started") + print("\(name) started") } assert(state == .ready, "This operation must be performed on an operation queue.") @@ -266,6 +266,16 @@ open class Operation: Foundation.Operation { state = .finishing let combinedErrors = _internalErrors + errors + let failed = !combinedErrors.isEmpty + + if let name = name { + if failed { + print("\(name) failed due to errors") + } else { + print("\(name) finished") + } + } + finished(combinedErrors) for observer in observers { diff --git a/Horatio/Scheduler/TaskScheduler.swift b/Horatio/Scheduler/TaskScheduler.swift index 34caee9..62aaf1a 100644 --- a/Horatio/Scheduler/TaskScheduler.swift +++ b/Horatio/Scheduler/TaskScheduler.swift @@ -25,7 +25,7 @@ public protocol ScheduledTaskCoordinator { class TimedTaskCoordinator : ScheduledTaskCoordinator { struct Behaviors { - static let TimerInterval: TimeInterval = 10.0 + static let timerInterval: TimeInterval = 10.0 } var providers = [ScheduledTaskProvider]() @@ -61,12 +61,14 @@ class TimedTaskCoordinator : ScheduledTaskCoordinator { func resume() { isActive = true - if updateTimer == nil { - updateTimer = Foundation.Timer.scheduledTimer(timeInterval: Behaviors.TimerInterval, target: self, selector: #selector(timerFired), userInfo: nil, repeats: true) - } - - if let updateTimer = updateTimer { - updateTimer.fire() + DispatchQueue.main.async { + if self.updateTimer == nil { + self.updateTimer = Foundation.Timer.scheduledTimer(timeInterval: Behaviors.timerInterval, target: self, selector: #selector(self.timerFired), userInfo: nil, repeats: true) + } + + if let updateTimer = self.updateTimer { + updateTimer.fire() + } } } diff --git a/Horatio/Services/ServiceRequestOperation.swift b/Horatio/Services/ServiceRequestOperation.swift index 26763f2..48b65e5 100644 --- a/Horatio/Services/ServiceRequestOperation.swift +++ b/Horatio/Services/ServiceRequestOperation.swift @@ -33,6 +33,7 @@ open class FetchServiceResponseOperation: GroupOperation { parseOperation = ProcessServiceResponseOperation(request: request, responseProcessor: responseProcessor, cacheFile: cacheFile) parseOperation.addDependency(downloadOperation) + parseOperation.addCondition(DependencySuccessCondition()) super.init(operations: [downloadOperation, parseOperation]) @@ -43,8 +44,7 @@ open class FetchServiceResponseOperation: GroupOperation { // MARK: - Private fileprivate static func randomCacheFileName() -> String { - // TODO: use guid or something similar - return "cacheFile" + return UUID().uuidString } } @@ -110,6 +110,25 @@ open class DownloadServiceResponseOperation: GroupOperation { } } +open struct ProcessServiceResponseErrors { + enum ErrorTypes: Error { + case notProcessed + } + + static let domain = "ProcessServiceResponseErrors" + + struct Codes { + static let unProcessed = 0 + } + + static func errorForType(_ type: ErrorTypes) -> NSError { + switch type { + case .notProcessed: + return NSError(domain: domain, code: Codes.unProcessed, userInfo: nil) + } + } +} + /** Uses a provided `ServiceResponseProcessor` to process a response downloaded @@ -163,6 +182,8 @@ open class ProcessServiceResponseOperation: Operation { self.finish() return } + + self.finishWithError(ProcessServiceResponseErrors.errorForType(.notProcessed)) case .error(let error): self.finishWithError(error) From eae45b78420b94aefa9ad57dcba6e5259d7e1747 Mon Sep 17 00:00:00 2001 From: Alex Turner Date: Tue, 22 Nov 2016 09:55:52 -0700 Subject: [PATCH 04/14] Fixes an issue with trying to present while another VC was already presented on the rootVC. --- Horatio/Operations/AlertOperation.swift | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Horatio/Operations/AlertOperation.swift b/Horatio/Operations/AlertOperation.swift index 5442b46..014198f 100644 --- a/Horatio/Operations/AlertOperation.swift +++ b/Horatio/Operations/AlertOperation.swift @@ -38,8 +38,7 @@ class AlertOperation: Operation { // MARK: Initialization init(presentationContext: UIViewController? = nil) { - self.presentationContext = presentationContext ?? UIApplication.shared.keyWindow?.rootViewController - + self.presentationContext = presentationContext super.init() addCondition(AlertPresentation()) @@ -65,18 +64,24 @@ class AlertOperation: Operation { } override func execute() { - guard let presentationContext = presentationContext else { - finish() - - return + var presentationViewController: UIViewController? + + if let presentationContext = presentationContext { + presentationViewController = presentationContext + } else { + presentationViewController = UIApplication.shared.keyWindow?.rootViewController + + while let presentedVC = presentationViewController?.presentedViewController { + presentationViewController = presentedVC + } } DispatchQueue.main.async { if self.alertController.actions.isEmpty { self.addAction("OK") } - - presentationContext.present(self.alertController, animated: true, completion: nil) + + presentationViewController?.present(self.alertController, animated: true, completion: nil) } } } From d56286767e3512ca33bb1f667bc31962ad8cfa85 Mon Sep 17 00:00:00 2001 From: "k.tatroe" Date: Tue, 22 Nov 2016 11:11:10 -0700 Subject: [PATCH 05/14] Fix double-encoding of parameters. --- .../Services/ServiceRequestDecorator.swift | 3 +-- .../UserInterfaceState.xcuserstate | Bin 43969 -> 43861 bytes 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Horatio/Services/ServiceRequestDecorator.swift b/Horatio/Services/ServiceRequestDecorator.swift index 62d294e..d3ca975 100644 --- a/Horatio/Services/ServiceRequestDecorator.swift +++ b/Horatio/Services/ServiceRequestDecorator.swift @@ -100,8 +100,7 @@ internal extension URL { guard var components = URLComponents(url: self, resolvingAgainstBaseURL: false) else { return self } for (key, value) in parameters { - let encodedValue = value.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) - let queryItem = URLQueryItem(name: key, value: encodedValue) + let queryItem = URLQueryItem(name: key, value: value) if let _ = components.queryItems { components.queryItems?.append(queryItem) diff --git a/HoratioDemo/HoratioDemo.xcodeproj/project.xcworkspace/xcuserdata/ktatroe.xcuserdatad/UserInterfaceState.xcuserstate b/HoratioDemo/HoratioDemo.xcodeproj/project.xcworkspace/xcuserdata/ktatroe.xcuserdatad/UserInterfaceState.xcuserstate index 07fcc45b3cf120b529e89b2998ecbf7b9f6dc64c..cae1b160901795b4b71cbf3d53ac696999e75cc4 100644 GIT binary patch literal 43861 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 Date: Tue, 22 Nov 2016 11:26:06 -0700 Subject: [PATCH 06/14] Upper camel cased static TimerInterval --- Horatio/Scheduler/TaskScheduler.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Horatio/Scheduler/TaskScheduler.swift b/Horatio/Scheduler/TaskScheduler.swift index 62aaf1a..9bbe2db 100644 --- a/Horatio/Scheduler/TaskScheduler.swift +++ b/Horatio/Scheduler/TaskScheduler.swift @@ -25,7 +25,7 @@ public protocol ScheduledTaskCoordinator { class TimedTaskCoordinator : ScheduledTaskCoordinator { struct Behaviors { - static let timerInterval: TimeInterval = 10.0 + static let TimerInterval: TimeInterval = 10.0 } var providers = [ScheduledTaskProvider]() @@ -63,7 +63,7 @@ class TimedTaskCoordinator : ScheduledTaskCoordinator { DispatchQueue.main.async { if self.updateTimer == nil { - self.updateTimer = Foundation.Timer.scheduledTimer(timeInterval: Behaviors.timerInterval, target: self, selector: #selector(self.timerFired), userInfo: nil, repeats: true) + self.updateTimer = Foundation.Timer.scheduledTimer(timeInterval: Behaviors.TimerInterval, target: self, selector: #selector(self.timerFired), userInfo: nil, repeats: true) } if let updateTimer = self.updateTimer { From 6bc1a63cfeb3d7d16d94cd1a0a69438897e70056 Mon Sep 17 00:00:00 2001 From: Alex Turner Date: Tue, 22 Nov 2016 11:36:28 -0700 Subject: [PATCH 07/14] Removed ignoreDefault option in JSONParser --- Horatio/JSON/JSONParsing.swift | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Horatio/JSON/JSONParsing.swift b/Horatio/JSON/JSONParsing.swift index 7d73115..c51478d 100644 --- a/Horatio/JSON/JSONParsing.swift +++ b/Horatio/JSON/JSONParsing.swift @@ -32,23 +32,17 @@ public struct JSONParsingOptions: OptionSet { types and missing values. */ open class JSONParser { - open static func parseIdentifier(_ value: AnyObject?, ignoreDefault defaultToIgnore: String? = nil, options: JSONParsingOptions = .none) -> String? { - if let stringValue = JSONParser.parseString(value, ignoreDefault: defaultToIgnore, options: options) { + open static func parseIdentifier(_ value: AnyObject?, options: JSONParsingOptions = .none) -> String? { + if let stringValue = JSONParser.parseString(value, options: options) { return stringValue.lowercased() } return nil } - open static func parseString(_ value: AnyObject?, ignoreDefault defaultToIgnore: String? = nil, options: JSONParsingOptions = .none) -> String? { + open static func parseString(_ value: AnyObject?, options: JSONParsingOptions = .none) -> String? { if let stringValue = value as? String { - let decodedString = stringValue.stringByDecodingJavascriptEntities() - - if defaultToIgnore == decodedString { - return nil - } - - return decodedString + return stringValue.stringByDecodingJavascriptEntities() } if options.contains(.allowConversion) { From daf73d0babc298c576386a7e1223db94952fb42c Mon Sep 17 00:00:00 2001 From: Alex Turner Date: Tue, 22 Nov 2016 11:38:20 -0700 Subject: [PATCH 08/14] Renamed processing code --- Horatio/Services/ServiceRequestOperation.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Horatio/Services/ServiceRequestOperation.swift b/Horatio/Services/ServiceRequestOperation.swift index 48b65e5..4102b94 100644 --- a/Horatio/Services/ServiceRequestOperation.swift +++ b/Horatio/Services/ServiceRequestOperation.swift @@ -118,13 +118,13 @@ open struct ProcessServiceResponseErrors { static let domain = "ProcessServiceResponseErrors" struct Codes { - static let unProcessed = 0 + static let notProcessed = 0 } static func errorForType(_ type: ErrorTypes) -> NSError { switch type { case .notProcessed: - return NSError(domain: domain, code: Codes.unProcessed, userInfo: nil) + return NSError(domain: domain, code: Codes.notProcessed, userInfo: nil) } } } From 7162c193e3c2f2cb49f8b9d495cf16c1c7c095bb Mon Sep 17 00:00:00 2001 From: Alex Turner Date: Tue, 22 Nov 2016 11:39:58 -0700 Subject: [PATCH 09/14] Restored JSONParser fully --- Horatio/JSON/JSONParsing.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Horatio/JSON/JSONParsing.swift b/Horatio/JSON/JSONParsing.swift index c51478d..880aad1 100644 --- a/Horatio/JSON/JSONParsing.swift +++ b/Horatio/JSON/JSONParsing.swift @@ -33,13 +33,13 @@ public struct JSONParsingOptions: OptionSet { */ open class JSONParser { open static func parseIdentifier(_ value: AnyObject?, options: JSONParsingOptions = .none) -> String? { - if let stringValue = JSONParser.parseString(value, options: options) { + if let stringValue = JSONParser.parseString(value) { return stringValue.lowercased() } return nil } - + open static func parseString(_ value: AnyObject?, options: JSONParsingOptions = .none) -> String? { if let stringValue = value as? String { return stringValue.stringByDecodingJavascriptEntities() From 6fd6e251d4d708dae8e95e0dfa2d7ef7305a98da Mon Sep 17 00:00:00 2001 From: Alex Turner Date: Tue, 22 Nov 2016 11:49:32 -0700 Subject: [PATCH 10/14] Removed space before comma --- Horatio/Operations/LocationOperation.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Horatio/Operations/LocationOperation.swift b/Horatio/Operations/LocationOperation.swift index ecc9900..2283a62 100644 --- a/Horatio/Operations/LocationOperation.swift +++ b/Horatio/Operations/LocationOperation.swift @@ -62,7 +62,7 @@ open class LocationOperation: Operation, CLLocationManagerDelegate { // MARK: CLLocationManagerDelegate open func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { - if let location = locations.last , location.horizontalAccuracy <= accuracy { + if let location = locations.last, location.horizontalAccuracy <= accuracy { stopLocationUpdates() handler(location) finish() From d2e93227c4612979d728866180ac5692d5c96d93 Mon Sep 17 00:00:00 2001 From: "k.tatroe" Date: Tue, 22 Nov 2016 12:05:08 -0700 Subject: [PATCH 11/14] New operation (baselined from original source). --- Horatio/Operations/Operation.swift | 385 ++++++++++-------- .../UserInterfaceState.xcuserstate | Bin 43861 -> 43499 bytes 2 files changed, 210 insertions(+), 175 deletions(-) diff --git a/Horatio/Operations/Operation.swift b/Horatio/Operations/Operation.swift index 5937186..22ecaac 100644 --- a/Horatio/Operations/Operation.swift +++ b/Horatio/Operations/Operation.swift @@ -1,313 +1,348 @@ /* -Copyright (C) 2015 Apple Inc. All Rights Reserved. -See LICENSE.txt for this sample’s licensing information - -Abstract: -This file contains the foundational subclass of NSOperation. -*/ + Copyright (C) 2015 Apple Inc. All Rights Reserved. + See LICENSE.txt for this sample’s licensing information + + Abstract: + This file contains the foundational subclass of NSOperation. + */ import Foundation /** - The subclass of `NSOperation` from which all other operations should be derived. - This class adds both Conditions and Observers, which allow the operation to define - extended readiness requirements, as well as notify many interested parties - about interesting operation state changes -*/ + The subclass of `NSOperation` from which all other operations should be derived. + This class adds both Conditions and Observers, which allow the operation to define + extended readiness requirements, as well as notify many interested parties + about interesting operation state changes + */ open class Operation: Foundation.Operation { - + // use the KVO mechanism to indicate that changes to "state" affect other properties as well class func keyPathsForValuesAffectingIsReady() -> Set { return ["state" as NSObject] } - + class func keyPathsForValuesAffectingIsExecuting() -> Set { return ["state" as NSObject] } - + class func keyPathsForValuesAffectingIsFinished() -> Set { return ["state" as NSObject] } - - class func keyPathsForValuesAffectingIsCancelled() -> Set { - return ["state" as NSObject] - } - + // MARK: State Management - + fileprivate enum State: Int, Comparable { /// The initial state of an `Operation`. case initialized - + /// The `Operation` is ready to begin evaluating conditions. case pending - + /// The `Operation` is evaluating conditions. case evaluatingConditions - + /** - The `Operation`'s conditions have all been satisfied, and it is ready - to execute. - */ + The `Operation`'s conditions have all been satisfied, and it is ready + to execute. + */ case ready - + /// The `Operation` is executing. case executing - + /** - Execution of the `Operation` has finished, but it has not yet notified - the queue of this. - */ + Execution of the `Operation` has finished, but it has not yet notified + the queue of this. + */ case finishing - + /// The `Operation` has finished executing. case finished - - /// The `Operation` has been cancelled. - case cancelled + + func canTransitionToState(_ target: State) -> Bool { + switch (self, target) { + case (.initialized, .pending): + return true + case (.pending, .evaluatingConditions): + return true + case (.evaluatingConditions, .ready): + return true + case (.ready, .executing): + return true + case (.ready, .finishing): + return true + case (.executing, .finishing): + return true + case (.finishing, .finished): + return true + default: + return false + } + } } - + /** - Indicates that the Operation can now begin to evaluate readiness conditions, - if appropriate. - */ + Indicates that the Operation can now begin to evaluate readiness conditions, + if appropriate. + */ func willEnqueue() { state = .pending } - + /// Private storage for the `state` property that will be KVO observed. fileprivate var _state = State.initialized - + + /// A lock to guard reads and writes to the `_state` property + fileprivate let stateLock = NSLock() + fileprivate var state: State { get { - return _state + return stateLock.withCriticalScope { + _state + } } - + set(newState) { - // Manually fire the KVO notifications for state change, since this is "private". - + /* + It's important to note that the KVO notifications are NOT called from inside + the lock. If they were, the app would deadlock, because in the middle of + calling the `didChangeValueForKey()` method, the observers try to access + properties like "isReady" or "isFinished". Since those methods also + acquire the lock, then we'd be stuck waiting on our own lock. It's the + classic definition of deadlock. + */ willChangeValue(forKey: "state") - - switch (_state, newState) { - case (.cancelled, _): - break // cannot leave the cancelled state - case (.finished, _): - break // cannot leave the finished state - default: - assert(_state != newState, "Performing invalid cyclic state transition.") - _state = newState + + stateLock.withCriticalScope { Void -> Void in + guard _state != .finished else { + return + } + + assert(_state.canTransitionToState(newState), "Performing invalid state transition.") + _state = newState } - + didChangeValue(forKey: "state") } } - + // Here is where we extend our definition of "readiness". override open var isReady: Bool { switch state { - case .pending: - if super.isReady { - evaluateConditions() - } - - return false - - case .ready: - return super.isReady - - default: - return false + + case .initialized: + // If the operation has been cancelled, "isReady" should return true + return isCancelled + + case .pending: + // If the operation has been cancelled, "isReady" should return true + guard !isCancelled else { + return true + } + + // If super isReady, conditions can be evaluated + if super.isReady { + evaluateConditions() + } + + // Until conditions have been evaluated, "isReady" returns false + return false + + case .ready: + return super.isReady || isCancelled + + default: + return false } } - - open var userInitiated: Bool { + + var userInitiated: Bool { get { return qualityOfService == .userInitiated } - + set { assert(state < .executing, "Cannot modify userInitiated after execution has begun.") - + qualityOfService = newValue ? .userInitiated : .default } } - + override open var isExecuting: Bool { return state == .executing } - + override open var isFinished: Bool { return state == .finished } - - override open var isCancelled: Bool { - return state == .cancelled - } - + fileprivate func evaluateConditions() { - assert(state == .pending, "evaluateConditions() was called out-of-order") - + assert(state == .pending && !isCancelled, "evaluateConditions() was called out-of-order") + state = .evaluatingConditions - + OperationConditionEvaluator.evaluate(conditions, operation: self) { failures in - if failures.isEmpty { - // If there were no errors, we may proceed. - self.state = .ready - } else { - self.state = .cancelled - self.finish(failures) - } + self._internalErrors.append(contentsOf: failures) + self.state = .ready } } - + // MARK: Observers and Conditions - + fileprivate(set) var conditions = [OperationCondition]() - - open func addCondition(_ condition: OperationCondition) { + + func addCondition(_ condition: OperationCondition) { assert(state < .evaluatingConditions, "Cannot modify conditions after execution has begun.") - + conditions.append(condition) } - + fileprivate(set) var observers = [OperationObserver]() - - open func addObserver(_ observer: OperationObserver) { + + func addObserver(_ observer: OperationObserver) { assert(state < .executing, "Cannot modify observers after execution has begun.") - + observers.append(observer) } - + override open func addDependency(_ operation: Foundation.Operation) { - assert(state <= .executing, "Dependencies cannot be modified after execution has begun.") - + assert(state < .executing, "Dependencies cannot be modified after execution has begun.") + super.addDependency(operation) } - + // MARK: Execution and Cancellation - + override final public func start() { - if let name = self.name { - print(name + " started") + // NSOperation.start() contains important logic that shouldn't be bypassed. + super.start() + + // If the operation has been cancelled, we still need to enter the "Finished" state. + if isCancelled { + finish() } - + } + + override final public func main() { assert(state == .ready, "This operation must be performed on an operation queue.") - - state = .executing - - for observer in observers { - observer.operationDidStart(self) + + if _internalErrors.isEmpty && !isCancelled { + state = .executing + + for observer in observers { + observer.operationDidStart(self) + } + + execute() + } + else { + finish() } - - execute() } - + /** - `execute()` is the entry point of execution for all `Operation` subclasses. - If you subclass `Operation` and wish to customize its execution, you would - do so by overriding the `execute()` method. - - At some point, your `Operation` subclass must call one of the "finish" - methods defined below; this is how you indicate that your operation has - finished its execution, and that operations dependent on yours can re-evaluate - their readiness state. - */ - open func execute() { + `execute()` is the entry point of execution for all `Operation` subclasses. + If you subclass `Operation` and wish to customize its execution, you would + do so by overriding the `execute()` method. + + At some point, your `Operation` subclass must call one of the "finish" + methods defined below; this is how you indicate that your operation has + finished its execution, and that operations dependent on yours can re-evaluate + their readiness state. + */ + func execute() { print("\(type(of: self)) must override `execute()`.") - + finish() } - + fileprivate var _internalErrors = [NSError]() - override open func cancel() { - cancelWithError() - } - - open func cancelWithError(_ error: NSError? = nil) { + func cancelWithError(_ error: NSError? = nil) { if let error = error { _internalErrors.append(error) } - - state = .cancelled + + cancel() } - + final func produceOperation(_ operation: Foundation.Operation) { for observer in observers { observer.operation(self, didProduceOperation: operation) } } - + // MARK: Finishing - + /** - Most operations may finish with a single error, if they have one at all. - This is a convenience method to simplify calling the actual `finish()` - method. This is also useful if you wish to finish with an error provided - by the system frameworks. As an example, see `DownloadEarthquakesOperation` - for how an error from an `NSURLSession` is passed along via the - `finishWithError()` method. - */ - final public func finishWithError(_ error: NSError?) { + Most operations may finish with a single error, if they have one at all. + This is a convenience method to simplify calling the actual `finish()` + method. This is also useful if you wish to finish with an error provided + by the system frameworks. As an example, see `DownloadEarthquakesOperation` + for how an error from an `NSURLSession` is passed along via the + `finishWithError()` method. + */ + final func finishWithError(_ error: NSError?) { if let error = error { finish([error]) - } else { + } + else { finish() } } - + /** - A private property to ensure we only notify the observers once that the - operation has finished. - */ + A private property to ensure we only notify the observers once that the + operation has finished. + */ fileprivate var hasFinishedAlready = false - final public func finish(_ errors: [NSError] = []) { + final func finish(_ errors: [NSError] = []) { if !hasFinishedAlready { hasFinishedAlready = true state = .finishing - + let combinedErrors = _internalErrors + errors finished(combinedErrors) - + for observer in observers { observer.operationDidFinish(self, errors: combinedErrors) } - + state = .finished } } - + /** - Subclasses may override `finished(_:)` if they wish to react to the operation - finishing with errors. For example, the `LoadModelOperation` implements - this method to potentially inform the user about an error when trying to - bring up the Core Data stack. - */ - open func finished(_ errors: [NSError]) { + Subclasses may override `finished(_:)` if they wish to react to the operation + finishing with errors. For example, the `LoadModelOperation` implements + this method to potentially inform the user about an error when trying to + bring up the Core Data stack. + */ + func finished(_ errors: [NSError]) { // No op. } - - override open func waitUntilFinished() { + + override final public func waitUntilFinished() { /* - Waiting on operations is almost NEVER the right thing to do. It is - usually superior to use proper locking constructs, such as `dispatch_semaphore_t` - or `dispatch_group_notify`, or even `NSLocking` objects. Many developers - use waiting when they should instead be chaining discrete operations - together using dependencies. - - To reinforce this idea, invoking `waitUntilFinished()` will crash your - app, as incentive for you to find a more appropriate way to express - the behavior you're wishing to create. - */ + Waiting on operations is almost NEVER the right thing to do. It is + usually superior to use proper locking constructs, such as `dispatch_semaphore_t` + or `dispatch_group_notify`, or even `NSLocking` objects. Many developers + use waiting when they should instead be chaining discrete operations + together using dependencies. + + To reinforce this idea, invoking `waitUntilFinished()` will crash your + app, as incentive for you to find a more appropriate way to express + the behavior you're wishing to create. + */ fatalError("Waiting on operations is an anti-pattern. Remove this ONLY if you're absolutely sure there is No Other Way™.") } - + } // Simple operator functions to simplify the assertions used above. -private func < (lhs: Operation.State, rhs: Operation.State) -> Bool { +private func <(lhs: Operation.State, rhs: Operation.State) -> Bool { return lhs.rawValue < rhs.rawValue } -private func == (lhs: Operation.State, rhs: Operation.State) -> Bool { +private func ==(lhs: Operation.State, rhs: Operation.State) -> Bool { return lhs.rawValue == rhs.rawValue } diff --git a/HoratioDemo/HoratioDemo.xcodeproj/project.xcworkspace/xcuserdata/ktatroe.xcuserdatad/UserInterfaceState.xcuserstate b/HoratioDemo/HoratioDemo.xcodeproj/project.xcworkspace/xcuserdata/ktatroe.xcuserdatad/UserInterfaceState.xcuserstate index cae1b160901795b4b71cbf3d53ac696999e75cc4..f40ee029767d50e8c6c917d583a6371696efeee1 100644 GIT binary patch delta 22129 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 Q>8F~X0?iK&XZ*|m1J*gHH~;_u delta 22584 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 Date: Tue, 22 Nov 2016 13:36:17 -0700 Subject: [PATCH 12/14] Update. --- .../UserInterfaceState.xcuserstate | Bin 45865 -> 45749 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/HoratioDemo/HoratioDemo.xcodeproj/project.xcworkspace/xcuserdata/ktatroe.xcuserdatad/UserInterfaceState.xcuserstate b/HoratioDemo/HoratioDemo.xcodeproj/project.xcworkspace/xcuserdata/ktatroe.xcuserdatad/UserInterfaceState.xcuserstate index 3279da3f1733fd8de00bef65246d0d194f01b696..85cc015f2765e2c72916efd7cff5b586eb51a3d3 100644 GIT binary patch delta 20491 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 Ya+b|32kiwpj%z=KJG7sle$R6HKV=avZ2$lO delta 20467 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 Date: Wed, 30 Nov 2016 09:06:32 -0700 Subject: [PATCH 13/14] Further updates. --- Horatio/Container/Container.swift | 7 ++- Horatio/JSON/JSONParsing.swift | 30 ++++----- .../JSON/JSONServiceResponseProcessor.swift | 15 +++-- Horatio/Operations/BlockObserver.swift | 6 +- Horatio/Operations/BlockOperation.swift | 59 ++++++++++-------- Horatio/Operations/GroupOperation.swift | 27 +++++--- Horatio/Operations/NetworkObserver.swift | 8 +-- Horatio/Operations/Operation.swift | 12 ++-- Horatio/Operations/OperationCondition.swift | 6 +- Horatio/Operations/OperationObserver.swift | 2 +- Horatio/Operations/OperationQueue.swift | 2 +- Horatio/Operations/TimeoutObserver.swift | 2 +- .../UIUserNotifications+Operations.swift | 1 + .../UserNotificationCondition.swift | 2 + Horatio/Scheduler/TaskScheduler.swift | 2 +- Horatio/Services/ServiceRequest.swift | 2 +- .../Services/ServiceRequestOperation.swift | 2 +- .../UserInterfaceState.xcuserstate | Bin 45749 -> 46275 bytes 18 files changed, 105 insertions(+), 80 deletions(-) diff --git a/Horatio/Container/Container.swift b/Horatio/Container/Container.swift index 9d2bc5a..293ab91 100644 --- a/Horatio/Container/Container.swift +++ b/Horatio/Container/Container.swift @@ -53,6 +53,7 @@ open class Container { return entry } + @discardableResult static open func register(_ serviceType: T.Type, name: String? = nil, factory: (Resolvable) -> T) -> ContainerEntry { return sharedContainer.register(serviceType, name: name, factory: factory) } @@ -60,14 +61,18 @@ open class Container { extension Container : Resolvable { + @discardableResult public func resolve(_ serviceType: T.Type, name: String? = nil) -> T? { typealias FactoryType = (Resolvable) -> T return resolveFactory(name) { (factory: FactoryType) in factory(self) } } + @discardableResult static public func resolve(_ serviceType: T.Type, name: String? = nil) -> T? { - return sharedContainer.resolve(serviceType, name: name) + let result = sharedContainer.resolve(serviceType, name: name) + + return result } internal func resolveFactory(_ name: String?, invoker: (Factory) -> T) -> T? { diff --git a/Horatio/JSON/JSONParsing.swift b/Horatio/JSON/JSONParsing.swift index 880aad1..50a7737 100644 --- a/Horatio/JSON/JSONParsing.swift +++ b/Horatio/JSON/JSONParsing.swift @@ -5,7 +5,7 @@ import Foundation -public typealias JSONObject = [String : AnyObject] +public typealias JSONObject = [String : Any] /// Options for parsing and validating JSON using the `JSONParser` class. @@ -32,7 +32,7 @@ public struct JSONParsingOptions: OptionSet { types and missing values. */ open class JSONParser { - open static func parseIdentifier(_ value: AnyObject?, options: JSONParsingOptions = .none) -> String? { + open static func parseIdentifier(_ value: Any?, options: JSONParsingOptions = .none) -> String? { if let stringValue = JSONParser.parseString(value) { return stringValue.lowercased() } @@ -40,7 +40,7 @@ open class JSONParser { return nil } - open static func parseString(_ value: AnyObject?, options: JSONParsingOptions = .none) -> String? { + open static func parseString(_ value: Any?, options: JSONParsingOptions = .none) -> String? { if let stringValue = value as? String { return stringValue.stringByDecodingJavascriptEntities() } @@ -58,7 +58,7 @@ open class JSONParser { return nil } - open static func parseInt(_ value: AnyObject?, options: JSONParsingOptions = .none) -> Int? { + open static func parseInt(_ value: Any?, options: JSONParsingOptions = .none) -> Int? { if let intValue = value as? Int { return intValue } @@ -80,7 +80,7 @@ open class JSONParser { return nil } - open static func parseDouble(_ value: AnyObject?, options: JSONParsingOptions = .none) -> Double? { + open static func parseDouble(_ value: Any?, options: JSONParsingOptions = .none) -> Double? { if let doubleValue = value as? Double { return doubleValue } @@ -102,7 +102,7 @@ open class JSONParser { return nil } - open static func parseBool(_ value: AnyObject?, options: JSONParsingOptions = .none) -> Bool? { + open static func parseBool(_ value: Any?, options: JSONParsingOptions = .none) -> Bool? { if let boolValue = value as? Bool { return boolValue } @@ -128,15 +128,15 @@ open class JSONParser { return nil } - open static func parseArray(_ value: AnyObject?, options: JSONParsingOptions = .none) -> [AnyObject]? { - if let arrayValue = value as? [AnyObject] { + open static func parseArray(_ value: Any?, options: JSONParsingOptions = .none) -> [Any]? { + if let arrayValue = value as? [Any] { return arrayValue } if let value = value { if let _ = value as? NSNull { if options.contains(.allowConversion) { - return [AnyObject]() + return [Any]() } } @@ -146,33 +146,33 @@ open class JSONParser { } if options.contains(.allowEmpty) { - return [AnyObject]() + return [Any]() } return nil } - open static func parseObject(_ value: AnyObject?, options: JSONParsingOptions = .none) -> JSONObject? { - if let objectValue = value as? [String : AnyObject] { + open static func parseObject(_ value: Any?, options: JSONParsingOptions = .none) -> JSONObject? { + if let objectValue = value as? [String : Any] { return objectValue } if let value = value { if let _ = value as? NSNull { if options.contains(.allowConversion) { - return [String : AnyObject]() + return [String : Any]() } } } if options.contains(.allowEmpty) { - return [String : AnyObject]() + return [String : Any]() } return nil } - open static func parseISO8601Date(_ value: AnyObject?, options: JSONParsingOptions = .none) -> Date? { + open static func parseISO8601Date(_ value: Any?, options: JSONParsingOptions = .none) -> Date? { if let dateString = JSONParser.parseString(value, options: options) { if let dateValue = Date.dateFromISO8601String(dateString) { return dateValue diff --git a/Horatio/JSON/JSONServiceResponseProcessor.swift b/Horatio/JSON/JSONServiceResponseProcessor.swift index 4971df6..d2ff604 100644 --- a/Horatio/JSON/JSONServiceResponseProcessor.swift +++ b/Horatio/JSON/JSONServiceResponseProcessor.swift @@ -9,18 +9,18 @@ import Foundation Processes JSON data in some way — transforming, storing, or otherwise manipulating the data. */ public protocol JSONProcessor { - func processJSONData(_ request: ServiceRequest, jsonData: JSONObject, completionBlock: (_ errors: [NSError]?) -> Void) - func processJSONData(_ request: ServiceRequest, jsonData: [JSONObject], completionBlock: (_ errors: [NSError]?) -> Void) + func processJSONData(_ request: ServiceRequest, jsonData: JSONObject, completionBlock: @escaping (_ errors: [NSError]?) -> Void) + func processJSONData(_ request: ServiceRequest, jsonData: [JSONObject], completionBlock: @escaping (_ errors: [NSError]?) -> Void) } extension JSONProcessor { - func processJSONData(_ request: ServiceRequest, jsonData: JSONObject, completionBlock: (_ errors: [NSError]?) -> Void) { + func processJSONData(_ request: ServiceRequest, jsonData: JSONObject, completionBlock: @escaping (_ errors: [NSError]?) -> Void) { completionBlock(nil) } - func processJSONData(_ request: ServiceRequest, jsonData: [JSONObject], completionBlock: (_ errors: [NSError]?) -> Void) { + func processJSONData(_ request: ServiceRequest, jsonData: [JSONObject], completionBlock: @escaping (_ errors: [NSError]?) -> Void) { completionBlock(nil) } } @@ -49,7 +49,7 @@ open class JSONServiceResponseProcessor: ServiceResponseProcessor { // MARK: - open func process(_ request: ServiceRequest, input: ServiceResponseProcessorParam, completionBlock: (ServiceResponseProcessorParam) -> Void) { + open func process(_ request: ServiceRequest, input: ServiceResponseProcessorParam, completionBlock: @escaping (ServiceResponseProcessorParam) -> Void) { var jsonData: Any? = nil do { @@ -80,8 +80,7 @@ open class JSONServiceResponseProcessor: ServiceResponseProcessor { // MARK: - Private - fileprivate func processObject(_ request: ServiceRequest, jsonObject: JSONObject, completionBlock: (ServiceResponseProcessorParam) -> Void) { - + fileprivate func processObject(_ request: ServiceRequest, jsonObject: JSONObject, completionBlock: @escaping (ServiceResponseProcessorParam) -> Void) { jsonProcessor.processJSONData(request, jsonData: jsonObject, completionBlock: { (errors: [NSError]?) in if let error = errors?.first { completionBlock(.error(error)) @@ -93,7 +92,7 @@ open class JSONServiceResponseProcessor: ServiceResponseProcessor { } - fileprivate func processArray(_ request: ServiceRequest, jsonArray: [JSONObject], completionBlock: (ServiceResponseProcessorParam) -> Void) { + fileprivate func processArray(_ request: ServiceRequest, jsonArray: [JSONObject], completionBlock: @escaping (ServiceResponseProcessorParam) -> Void) { jsonProcessor.processJSONData(request, jsonData: jsonArray, completionBlock: { (errors: [NSError]?) in if let error = errors?.first { completionBlock(.error(error)) diff --git a/Horatio/Operations/BlockObserver.swift b/Horatio/Operations/BlockObserver.swift index c557fcc..2b90cfa 100644 --- a/Horatio/Operations/BlockObserver.swift +++ b/Horatio/Operations/BlockObserver.swift @@ -17,9 +17,9 @@ public struct BlockObserver: OperationObserver { fileprivate let startHandler: ((Operation) -> Void)? fileprivate let produceHandler: ((Operation, Foundation.Operation) -> Void)? - fileprivate let finishHandler: ((Operation, [NSError]) -> Void)? + fileprivate let finishHandler: ((Operation, [Error]) -> Void)? - public init(startHandler: ((Operation) -> Void)? = nil, produceHandler: ((Operation, Foundation.Operation) -> Void)? = nil, finishHandler: ((Operation, [NSError]) -> Void)? = nil) { + public init(startHandler: ((Operation) -> Void)? = nil, produceHandler: ((Operation, Foundation.Operation) -> Void)? = nil, finishHandler: ((Operation, [Error]) -> Void)? = nil) { self.startHandler = startHandler self.produceHandler = produceHandler self.finishHandler = finishHandler @@ -35,7 +35,7 @@ public struct BlockObserver: OperationObserver { produceHandler?(operation, newOperation) } - public func operationDidFinish(_ operation: Operation, errors: [NSError]) { + public func operationDidFinish(_ operation: Operation, errors: [Error]) { finishHandler?(operation, errors) } } diff --git a/Horatio/Operations/BlockOperation.swift b/Horatio/Operations/BlockOperation.swift index 33af978..4197f9d 100644 --- a/Horatio/Operations/BlockOperation.swift +++ b/Horatio/Operations/BlockOperation.swift @@ -1,10 +1,10 @@ /* -Copyright (C) 2015 Apple Inc. All Rights Reserved. -See LICENSE.txt for this sample’s licensing information - -Abstract: -This code shows how to create a simple subclass of Operation. -*/ + Copyright (C) 2015 Apple Inc. All Rights Reserved. + See LICENSE.txt for this sample’s licensing information + + Abstract: + This code shows how to create a simple subclass of Operation. + */ import Foundation @@ -16,30 +16,30 @@ public typealias BlockType = (_ continueWithError: @escaping ContinuationBlockTy /// A sublcass of `Operation` to execute a closure. open class BlockOperation: Operation { fileprivate let block: BlockType - + /** - The designated initializer. - - - parameter block: The closure to run when the operation executes. This - closure will be run on an arbitrary queue. The parameter passed to the - block **MUST** be invoked by your code, or else the `BlockOperation` - will never finish executing. If this parameter is `nil`, the operation - will immediately finish. - */ + The designated initializer. + + - parameter block: The closure to run when the operation executes. This + closure will be run on an arbitrary queue. The parameter passed to the + block **MUST** be invoked by your code, or else the `BlockOperation` + will never finish executing. If this parameter is `nil`, the operation + will immediately finish. + */ public init(block: @escaping BlockType = { continuation in continuation(nil) }) { self.block = block super.init() name = "Block Operation" } - + /** - A convenience initializer to execute a block on the main queue. - - - parameter mainQueueBlock: The block to execute on the main queue. Note - that this block does not have a "continuation" block to execute (unlike - the designated initializer). The operation will be automatically ended - after the `mainQueueBlock` is executed. - */ + A convenience initializer to execute a block on the main queue. + + - parameter mainQueueBlock: The block to execute on the main queue. Note + that this block does not have a "continuation" block to execute (unlike + the designated initializer). The operation will be automatically ended + after the `mainQueueBlock` is executed. + */ public convenience init(mainQueueBlock: @escaping ()->()) { self.init(block: { continuation in DispatchQueue.main.async { @@ -48,10 +48,15 @@ open class BlockOperation: Operation { } }) } - - open override func execute() { - if !isCancelled { - block { error in self.finish([error as! NSError]) } + + override open func execute() { + guard !isCancelled else { + finish() + return + } + + block { _ in + self.finish() } } } diff --git a/Horatio/Operations/GroupOperation.swift b/Horatio/Operations/GroupOperation.swift index cb42c79..3e7530a 100644 --- a/Horatio/Operations/GroupOperation.swift +++ b/Horatio/Operations/GroupOperation.swift @@ -23,9 +23,10 @@ import Foundation */ open class GroupOperation: Operation { fileprivate let internalQueue = OperationQueue() + fileprivate let startingOperation = Foundation.BlockOperation(block: {}) fileprivate let finishingOperation = Foundation.BlockOperation(block: {}) - fileprivate var aggregatedErrors = [NSError]() + fileprivate var aggregatedErrors = [Error]() public convenience init(operations: Foundation.Operation...) { self.init(operations: operations) @@ -34,9 +35,10 @@ open class GroupOperation: Operation { public init(operations: [Foundation.Operation]) { super.init() + internalQueue.name = "\(name ?? "Unknown Group Operation") queue" internalQueue.isSuspended = true - internalQueue.delegate = self + internalQueue.addOperation(startingOperation) for operation in operations { internalQueue.addOperation(operation) @@ -62,11 +64,11 @@ open class GroupOperation: Operation { Errors aggregated through this method will be included in the final array of errors reported to observers and to the `finished(_:)` method. */ - final public func aggregateError(_ error: NSError) { + final public func aggregateError(_ error: Error) { aggregatedErrors.append(error) } - open func operationDidFinish(_ operation: Foundation.Operation, withErrors errors: [NSError]) { + open func operationDidFinish(_ operation: Foundation.Operation, withErrors errors: [Error]) { // For use by subclassers. } } @@ -83,15 +85,26 @@ extension GroupOperation: OperationQueueDelegate { if operation !== finishingOperation { finishingOperation.addDependency(operation) } + + /* + All operations should be dependent on the "startingOperation". + This way, we can guarantee that the conditions for other operations + will not evaluate until just before the operation is about to run. + Otherwise, the conditions could be evaluated at any time, even + before the internal operation queue is unsuspended. + */ + if operation !== startingOperation { + operation.addDependency(startingOperation) + } } - final public func operationQueue(_ operationQueue: OperationQueue, operationDidFinish operation: Foundation.Operation, withErrors errors: [NSError]) { - aggregatedErrors.append(contentsOf: errors) + final public func operationQueue(_ operationQueue: OperationQueue, operationDidFinish operation: Foundation.Operation, withErrors errors: [Error]) { + aggregatedErrors += errors if operation === finishingOperation { internalQueue.isSuspended = true finish(aggregatedErrors) - } else { + } else if operation !== startingOperation { operationDidFinish(operation, withErrors: errors) } } diff --git a/Horatio/Operations/NetworkObserver.swift b/Horatio/Operations/NetworkObserver.swift index ca77493..1b73343 100644 --- a/Horatio/Operations/NetworkObserver.swift +++ b/Horatio/Operations/NetworkObserver.swift @@ -29,7 +29,7 @@ public struct NetworkObserver: OperationObserver { public func operation(_ operation: Operation, didProduceOperation newOperation: Foundation.Operation) { } - public func operationDidFinish(_ operation: Operation, errors: [NSError]) { + public func operationDidFinish(_ operation: Operation, errors: [Error]) { DispatchQueue.main.async { // Decrement the network indicator's "reference count". NetworkIndicatorController.sharedIndicatorController.networkActivityDidEnd() @@ -46,7 +46,7 @@ private class NetworkIndicatorController { fileprivate var activityCount = 0 - fileprivate var visibilityTimer: Timer? + fileprivate var visibilityTimer: NetworkObserverTimer? // MARK: Methods @@ -75,7 +75,7 @@ private class NetworkIndicatorController { hiding of the indicator by one second. This provides the chance to come in and invalidate the timer before it fires. */ - visibilityTimer = Timer(interval: 1.0) { + visibilityTimer = NetworkObserverTimer(interval: 1.0) { self.hideIndicator() } } @@ -101,7 +101,7 @@ private class NetworkIndicatorController { } /// Essentially a cancellable `dispatch_after`. -class Timer { +fileprivate class NetworkObserverTimer { // MARK: Properties fileprivate var isCancelled = false diff --git a/Horatio/Operations/Operation.swift b/Horatio/Operations/Operation.swift index 680de37..4dcb598 100644 --- a/Horatio/Operations/Operation.swift +++ b/Horatio/Operations/Operation.swift @@ -266,8 +266,8 @@ open class Operation: Foundation.Operation { finish() } - fileprivate var _internalErrors = [NSError]() - func cancelWithError(_ error: NSError? = nil) { + fileprivate var _internalErrors = [Error]() + func cancelWithError(_ error: Error? = nil) { if let error = error { _internalErrors.append(error) } @@ -291,7 +291,7 @@ open class Operation: Foundation.Operation { for how an error from an `NSURLSession` is passed along via the `finishWithError()` method. */ - final func finishWithError(_ error: NSError?) { + final func finishWithError(_ error: Error?) { if let error = error { finish([error]) } @@ -305,7 +305,7 @@ open class Operation: Foundation.Operation { operation has finished. */ fileprivate var hasFinishedAlready = false - final func finish(_ errors: [NSError] = []) { + final func finish(_ errors: [Error] = []) { if !hasFinishedAlready { hasFinishedAlready = true state = .finishing @@ -321,7 +321,7 @@ open class Operation: Foundation.Operation { } } - finished(combinedErrors) + finished(combinedErrors as [NSError]) for observer in observers { observer.operationDidFinish(self, errors: combinedErrors) @@ -340,7 +340,7 @@ open class Operation: Foundation.Operation { func finished(_ errors: [NSError]) { // No op. } - + override final public func waitUntilFinished() { /* Waiting on operations is almost NEVER the right thing to do. It is diff --git a/Horatio/Operations/OperationCondition.swift b/Horatio/Operations/OperationCondition.swift index d31c0f4..1f00555 100644 --- a/Horatio/Operations/OperationCondition.swift +++ b/Horatio/Operations/OperationCondition.swift @@ -53,9 +53,9 @@ public protocol OperationCondition { */ public enum OperationConditionResult { case satisfied - case failed(NSError) + case failed(Error) - var error: NSError? { + var error: Error? { if case .failed(let error) = self { return error } @@ -67,7 +67,7 @@ public enum OperationConditionResult { // MARK: Evaluate Conditions public struct OperationConditionEvaluator { - public static func evaluate(_ conditions: [OperationCondition], operation: Operation, completion: @escaping ([NSError]) -> Void) { + public static func evaluate(_ conditions: [OperationCondition], operation: Operation, completion: @escaping ([Error]) -> Void) { // Check conditions. let conditionGroup = DispatchGroup() diff --git a/Horatio/Operations/OperationObserver.swift b/Horatio/Operations/OperationObserver.swift index cd7d3ad..98d4726 100644 --- a/Horatio/Operations/OperationObserver.swift +++ b/Horatio/Operations/OperationObserver.swift @@ -24,6 +24,6 @@ public protocol OperationObserver { Invoked as an `Operation` finishes, along with any errors produced during execution (or readiness evaluation). */ - func operationDidFinish(_ operation: Operation, errors: [NSError]) + func operationDidFinish(_ operation: Operation, errors: [Error]) } diff --git a/Horatio/Operations/OperationQueue.swift b/Horatio/Operations/OperationQueue.swift index 26b775b..feb3582 100644 --- a/Horatio/Operations/OperationQueue.swift +++ b/Horatio/Operations/OperationQueue.swift @@ -20,7 +20,7 @@ import Foundation */ @objc public protocol OperationQueueDelegate: NSObjectProtocol { @objc optional func operationQueue(_ operationQueue: OperationQueue, willAddOperation operation: Foundation.Operation) - @objc optional func operationQueue(_ operationQueue: OperationQueue, operationDidFinish operation: Foundation.Operation, withErrors errors: [NSError]) + @objc optional func operationQueue(_ operationQueue: OperationQueue, operationDidFinish operation: Foundation.Operation, withErrors errors: [Error]) } /** diff --git a/Horatio/Operations/TimeoutObserver.swift b/Horatio/Operations/TimeoutObserver.swift index 10dd981..433df7c 100644 --- a/Horatio/Operations/TimeoutObserver.swift +++ b/Horatio/Operations/TimeoutObserver.swift @@ -50,7 +50,7 @@ public struct TimeoutObserver: OperationObserver { // No op. } - public func operationDidFinish(_ operation: Operation, errors: [NSError]) { + public func operationDidFinish(_ operation: Operation, errors: [Error]) { // No op. } } diff --git a/Horatio/Operations/UIUserNotifications+Operations.swift b/Horatio/Operations/UIUserNotifications+Operations.swift index abfd072..f34723a 100644 --- a/Horatio/Operations/UIUserNotifications+Operations.swift +++ b/Horatio/Operations/UIUserNotifications+Operations.swift @@ -12,6 +12,7 @@ import UIKit import UserNotifications +@available(iOS 10.0, *) extension UNNotificationSettings { /// Check to see if one Settings object is a superset of another Settings object. func contains(_ settings: UNNotificationSettings) -> Bool { diff --git a/Horatio/Operations/UserNotificationCondition.swift b/Horatio/Operations/UserNotificationCondition.swift index 380e6aa..ccb3b29 100644 --- a/Horatio/Operations/UserNotificationCondition.swift +++ b/Horatio/Operations/UserNotificationCondition.swift @@ -16,6 +16,7 @@ import UserNotifications A condition for verifying that we can present alerts to the user via `UILocalNotification` and/or remote notifications. */ +@available(iOS 10.0, *) public struct UserNotificationCondition: OperationCondition { public enum Behavior { @@ -87,6 +88,7 @@ public struct UserNotificationCondition: OperationCondition { A private `Operation` subclass to register a `UIUserNotificationSettings` object with a `UIApplication`, prompting the user for permission if necessary. */ +@available(iOS 10.0, *) private class UserNotificationPermissionOperation: Operation { let settings: UNNotificationSettings let application: UIApplication diff --git a/Horatio/Scheduler/TaskScheduler.swift b/Horatio/Scheduler/TaskScheduler.swift index 9bbe2db..c163862 100644 --- a/Horatio/Scheduler/TaskScheduler.swift +++ b/Horatio/Scheduler/TaskScheduler.swift @@ -8,7 +8,7 @@ import Foundation public protocol ScheduledTaskProvider { var identifier: String { get } - func makeScheduledTasks() -> [Foundation.Operation] + func makeScheduledTasks() -> [Operation] } diff --git a/Horatio/Services/ServiceRequest.swift b/Horatio/Services/ServiceRequest.swift index 2282ccf..2748ffd 100644 --- a/Horatio/Services/ServiceRequest.swift +++ b/Horatio/Services/ServiceRequest.swift @@ -5,7 +5,7 @@ import Foundation -public typealias ServiceRequestCompletionBlock = (ServiceRequest, [NSError]) -> Void +public typealias ServiceRequestCompletionBlock = (ServiceRequest, [Error]) -> Void /** diff --git a/Horatio/Services/ServiceRequestOperation.swift b/Horatio/Services/ServiceRequestOperation.swift index 15011c7..c941b48 100644 --- a/Horatio/Services/ServiceRequestOperation.swift +++ b/Horatio/Services/ServiceRequestOperation.swift @@ -221,5 +221,5 @@ public enum ServiceResponseProcessorParam { complete the processing stage of the operation. */ public protocol ServiceResponseProcessor: class { - func process(_ request: ServiceRequest, input: ServiceResponseProcessorParam, completionBlock: (ServiceResponseProcessorParam) -> Void) + func process(_ request: ServiceRequest, input: ServiceResponseProcessorParam, completionBlock: @escaping (ServiceResponseProcessorParam) -> Void) } diff --git a/HoratioDemo/HoratioDemo.xcodeproj/project.xcworkspace/xcuserdata/ktatroe.xcuserdatad/UserInterfaceState.xcuserstate b/HoratioDemo/HoratioDemo.xcodeproj/project.xcworkspace/xcuserdata/ktatroe.xcuserdatad/UserInterfaceState.xcuserstate index 85cc015f2765e2c72916efd7cff5b586eb51a3d3..93ec172871af7367552a9deb80eeaa2a92f25065 100644 GIT binary patch literal 46275 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%0A^OrMP_#;hncTywkuo(t%v6 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 N+5hPO_mvh8{~s!DI7k2h literal 45749 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 Date: Thu, 1 Dec 2016 10:22:14 -0700 Subject: [PATCH 14/14] Use Error instead of NSError in Operation --- Horatio/Operations/Operation.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Horatio/Operations/Operation.swift b/Horatio/Operations/Operation.swift index 4dcb598..043d7d4 100644 --- a/Horatio/Operations/Operation.swift +++ b/Horatio/Operations/Operation.swift @@ -321,7 +321,7 @@ open class Operation: Foundation.Operation { } } - finished(combinedErrors as [NSError]) + finished(combinedErrors) for observer in observers { observer.operationDidFinish(self, errors: combinedErrors) @@ -337,7 +337,7 @@ open class Operation: Foundation.Operation { this method to potentially inform the user about an error when trying to bring up the Core Data stack. */ - func finished(_ errors: [NSError]) { + func finished(_ errors: [Error]) { // No op. }