From 5f52f9d3f0458e8af0c657a6b234908100903b96 Mon Sep 17 00:00:00 2001 From: James Barrow Date: Sun, 11 Oct 2020 21:19:32 +0200 Subject: [PATCH 01/15] Store jwtState and reference jwt and expires from it --- Source/Manager/Authentication.swift | 6 ++---- Source/Manager/Trefle.swift | 8 ++++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Source/Manager/Authentication.swift b/Source/Manager/Authentication.swift index acede86..df2db1c 100644 --- a/Source/Manager/Authentication.swift +++ b/Source/Manager/Authentication.swift @@ -27,8 +27,7 @@ public extension Trefle { switch result { case .success(let state): - shared.jwt = state.jwt - shared.expires = state.expires + shared.jwtState = state shared.authState = .authorized guard let stateUUID = shared.stateUUID else { @@ -120,8 +119,7 @@ public extension Trefle { manager.removeStateUUID() - manager.jwt = nil - manager.expires = nil + manager.jwtState = nil manager.stateUUID = nil manager.authState = .unauthorized diff --git a/Source/Manager/Trefle.swift b/Source/Manager/Trefle.swift index 98fafc2..3b0adca 100644 --- a/Source/Manager/Trefle.swift +++ b/Source/Manager/Trefle.swift @@ -66,8 +66,9 @@ public class Trefle { public var config: Config internal var accessToken: String = "" internal var uri: String = "" - internal var jwt: String? - internal var expires: Date? + internal var jwtState: JWTState? + internal var jwt: String? { jwtState?.jwt } + internal var expires: Date? { jwtState?.expires } internal var isValid: Bool { guard let expires = self.expires else { return false } return Date() < expires @@ -127,8 +128,7 @@ public class Trefle { } // Set returned JWT state - shared.jwt = keychainAuthState.jwt - shared.expires = keychainAuthState.expires + shared.jwtState = keychainAuthState // Check if JWT state is valid, otherwise refresh token guard keychainAuthState.isValid == false else { From 59edcb6fb4c8d1422d328fd56ce8019ab75cee45 Mon Sep 17 00:00:00 2001 From: James Barrow Date: Sun, 11 Oct 2020 21:20:06 +0200 Subject: [PATCH 02/15] Created list item and claim token operations --- .../Authentication/ClaimTokenOperation.swift | 173 ++++++++++++++++++ Source/Operations/ItemOperation.swift | 142 ++++++++++++++ Source/Operations/ListOperation.swift | 142 ++++++++++++++ TrefleSwiftSDK.xcodeproj/project.pbxproj | 20 ++ 4 files changed, 477 insertions(+) create mode 100644 Source/Operations/Authentication/ClaimTokenOperation.swift create mode 100644 Source/Operations/ItemOperation.swift create mode 100644 Source/Operations/ListOperation.swift diff --git a/Source/Operations/Authentication/ClaimTokenOperation.swift b/Source/Operations/Authentication/ClaimTokenOperation.swift new file mode 100644 index 0000000..d885223 --- /dev/null +++ b/Source/Operations/Authentication/ClaimTokenOperation.swift @@ -0,0 +1,173 @@ +// +// ClaimTokenOperation.swift +// TrefleSwiftSDK +// +// Created by James Barrow on 2020-10-11. +// Copyright © 2020 Pig on a Hill Productions. All rights reserved. +// + +import Foundation + +public class ClaimTokenOperation: Operation { + + internal var claimTokenCompletionBlock: ((_ result: Result) -> Void)? + + private var task: URLSessionTask? + internal var jwtState: JWTState? + public var error: Error? + public override var isAsynchronous: Bool { true } + public override var isConcurrent: Bool { true } + private var _isExecuting: Bool = false { + willSet { willChangeValue(forKey: "isExecuting") } + didSet { didChangeValue(forKey: "isExecuting") } + } + public override var isExecuting: Bool { _isExecuting } + private var _isFinished: Bool = false { + willSet { willChangeValue(forKey: "isFinished") } + didSet { didChangeValue(forKey: "isFinished") } + } + public override var isFinished: Bool { _isFinished } + + internal init(_ completionBlock: ((_ result: Result) -> Void)? = nil) { + claimTokenCompletionBlock = completionBlock + } + + public override func start() { + + if isExecuting == true { + return + } + + // Check if canceled, if so then return + if isCancelled == true { + + // Finish + _isFinished = true + return + } + + _isExecuting = true + + // Pre-check if JWT is still valid, if so don't claim a new token + if Trefle.shared.isValid == true { + jwtState = Trefle.shared.jwtState + + // Finish + self._isExecuting = false + self._isFinished = true + } + + guard var urlComponents = URLComponents(string: "\(Trefle.baseAPIURL)/auth/claim") else { + error = TrefleError.badURL + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + urlComponents.queryItems = [ + URLQueryItem(name: "token", value: Trefle.shared.accessToken), + URLQueryItem(name: "origin", value: Trefle.shared.uri) + ] + + guard let url = urlComponents.url else { + error = TrefleError.badURL + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + if Trefle.shared.stateUUID == nil { + Trefle.shared.stateUUID = UUID().uuidString + } + + var urlRequest = URLRequest(url: url) + urlRequest.httpMethod = "POST" + task = URLSession.shared.dataTask(with: urlRequest) { [weak self] (data, _, error) in + + guard let self = self else { + return + } + + // Check if canceled, if so then return + if self.isCancelled == true { + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + if let error = error { + self.error = error + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + guard let data = data else { + self.error = TrefleError.noData + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + let decoder = JSONDecoder.jwtJSONDecoder + let result: JWTState? + do { + result = try decoder.decode(JWTState.self, from: data) + } catch { + self.error = error + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + // Check if canceled, if so then return + if self.isCancelled == true { + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + guard let jwtState = result else { + self.error = TrefleError.generalError + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + guard jwtState.isValid == true else { + self.error = TrefleError.invalidToken + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + self.jwtState = jwtState + } + task?.resume() + } + + public override func cancel() { + super.cancel() + + task?.cancel() + } + +} diff --git a/Source/Operations/ItemOperation.swift b/Source/Operations/ItemOperation.swift new file mode 100644 index 0000000..4c0238e --- /dev/null +++ b/Source/Operations/ItemOperation.swift @@ -0,0 +1,142 @@ +// +// ItemOperation.swift +// TrefleSwiftSDK +// +// Created by James Barrow on 2020-10-11. +// Copyright © 2020 Pig on a Hill Productions. All rights reserved. +// + +import Foundation + +public class ItemOperation: Operation { + + public var fetchCompleted: ((_ result: Result, Error>) -> Void)? + + private let url: URL + private var task: URLSessionTask? + public var response: ResponseSingle? + public var error: Error? + public override var isAsynchronous: Bool { true } + public override var isConcurrent: Bool { true } + private var _isExecuting: Bool = false { + willSet { willChangeValue(forKey: "isExecuting") } + didSet { didChangeValue(forKey: "isExecuting") } + } + public override var isExecuting: Bool { _isExecuting } + private var _isFinished: Bool = false { + willSet { willChangeValue(forKey: "isFinished") } + didSet { didChangeValue(forKey: "isFinished") } + } + public override var isFinished: Bool { _isFinished } + + internal init(url: URL, completionBlock: ((_ result: Result, Error>) -> Void)? = nil) { + self.url = url + fetchCompleted = completionBlock + } + + public override func start() { + + if isExecuting == true { + return + } + + // Check if canceled, if so then return + if isCancelled == true { + + // Finish + _isFinished = true + return + } + + _isExecuting = true + + guard Trefle.shared.isValid == true, let jwt = Trefle.shared.jwt else { + error = TrefleError.noJWT + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) + task = URLSession.shared.dataTask(with: urlRequest) { [weak self] (data, _, error) in + + guard let self = self else { + return + } + + // Check if canceled, if so then return + if self.isCancelled == true { + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + if let error = error { + self.error = error + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + guard let data = data else { + self.error = TrefleError.noData + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + let decoder = JSONDecoder.customJSONDecoder + let result: ResponseSingle? + do { + result = try decoder.decode(ResponseSingle.self, from: data) + } catch { + self.error = error + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + // Check if canceled, if so then return + if self.isCancelled == true { + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + guard let responseResult = result else { + self.error = TrefleError.generalError + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + self.response = responseResult + + // Finish + self._isExecuting = false + self._isFinished = true + } + task?.resume() + } + + public override func cancel() { + super.cancel() + + task?.cancel() + } + +} diff --git a/Source/Operations/ListOperation.swift b/Source/Operations/ListOperation.swift new file mode 100644 index 0000000..4dc507f --- /dev/null +++ b/Source/Operations/ListOperation.swift @@ -0,0 +1,142 @@ +// +// ListOperation.swift +// TrefleSwiftSDK +// +// Created by James Barrow on 2020-10-11. +// Copyright © 2020 Pig on a Hill Productions. All rights reserved. +// + +import Foundation + +public class ListOperation: Operation { + + public var fetchCompleted: ((_ result: Result, Error>) -> Void)? + + private let url: URL + private var task: URLSessionTask? + public var response: ResponseList? + public var error: Error? + public override var isAsynchronous: Bool { true } + public override var isConcurrent: Bool { true } + private var _isExecuting: Bool = false { + willSet { willChangeValue(forKey: "isExecuting") } + didSet { didChangeValue(forKey: "isExecuting") } + } + public override var isExecuting: Bool { _isExecuting } + private var _isFinished: Bool = false { + willSet { willChangeValue(forKey: "isFinished") } + didSet { didChangeValue(forKey: "isFinished") } + } + public override var isFinished: Bool { _isFinished } + + internal init(url: URL, completionBlock: ((_ result: Result, Error>) -> Void)? = nil) { + self.url = url + fetchCompleted = completionBlock + } + + public override func start() { + + if isExecuting == true { + return + } + + // Check if canceled, if so then return + if isCancelled == true { + + // Finish + _isFinished = true + return + } + + _isExecuting = true + + guard Trefle.shared.isValid == true, let jwt = Trefle.shared.jwt else { + error = TrefleError.noJWT + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) + task = URLSession.shared.dataTask(with: urlRequest) { [weak self] (data, _, error) in + + guard let self = self else { + return + } + + // Check if canceled, if so then return + if self.isCancelled == true { + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + if let error = error { + self.error = error + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + guard let data = data else { + self.error = TrefleError.noData + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + let decoder = JSONDecoder.customJSONDecoder + let result: ResponseList? + do { + result = try decoder.decode(ResponseList.self, from: data) + } catch { + self.error = error + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + // Check if canceled, if so then return + if self.isCancelled == true { + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + guard let responseResult = result else { + self.error = TrefleError.generalError + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + self.response = responseResult + + // Finish + self._isExecuting = false + self._isFinished = true + } + task?.resume() + } + + public override func cancel() { + super.cancel() + + task?.cancel() + } + +} diff --git a/TrefleSwiftSDK.xcodeproj/project.pbxproj b/TrefleSwiftSDK.xcodeproj/project.pbxproj index a228c1a..18ebb12 100644 --- a/TrefleSwiftSDK.xcodeproj/project.pbxproj +++ b/TrefleSwiftSDK.xcodeproj/project.pbxproj @@ -9,6 +9,9 @@ /* Begin PBXBuildFile section */ 181CAAC025323C89009A252C /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = 181CAABF25323C89009A252C /* Config.swift */; }; 181CAAC425323CDC009A252C /* URLExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 181CAAC325323CDC009A252C /* URLExtensions.swift */; }; + 181CAAD12533234A009A252C /* ClaimTokenOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 181CAAD02533234A009A252C /* ClaimTokenOperation.swift */; }; + 181CAAD5253329F5009A252C /* ListOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 181CAAD4253329F5009A252C /* ListOperation.swift */; }; + 181CAADB25338DC6009A252C /* ItemOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 181CAADA25338DC6009A252C /* ItemOperation.swift */; }; 183B16932529E281007C7A72 /* PlantFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 183B16922529E281007C7A72 /* PlantFilter.swift */; }; 183B1697252A4D3E007C7A72 /* PlantExclude.swift in Sources */ = {isa = PBXBuildFile; fileRef = 183B1696252A4D3E007C7A72 /* PlantExclude.swift */; }; 183B169B252A5271007C7A72 /* PlantSortOrder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 183B169A252A5271007C7A72 /* PlantSortOrder.swift */; }; @@ -112,6 +115,9 @@ /* Begin PBXFileReference section */ 181CAABF25323C89009A252C /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = ""; }; 181CAAC325323CDC009A252C /* URLExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLExtensions.swift; sourceTree = ""; }; + 181CAAD02533234A009A252C /* ClaimTokenOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClaimTokenOperation.swift; sourceTree = ""; }; + 181CAAD4253329F5009A252C /* ListOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOperation.swift; sourceTree = ""; }; + 181CAADA25338DC6009A252C /* ItemOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemOperation.swift; sourceTree = ""; }; 183B16922529E281007C7A72 /* PlantFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlantFilter.swift; sourceTree = ""; }; 183B1696252A4D3E007C7A72 /* PlantExclude.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlantExclude.swift; sourceTree = ""; }; 183B169A252A5271007C7A72 /* PlantSortOrder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlantSortOrder.swift; sourceTree = ""; }; @@ -227,6 +233,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 181CAACF2533232E009A252C /* Authentication */ = { + isa = PBXGroup; + children = ( + 181CAAD02533234A009A252C /* ClaimTokenOperation.swift */, + ); + path = Authentication; + sourceTree = ""; + }; 183B16BB252A5F7D007C7A72 /* Plants */ = { isa = PBXGroup; children = ( @@ -439,6 +453,9 @@ 18DF92632454D94B0034A058 /* Operations */ = { isa = PBXGroup; children = ( + 181CAAD4253329F5009A252C /* ListOperation.swift */, + 181CAADA25338DC6009A252C /* ItemOperation.swift */, + 181CAACF2533232E009A252C /* Authentication */, 18DF92642454D9640034A058 /* Plants */, ); path = Operations; @@ -676,6 +693,7 @@ 188CA15E2528940600C26F55 /* Month.swift in Sources */, 18E7880424562F530064F78D /* DivisionClass.swift in Sources */, 18D11838252BAF110004DC72 /* GenusSortOrder.swift in Sources */, + 181CAAD5253329F5009A252C /* ListOperation.swift in Sources */, 186105D024507687008A863B /* PlantsManager.swift in Sources */, 18E787F224562BAF0064F78D /* Kingdom.swift in Sources */, 18C3D78E2527A9F3006B6413 /* SpeciesRef.swift in Sources */, @@ -686,6 +704,7 @@ 186105C2244F1AD1008A863B /* KeychainPasswordItem.swift in Sources */, 18E7881224563AA80064F78D /* GenusRef.swift in Sources */, 183B1697252A4D3E007C7A72 /* PlantExclude.swift in Sources */, + 181CAAD12533234A009A252C /* ClaimTokenOperation.swift in Sources */, 18D11834252BAF080004DC72 /* GenusFilter.swift in Sources */, 188CA1442528933000C26F55 /* Status.swift in Sources */, 18C3D78A252674FE006B6413 /* Zone.swift in Sources */, @@ -714,6 +733,7 @@ 18D11800252B9D210004DC72 /* DivisionOrdersManager.swift in Sources */, 184BB2C624E5E1D6007DED03 /* Response.swift in Sources */, 18E787FE24562E560064F78D /* Division.swift in Sources */, + 181CAADB25338DC6009A252C /* ItemOperation.swift in Sources */, 181CAAC425323CDC009A252C /* URLExtensions.swift in Sources */, 18D11842252C6BBC0004DC72 /* SpeciesManager.swift in Sources */, 183B169F252A54F2007C7A72 /* PlantRange.swift in Sources */, From e03ff8989226f5a0770696762146fd7abb9b3a9e Mon Sep 17 00:00:00 2001 From: James Barrow Date: Sun, 11 Oct 2020 21:37:23 +0200 Subject: [PATCH 03/15] Renamed ResponseSingle -> ResponseItem --- Source/Operations/ItemOperation.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/Operations/ItemOperation.swift b/Source/Operations/ItemOperation.swift index 4c0238e..cd2e7f3 100644 --- a/Source/Operations/ItemOperation.swift +++ b/Source/Operations/ItemOperation.swift @@ -10,11 +10,11 @@ import Foundation public class ItemOperation: Operation { - public var fetchCompleted: ((_ result: Result, Error>) -> Void)? + public var fetchCompleted: ((_ result: Result, Error>) -> Void)? private let url: URL private var task: URLSessionTask? - public var response: ResponseSingle? + public var response: ResponseItem? public var error: Error? public override var isAsynchronous: Bool { true } public override var isConcurrent: Bool { true } @@ -29,7 +29,7 @@ public class ItemOperation: Operation { } public override var isFinished: Bool { _isFinished } - internal init(url: URL, completionBlock: ((_ result: Result, Error>) -> Void)? = nil) { + internal init(url: URL, completionBlock: ((_ result: Result, Error>) -> Void)? = nil) { self.url = url fetchCompleted = completionBlock } @@ -94,9 +94,9 @@ public class ItemOperation: Operation { } let decoder = JSONDecoder.customJSONDecoder - let result: ResponseSingle? + let result: ResponseItem? do { - result = try decoder.decode(ResponseSingle.self, from: data) + result = try decoder.decode(ResponseItem.self, from: data) } catch { self.error = error From f7b2bf1f19dd3eeebb98a7861aa94ecf5331516b Mon Sep 17 00:00:00 2001 From: James Barrow Date: Sun, 11 Oct 2020 21:56:38 +0200 Subject: [PATCH 04/15] Added operation queue to Trefle --- Source/Manager/Trefle.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source/Manager/Trefle.swift b/Source/Manager/Trefle.swift index 3b0adca..2c8cfb1 100644 --- a/Source/Manager/Trefle.swift +++ b/Source/Manager/Trefle.swift @@ -87,6 +87,11 @@ public class Trefle { } internal lazy var authStateDidChangeListeners = [UUID: ((authState: AuthState) -> Void)]() internal let authStateListenerQueue = DispatchQueue(label: "com.PigonaHill.TrefleSwiftSDK.AuthStateListenerQueue", attributes: .concurrent) + public static let operationQueue: OperationQueue = { + let queue = OperationQueue() + queue.name = "com.TrefleSwiftSDK.OperationQueue" + return queue + }() // MARK: - Lifecycle From ddea059810f91e922d5ee876ec067950084a8617 Mon Sep 17 00:00:00 2001 From: James Barrow Date: Sun, 11 Oct 2020 22:01:02 +0200 Subject: [PATCH 05/15] Set claim token operation queue priority to very high by default and set name --- Source/Operations/Authentication/ClaimTokenOperation.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source/Operations/Authentication/ClaimTokenOperation.swift b/Source/Operations/Authentication/ClaimTokenOperation.swift index d885223..35e4b4c 100644 --- a/Source/Operations/Authentication/ClaimTokenOperation.swift +++ b/Source/Operations/Authentication/ClaimTokenOperation.swift @@ -30,6 +30,11 @@ public class ClaimTokenOperation: Operation { internal init(_ completionBlock: ((_ result: Result) -> Void)? = nil) { claimTokenCompletionBlock = completionBlock + + super.init() + + name = "com.TrefleSwiftSDK.Operation.ClaimToken" + queuePriority = .veryHigh } public override func start() { From f853c24ab27cf5e7991ebfdc263cf9583ac5a24a Mon Sep 17 00:00:00 2001 From: James Barrow Date: Sun, 11 Oct 2020 22:07:18 +0200 Subject: [PATCH 06/15] Used operation to remove duplicate code for claimToken --- Source/Manager/Authentication.swift | 61 +++-------------------------- 1 file changed, 5 insertions(+), 56 deletions(-) diff --git a/Source/Manager/Authentication.swift b/Source/Manager/Authentication.swift index df2db1c..3e0e390 100644 --- a/Source/Manager/Authentication.swift +++ b/Source/Manager/Authentication.swift @@ -47,63 +47,12 @@ public extension Trefle { // MARK: - Token - internal static func claimToken(_ completed: @escaping (Result) -> Void) { + @discardableResult + internal static func claimToken(_ completed: @escaping (Result) -> Void) -> ClaimTokenOperation { - guard var urlComponents = URLComponents(string: "\(Trefle.baseAPIURL)/auth/claim") else { - completed(Result.failure(TrefleError.badURL)) - return - } - - urlComponents.queryItems = [ - URLQueryItem(name: "token", value: shared.accessToken), - URLQueryItem(name: "origin", value: shared.uri) - ] - - guard let url = urlComponents.url else { - completed(Result.failure(TrefleError.badURL)) - return - } - - if shared.stateUUID == nil { - shared.stateUUID = UUID().uuidString - } - - var urlRequest = URLRequest(url: url) - urlRequest.httpMethod = "POST" - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.jwtJSONDecoder - let result: JWTState? - do { - result = try decoder.decode(JWTState.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - guard let state = result else { - completed(Result.failure(TrefleError.generalError)) - return - } - - guard state.isValid == true else { - completed(Result.failure(TrefleError.invalidToken)) - return - } - - completed(Result.success(state)) - } - downloadTask.resume() + let operation = ClaimTokenOperation(completed) + Trefle.operationQueue.addOperation(operation) + return operation } // MARK: - Logout From 72a7c301ff21655b4170f10b403f31afaf62db6b Mon Sep 17 00:00:00 2001 From: James Barrow Date: Sun, 11 Oct 2020 22:17:50 +0200 Subject: [PATCH 07/15] Fixed missed completion issues with operations --- .../Authentication/ClaimTokenOperation.swift | 35 ++++++++++++++++--- Source/Operations/ItemOperation.swift | 25 ++++++++++--- Source/Operations/ListOperation.swift | 21 +++++++++-- 3 files changed, 68 insertions(+), 13 deletions(-) diff --git a/Source/Operations/Authentication/ClaimTokenOperation.swift b/Source/Operations/Authentication/ClaimTokenOperation.swift index 35e4b4c..9e58fd1 100644 --- a/Source/Operations/Authentication/ClaimTokenOperation.swift +++ b/Source/Operations/Authentication/ClaimTokenOperation.swift @@ -63,7 +63,10 @@ public class ClaimTokenOperation: Operation { } guard var urlComponents = URLComponents(string: "\(Trefle.baseAPIURL)/auth/claim") else { - error = TrefleError.badURL + let error = TrefleError.badURL + self.error = error + + claimTokenCompletionBlock?(Result.failure(error)) // Finish self._isExecuting = false @@ -77,7 +80,10 @@ public class ClaimTokenOperation: Operation { ] guard let url = urlComponents.url else { - error = TrefleError.badURL + let error = TrefleError.badURL + self.error = error + + claimTokenCompletionBlock?(Result.failure(error)) // Finish self._isExecuting = false @@ -109,6 +115,8 @@ public class ClaimTokenOperation: Operation { if let error = error { self.error = error + self.claimTokenCompletionBlock?(Result.failure(error)) + // Finish self._isExecuting = false self._isFinished = true @@ -116,7 +124,10 @@ public class ClaimTokenOperation: Operation { } guard let data = data else { - self.error = TrefleError.noData + let error = TrefleError.noData + self.error = error + + self.claimTokenCompletionBlock?(Result.failure(error)) // Finish self._isExecuting = false @@ -131,6 +142,8 @@ public class ClaimTokenOperation: Operation { } catch { self.error = error + self.claimTokenCompletionBlock?(Result.failure(error)) + // Finish self._isExecuting = false self._isFinished = true @@ -147,7 +160,10 @@ public class ClaimTokenOperation: Operation { } guard let jwtState = result else { - self.error = TrefleError.generalError + let error = TrefleError.generalError + self.error = error + + self.claimTokenCompletionBlock?(Result.failure(error)) // Finish self._isExecuting = false @@ -156,7 +172,10 @@ public class ClaimTokenOperation: Operation { } guard jwtState.isValid == true else { - self.error = TrefleError.invalidToken + let error = TrefleError.invalidToken + self.error = error + + self.claimTokenCompletionBlock?(Result.failure(error)) // Finish self._isExecuting = false @@ -165,6 +184,12 @@ public class ClaimTokenOperation: Operation { } self.jwtState = jwtState + + self.claimTokenCompletionBlock?(Result.success(jwtState)) + + // Finish + self._isExecuting = false + self._isFinished = true } task?.resume() } diff --git a/Source/Operations/ItemOperation.swift b/Source/Operations/ItemOperation.swift index cd2e7f3..40a9794 100644 --- a/Source/Operations/ItemOperation.swift +++ b/Source/Operations/ItemOperation.swift @@ -10,7 +10,7 @@ import Foundation public class ItemOperation: Operation { - public var fetchCompleted: ((_ result: Result, Error>) -> Void)? + public var fetchItemCompleted: ((_ result: Result, Error>) -> Void)? private let url: URL private var task: URLSessionTask? @@ -31,7 +31,7 @@ public class ItemOperation: Operation { internal init(url: URL, completionBlock: ((_ result: Result, Error>) -> Void)? = nil) { self.url = url - fetchCompleted = completionBlock + fetchItemCompleted = completionBlock } public override func start() { @@ -51,7 +51,10 @@ public class ItemOperation: Operation { _isExecuting = true guard Trefle.shared.isValid == true, let jwt = Trefle.shared.jwt else { - error = TrefleError.noJWT + let error = TrefleError.noJWT + self.error = error + + fetchItemCompleted?(Result.failure(error)) // Finish self._isExecuting = false @@ -78,6 +81,8 @@ public class ItemOperation: Operation { if let error = error { self.error = error + self.fetchItemCompleted?(Result.failure(error)) + // Finish self._isExecuting = false self._isFinished = true @@ -85,7 +90,10 @@ public class ItemOperation: Operation { } guard let data = data else { - self.error = TrefleError.noData + let error = TrefleError.noData + self.error = error + + self.fetchItemCompleted?(Result.failure(error)) // Finish self._isExecuting = false @@ -100,6 +108,8 @@ public class ItemOperation: Operation { } catch { self.error = error + self.fetchItemCompleted?(Result.failure(error)) + // Finish self._isExecuting = false self._isFinished = true @@ -116,7 +126,10 @@ public class ItemOperation: Operation { } guard let responseResult = result else { - self.error = TrefleError.generalError + let error = TrefleError.generalError + self.error = error + + self.fetchItemCompleted?(Result.failure(error)) // Finish self._isExecuting = false @@ -126,6 +139,8 @@ public class ItemOperation: Operation { self.response = responseResult + self.fetchItemCompleted?(Result.success(responseResult)) + // Finish self._isExecuting = false self._isFinished = true diff --git a/Source/Operations/ListOperation.swift b/Source/Operations/ListOperation.swift index 4dc507f..369cf85 100644 --- a/Source/Operations/ListOperation.swift +++ b/Source/Operations/ListOperation.swift @@ -51,7 +51,10 @@ public class ListOperation: Operation { _isExecuting = true guard Trefle.shared.isValid == true, let jwt = Trefle.shared.jwt else { - error = TrefleError.noJWT + let error = TrefleError.noJWT + self.error = error + + fetchCompleted?(Result.failure(error)) // Finish self._isExecuting = false @@ -78,6 +81,8 @@ public class ListOperation: Operation { if let error = error { self.error = error + self.fetchCompleted?(Result.failure(error)) + // Finish self._isExecuting = false self._isFinished = true @@ -85,7 +90,10 @@ public class ListOperation: Operation { } guard let data = data else { - self.error = TrefleError.noData + let error = TrefleError.noData + self.error = error + + self.fetchCompleted?(Result.failure(error)) // Finish self._isExecuting = false @@ -100,6 +108,8 @@ public class ListOperation: Operation { } catch { self.error = error + self.fetchCompleted?(Result.failure(error)) + // Finish self._isExecuting = false self._isFinished = true @@ -116,7 +126,10 @@ public class ListOperation: Operation { } guard let responseResult = result else { - self.error = TrefleError.generalError + let error = TrefleError.generalError + self.error = error + + self.fetchCompleted?(Result.failure(error)) // Finish self._isExecuting = false @@ -126,6 +139,8 @@ public class ListOperation: Operation { self.response = responseResult + self.fetchCompleted?(Result.success(responseResult)) + // Finish self._isExecuting = false self._isFinished = true From 3d06d30aeda8218e2378a495f9b30ff2360decd3 Mon Sep 17 00:00:00 2001 From: James Barrow Date: Sun, 11 Oct 2020 22:29:53 +0200 Subject: [PATCH 08/15] Swapped to using operations in PlantsManager --- Source/Manager/PlantsManager.swift | 211 ++++++++--------------------- 1 file changed, 60 insertions(+), 151 deletions(-) diff --git a/Source/Manager/PlantsManager.swift b/Source/Manager/PlantsManager.swift index 4db447d..51d484b 100644 --- a/Source/Manager/PlantsManager.swift +++ b/Source/Manager/PlantsManager.swift @@ -74,215 +74,124 @@ public class PlantsManager { // MARK: - Fetch Plants - public static func fetch(filter: Filter? = nil, exclude: Exclude? = nil, order: SortOrder? = nil, range: Range? = nil, page: Int? = nil, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetch(filter: Filter? = nil, exclude: Exclude? = nil, order: SortOrder? = nil, range: Range? = nil, page: Int? = nil, completed: @escaping (Result, Error>) -> Void) -> ListOperation? { guard let url = listURL(filter: filter, exclude: exclude, order: order, range: range, page: page) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetch(jwt: jwt, url: url, completed: completed) - return - } + let listOperation = ListOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetch(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(listOperation) + return listOperation } - } - - internal static func fetch(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseList? - do { - result = try decoder.decode(ResponseList.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - guard let responseResult = result else { - completed(Result.failure(TrefleError.generalError)) - return - } - - completed(Result.success(responseResult)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + listOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, listOperation], waitUntilFinished: false) + return listOperation } // MARK: - Search Plants - public static func search(query: String, filter: Filter? = nil, exclude: Exclude? = nil, order: SortOrder? = nil, range: Range? = nil, page: Int? = nil, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + public static func search(query: String, filter: Filter? = nil, exclude: Exclude? = nil, order: SortOrder? = nil, range: Range? = nil, page: Int? = nil, completed: @escaping (Result, Error>) -> Void) -> ListOperation? { guard let url = listURL(query: query, filter: filter, exclude: exclude, order: order, range: range, page: page) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetch(jwt: jwt, url: url, completed: completed) - return - } + let listOperation = ListOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetch(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(listOperation) + return listOperation } + + let claimTokenOperation = ClaimTokenOperation() + listOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, listOperation], waitUntilFinished: false) + return listOperation } // MARK: - Fetch Plants in Distribution Zone - public static func fetchInDistributionZone(with zoneId: String, filter: Filter? = nil, exclude: Exclude? = nil, order: SortOrder? = nil, range: Range? = nil, page: Int? = nil, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + public static func fetchInDistributionZone(with zoneId: String, filter: Filter? = nil, exclude: Exclude? = nil, order: SortOrder? = nil, range: Range? = nil, page: Int? = nil, completed: @escaping (Result, Error>) -> Void) -> ListOperation? { guard let url = listURL(zoneId: zoneId, filter: filter, exclude: exclude, order: order, range: range, page: page) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetch(jwt: jwt, url: url, completed: completed) - return - } + let listOperation = ListOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetch(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(listOperation) + return listOperation } + + let claimTokenOperation = ClaimTokenOperation() + listOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, listOperation], waitUntilFinished: false) + return listOperation } // MARK: - Fetch Plants of a Genus - public static func fetchOfGenus(with genusId: String, filter: Filter? = nil, exclude: Exclude? = nil, order: SortOrder? = nil, range: Range? = nil, page: Int? = nil, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + public static func fetchOfGenus(with genusId: String, filter: Filter? = nil, exclude: Exclude? = nil, order: SortOrder? = nil, range: Range? = nil, page: Int? = nil, completed: @escaping (Result, Error>) -> Void) -> ListOperation? { guard let url = listURL(genusId: genusId, filter: filter, exclude: exclude, order: order, range: range, page: page) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetch(jwt: jwt, url: url, completed: completed) - return - } + let listOperation = ListOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetch(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(listOperation) + return listOperation } + + let claimTokenOperation = ClaimTokenOperation() + listOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, listOperation], waitUntilFinished: false) + return listOperation } // MARK: - Fetch Plant - public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) -> ItemOperation? { guard let url = itemURL(identifier: identifier) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetchItem(jwt: jwt, url: url, completed: completed) - return - } + let listOperation = ItemOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetchItem(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(listOperation) + return listOperation } - } - - internal static func fetchItem(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseItem - do { - result = try decoder.decode(ResponseItem.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - completed(Result.success(result)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + listOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, listOperation], waitUntilFinished: false) + return listOperation } } From ce8c66f2f8d6098280c36bdc29f9a70a105b9bf1 Mon Sep 17 00:00:00 2001 From: James Barrow Date: Sun, 11 Oct 2020 22:40:24 +0200 Subject: [PATCH 09/15] Updated list and item operations to take custom jwt paramiter --- Source/Operations/ItemOperation.swift | 18 ++++++++++++++++-- Source/Operations/ListOperation.swift | 18 ++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Source/Operations/ItemOperation.swift b/Source/Operations/ItemOperation.swift index 40a9794..6fe2022 100644 --- a/Source/Operations/ItemOperation.swift +++ b/Source/Operations/ItemOperation.swift @@ -12,6 +12,7 @@ public class ItemOperation: Operation { public var fetchItemCompleted: ((_ result: Result, Error>) -> Void)? + private let jwt: String? private let url: URL private var task: URLSessionTask? public var response: ResponseItem? @@ -29,7 +30,8 @@ public class ItemOperation: Operation { } public override var isFinished: Bool { _isFinished } - internal init(url: URL, completionBlock: ((_ result: Result, Error>) -> Void)? = nil) { + internal init(jwt: String? = nil, url: URL, completionBlock: ((_ result: Result, Error>) -> Void)? = nil) { + self.jwt = jwt self.url = url fetchItemCompleted = completionBlock } @@ -50,7 +52,19 @@ public class ItemOperation: Operation { _isExecuting = true - guard Trefle.shared.isValid == true, let jwt = Trefle.shared.jwt else { + guard let jwt = self.jwt ?? Trefle.shared.jwt else { + let error = TrefleError.noJWT + self.error = error + + fetchItemCompleted?(Result.failure(error)) + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + if jwt == Trefle.shared.jwt && Trefle.shared.isValid == false { let error = TrefleError.noJWT self.error = error diff --git a/Source/Operations/ListOperation.swift b/Source/Operations/ListOperation.swift index 369cf85..1b5977c 100644 --- a/Source/Operations/ListOperation.swift +++ b/Source/Operations/ListOperation.swift @@ -12,6 +12,7 @@ public class ListOperation: Operation { public var fetchCompleted: ((_ result: Result, Error>) -> Void)? + private let jwt: String? private let url: URL private var task: URLSessionTask? public var response: ResponseList? @@ -29,7 +30,8 @@ public class ListOperation: Operation { } public override var isFinished: Bool { _isFinished } - internal init(url: URL, completionBlock: ((_ result: Result, Error>) -> Void)? = nil) { + internal init(jwt: String? = nil, url: URL, completionBlock: ((_ result: Result, Error>) -> Void)? = nil) { + self.jwt = jwt self.url = url fetchCompleted = completionBlock } @@ -50,7 +52,19 @@ public class ListOperation: Operation { _isExecuting = true - guard Trefle.shared.isValid == true, let jwt = Trefle.shared.jwt else { + guard let jwt = self.jwt ?? Trefle.shared.jwt else { + let error = TrefleError.noJWT + self.error = error + + fetchCompleted?(Result.failure(error)) + + // Finish + self._isExecuting = false + self._isFinished = true + return + } + + if jwt == Trefle.shared.jwt && Trefle.shared.isValid == false { let error = TrefleError.noJWT self.error = error From 14cccea2891d3c13fdd2c8cf76c17d0a695da7c0 Mon Sep 17 00:00:00 2001 From: James Barrow Date: Sun, 11 Oct 2020 22:40:32 +0200 Subject: [PATCH 10/15] Updated plant tests --- Tests/PlantsTests.swift | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Tests/PlantsTests.swift b/Tests/PlantsTests.swift index 1668c0d..6e9f670 100644 --- a/Tests/PlantsTests.swift +++ b/Tests/PlantsTests.swift @@ -27,7 +27,7 @@ class PlantsTests: XCTestCase { let expectation = self.expectation(description: #function) - PlantsManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let page): @@ -39,6 +39,7 @@ class PlantsTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -59,7 +60,7 @@ class PlantsTests: XCTestCase { let expectation = self.expectation(description: #function) - PlantsManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -71,6 +72,7 @@ class PlantsTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -92,7 +94,7 @@ class PlantsTests: XCTestCase { let expectation = self.expectation(description: #function) - PlantsManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -110,6 +112,7 @@ class PlantsTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -130,7 +133,7 @@ class PlantsTests: XCTestCase { let expectation = self.expectation(description: #function) - PlantsManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -142,6 +145,7 @@ class PlantsTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -162,7 +166,7 @@ class PlantsTests: XCTestCase { let expectation = self.expectation(description: #function) - PlantsManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let page): @@ -174,6 +178,7 @@ class PlantsTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -194,7 +199,7 @@ class PlantsTests: XCTestCase { let expectation = self.expectation(description: #function) - PlantsManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let page): @@ -206,6 +211,7 @@ class PlantsTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -226,7 +232,7 @@ class PlantsTests: XCTestCase { let expectation = self.expectation(description: #function) - PlantsManager.fetchItem(jwt: config.accessToken, url: url) { (result) in + let operation = ItemOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -238,6 +244,7 @@ class PlantsTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") From 89952578528ff30d1ed8dd814f5bec44109070f3 Mon Sep 17 00:00:00 2001 From: James Barrow Date: Mon, 12 Oct 2020 16:32:57 +0200 Subject: [PATCH 11/15] Swapped out to using operations for all actions --- Source/Manager/DistributionZonesManager.swift | 121 ++++------------- Source/Manager/DivisionClassesManager.swift | 122 ++++-------------- Source/Manager/DivisionOrdersManager.swift | 122 ++++-------------- Source/Manager/DivisionsManager.swift | 121 ++++------------- Source/Manager/FamiliesManager.swift | 121 ++++------------- Source/Manager/GenusManager.swift | 121 ++++------------- Source/Manager/KingdomsManager.swift | 121 ++++------------- Source/Manager/PlantsManager.swift | 15 ++- Source/Manager/SpeciesManager.swift | 121 ++++------------- Source/Manager/SubkingdomsManager.swift | 121 ++++------------- 10 files changed, 225 insertions(+), 881 deletions(-) diff --git a/Source/Manager/DistributionZonesManager.swift b/Source/Manager/DistributionZonesManager.swift index 6aebc00..d910864 100644 --- a/Source/Manager/DistributionZonesManager.swift +++ b/Source/Manager/DistributionZonesManager.swift @@ -37,125 +37,52 @@ public class DistributionZonesManager { // MARK: - Fetch Distribution Zones - public static func fetch(page: Int? = nil, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetch(page: Int? = nil, completed: @escaping (Result, Error>) -> Void) -> ListOperation? { guard let url = listURL(page: page) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetch(jwt: jwt, url: url, completed: completed) - return - } + let listOperation = ListOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetch(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(listOperation) + return listOperation } - } - - internal static func fetch(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseList? - do { - result = try decoder.decode(ResponseList.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - guard let responseResult = result else { - completed(Result.failure(TrefleError.generalError)) - return - } - - completed(Result.success(responseResult)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + listOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, listOperation], waitUntilFinished: false) + return listOperation } // MARK: - Fetch Distribution Zone - public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) -> ItemOperation? { guard let url = itemURL(identifier: identifier) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetchItem(jwt: jwt, url: url, completed: completed) - return - } + let itemOperation = ItemOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetchItem(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(itemOperation) + return itemOperation } - } - - internal static func fetchItem(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseItem - do { - result = try decoder.decode(ResponseItem.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - completed(Result.success(result)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + itemOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, itemOperation], waitUntilFinished: false) + return itemOperation } } diff --git a/Source/Manager/DivisionClassesManager.swift b/Source/Manager/DivisionClassesManager.swift index d076f2d..5325515 100644 --- a/Source/Manager/DivisionClassesManager.swift +++ b/Source/Manager/DivisionClassesManager.swift @@ -37,126 +37,52 @@ public class DivisionClassesManager { // MARK: - Fetch Divisions - public static func fetch(page: Int? = nil, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetch(page: Int? = nil, completed: @escaping (Result, Error>) -> Void) -> ListOperation? { guard let url = listURL(page: page) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetch(jwt: jwt, url: url, completed: completed) - return - } + let listOperation = ListOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetch(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(listOperation) + return listOperation } - } - - internal static func fetch(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseList? - do { - result = try decoder.decode(ResponseList.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - guard let responseResult = result else { - completed(Result.failure(TrefleError.generalError)) - return - } - - completed(Result.success(responseResult)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + listOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, listOperation], waitUntilFinished: false) + return listOperation } // MARK: - Fetch Division Class - public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) -> ItemOperation? { guard let url = itemURL(identifier: identifier) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetchItem(jwt: jwt, url: url, completed: completed) - return - } + let itemOperation = ItemOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetchItem(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(itemOperation) + return itemOperation } - } - - internal static func fetchItem(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - print(url) - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseItem - do { - result = try decoder.decode(ResponseItem.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - completed(Result.success(result)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + itemOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, itemOperation], waitUntilFinished: false) + return itemOperation } } diff --git a/Source/Manager/DivisionOrdersManager.swift b/Source/Manager/DivisionOrdersManager.swift index fb16b29..b6388b2 100644 --- a/Source/Manager/DivisionOrdersManager.swift +++ b/Source/Manager/DivisionOrdersManager.swift @@ -37,126 +37,52 @@ public class DivisionOrdersManager { // MARK: - Fetch Divisions - public static func fetch(page: Int? = nil, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetch(page: Int? = nil, completed: @escaping (Result, Error>) -> Void) -> ListOperation? { guard let url = listURL(page: page) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetch(jwt: jwt, url: url, completed: completed) - return - } + let listOperation = ListOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetch(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(listOperation) + return listOperation } - } - - internal static func fetch(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseList? - do { - result = try decoder.decode(ResponseList.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - guard let responseResult = result else { - completed(Result.failure(TrefleError.generalError)) - return - } - - completed(Result.success(responseResult)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + listOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, listOperation], waitUntilFinished: false) + return listOperation } // MARK: - Fetch Division Order - public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) -> ItemOperation? { guard let url = itemURL(identifier: identifier) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetchItem(jwt: jwt, url: url, completed: completed) - return - } + let itemOperation = ItemOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetchItem(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(itemOperation) + return itemOperation } - } - - internal static func fetchItem(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - print(url) - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseItem - do { - result = try decoder.decode(ResponseItem.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - completed(Result.success(result)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + itemOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, itemOperation], waitUntilFinished: false) + return itemOperation } } diff --git a/Source/Manager/DivisionsManager.swift b/Source/Manager/DivisionsManager.swift index 3f1a693..14d9150 100644 --- a/Source/Manager/DivisionsManager.swift +++ b/Source/Manager/DivisionsManager.swift @@ -37,125 +37,52 @@ public class DivisionsManager { // MARK: - Fetch Divisions - public static func fetch(page: Int? = nil, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetch(page: Int? = nil, completed: @escaping (Result, Error>) -> Void) -> ListOperation? { guard let url = listURL(page: page) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetch(jwt: jwt, url: url, completed: completed) - return - } + let listOperation = ListOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetch(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(listOperation) + return listOperation } - } - - internal static func fetch(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseList? - do { - result = try decoder.decode(ResponseList.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - guard let responseResult = result else { - completed(Result.failure(TrefleError.generalError)) - return - } - - completed(Result.success(responseResult)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + listOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, listOperation], waitUntilFinished: false) + return listOperation } // MARK: - Fetch Division - public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) -> ItemOperation? { guard let url = itemURL(identifier: identifier) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetchItem(jwt: jwt, url: url, completed: completed) - return - } + let itemOperation = ItemOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetchItem(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(itemOperation) + return itemOperation } - } - - internal static func fetchItem(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseItem - do { - result = try decoder.decode(ResponseItem.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - completed(Result.success(result)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + itemOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, itemOperation], waitUntilFinished: false) + return itemOperation } } diff --git a/Source/Manager/FamiliesManager.swift b/Source/Manager/FamiliesManager.swift index 6f9f93e..c03dd4d 100644 --- a/Source/Manager/FamiliesManager.swift +++ b/Source/Manager/FamiliesManager.swift @@ -49,125 +49,52 @@ public class FamiliesManager { // MARK: - Fetch Families - public static func fetch(page: Int? = nil, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetch(page: Int? = nil, completed: @escaping (Result, Error>) -> Void) -> ListOperation? { guard let url = listURL(page: page) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetch(jwt: jwt, url: url, completed: completed) - return - } + let listOperation = ListOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetch(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(listOperation) + return listOperation } - } - - internal static func fetch(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseList? - do { - result = try decoder.decode(ResponseList.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - guard let responseResult = result else { - completed(Result.failure(TrefleError.generalError)) - return - } - - completed(Result.success(responseResult)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + listOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, listOperation], waitUntilFinished: false) + return listOperation } // MARK: - Fetch Family - public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) -> ItemOperation? { guard let url = itemURL(identifier: identifier) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetchItem(jwt: jwt, url: url, completed: completed) - return - } + let itemOperation = ItemOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetchItem(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(itemOperation) + return itemOperation } - } - - internal static func fetchItem(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseItem - do { - result = try decoder.decode(ResponseItem.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - completed(Result.success(result)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + itemOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, itemOperation], waitUntilFinished: false) + return itemOperation } } diff --git a/Source/Manager/GenusManager.swift b/Source/Manager/GenusManager.swift index c5cdaf3..fa56a1b 100644 --- a/Source/Manager/GenusManager.swift +++ b/Source/Manager/GenusManager.swift @@ -40,125 +40,52 @@ public class GenusManager { // MARK: - Fetch Genus - public static func fetch(page: Int? = nil, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetch(page: Int? = nil, completed: @escaping (Result, Error>) -> Void) -> ListOperation? { guard let url = listURL(page: page) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetch(jwt: jwt, url: url, completed: completed) - return - } + let listOperation = ListOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetch(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(listOperation) + return listOperation } - } - - internal static func fetch(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseList? - do { - result = try decoder.decode(ResponseList.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - guard let responseResult = result else { - completed(Result.failure(TrefleError.generalError)) - return - } - - completed(Result.success(responseResult)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + listOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, listOperation], waitUntilFinished: false) + return listOperation } // MARK: - Fetch Genus - public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) -> ItemOperation? { guard let url = itemURL(identifier: identifier) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetchItem(jwt: jwt, url: url, completed: completed) - return - } + let itemOperation = ItemOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetchItem(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(itemOperation) + return itemOperation } - } - - internal static func fetchItem(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseItem - do { - result = try decoder.decode(ResponseItem.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - completed(Result.success(result)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + itemOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, itemOperation], waitUntilFinished: false) + return itemOperation } } diff --git a/Source/Manager/KingdomsManager.swift b/Source/Manager/KingdomsManager.swift index bb95bf5..e7916f2 100644 --- a/Source/Manager/KingdomsManager.swift +++ b/Source/Manager/KingdomsManager.swift @@ -37,125 +37,52 @@ public class KingdomsManager { // MARK: - Fetch Kingdoms - public static func fetch(page: Int? = nil, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetch(page: Int? = nil, completed: @escaping (Result, Error>) -> Void) -> ListOperation? { guard let url = listURL(page: page) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetch(jwt: jwt, url: url, completed: completed) - return - } + let listOperation = ListOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetch(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(listOperation) + return listOperation } - } - - internal static func fetch(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseList? - do { - result = try decoder.decode(ResponseList.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - guard let responseResult = result else { - completed(Result.failure(TrefleError.generalError)) - return - } - - completed(Result.success(responseResult)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + listOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, listOperation], waitUntilFinished: false) + return listOperation } // MARK: - Fetch Kingdom - public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) -> ItemOperation? { guard let url = itemURL(identifier: identifier) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetchItem(jwt: jwt, url: url, completed: completed) - return - } + let itemOperation = ItemOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetchItem(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(itemOperation) + return itemOperation } - } - - internal static func fetchItem(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseItem - do { - result = try decoder.decode(ResponseItem.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - completed(Result.success(result)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + itemOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, itemOperation], waitUntilFinished: false) + return itemOperation } } diff --git a/Source/Manager/PlantsManager.swift b/Source/Manager/PlantsManager.swift index 51d484b..d8a233a 100644 --- a/Source/Manager/PlantsManager.swift +++ b/Source/Manager/PlantsManager.swift @@ -99,6 +99,7 @@ public class PlantsManager { // MARK: - Search Plants + @discardableResult public static func search(query: String, filter: Filter? = nil, exclude: Exclude? = nil, order: SortOrder? = nil, range: Range? = nil, page: Int? = nil, completed: @escaping (Result, Error>) -> Void) -> ListOperation? { guard let url = listURL(query: query, filter: filter, exclude: exclude, order: order, range: range, page: page) else { @@ -123,6 +124,7 @@ public class PlantsManager { // MARK: - Fetch Plants in Distribution Zone + @discardableResult public static func fetchInDistributionZone(with zoneId: String, filter: Filter? = nil, exclude: Exclude? = nil, order: SortOrder? = nil, range: Range? = nil, page: Int? = nil, completed: @escaping (Result, Error>) -> Void) -> ListOperation? { guard let url = listURL(zoneId: zoneId, filter: filter, exclude: exclude, order: order, range: range, page: page) else { @@ -147,6 +149,7 @@ public class PlantsManager { // MARK: - Fetch Plants of a Genus + @discardableResult public static func fetchOfGenus(with genusId: String, filter: Filter? = nil, exclude: Exclude? = nil, order: SortOrder? = nil, range: Range? = nil, page: Int? = nil, completed: @escaping (Result, Error>) -> Void) -> ListOperation? { guard let url = listURL(genusId: genusId, filter: filter, exclude: exclude, order: order, range: range, page: page) else { @@ -179,19 +182,19 @@ public class PlantsManager { return nil } - let listOperation = ItemOperation(url: url, completionBlock: completed) + let itemOperation = ItemOperation(url: url, completionBlock: completed) guard Trefle.shared.isValid == false else { - Trefle.operationQueue.addOperation(listOperation) - return listOperation + Trefle.operationQueue.addOperation(itemOperation) + return itemOperation } let claimTokenOperation = ClaimTokenOperation() - listOperation.addDependency(claimTokenOperation) + itemOperation.addDependency(claimTokenOperation) - Trefle.operationQueue.addOperations([claimTokenOperation, listOperation], waitUntilFinished: false) - return listOperation + Trefle.operationQueue.addOperations([claimTokenOperation, itemOperation], waitUntilFinished: false) + return itemOperation } } diff --git a/Source/Manager/SpeciesManager.swift b/Source/Manager/SpeciesManager.swift index a843f2f..9ac6be3 100644 --- a/Source/Manager/SpeciesManager.swift +++ b/Source/Manager/SpeciesManager.swift @@ -70,125 +70,52 @@ public class SpeciesManager { // MARK: - Fetch Species - public static func fetch(query: String? = nil, filter: Filter? = nil, exclude: Exclude? = nil, order: SortOrder? = nil, range: Range? = nil, page: Int? = nil, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetch(query: String? = nil, filter: Filter? = nil, exclude: Exclude? = nil, order: SortOrder? = nil, range: Range? = nil, page: Int? = nil, completed: @escaping (Result, Error>) -> Void) -> ListOperation? { guard let url = listURL(page: page) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetch(jwt: jwt, url: url, completed: completed) - return - } + let listOperation = ListOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetch(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(listOperation) + return listOperation } - } - - internal static func fetch(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseList? - do { - result = try decoder.decode(ResponseList.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - guard let responseResult = result else { - completed(Result.failure(TrefleError.generalError)) - return - } - - completed(Result.success(responseResult)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + listOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, listOperation], waitUntilFinished: false) + return listOperation } // MARK: - Fetch Species - public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) -> ItemOperation? { guard let url = itemURL(identifier: identifier) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetchItem(jwt: jwt, url: url, completed: completed) - return - } + let itemOperation = ItemOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetchItem(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(itemOperation) + return itemOperation } - } - - internal static func fetchItem(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseItem - do { - result = try decoder.decode(ResponseItem.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - completed(Result.success(result)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + itemOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, itemOperation], waitUntilFinished: false) + return itemOperation } } diff --git a/Source/Manager/SubkingdomsManager.swift b/Source/Manager/SubkingdomsManager.swift index 1c7ca5d..c5d6982 100644 --- a/Source/Manager/SubkingdomsManager.swift +++ b/Source/Manager/SubkingdomsManager.swift @@ -37,125 +37,52 @@ public class SubkingdomsManager { // MARK: - Fetch Subkingdoms - public static func fetch(page: Int? = nil, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetch(page: Int? = nil, completed: @escaping (Result, Error>) -> Void) -> ListOperation? { guard let url = listURL(page: page) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetch(jwt: jwt, url: url, completed: completed) - return - } + let listOperation = ListOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetch(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(listOperation) + return listOperation } - } - - internal static func fetch(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseList? - do { - result = try decoder.decode(ResponseList.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - guard let responseResult = result else { - completed(Result.failure(TrefleError.generalError)) - return - } - - completed(Result.success(responseResult)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + listOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, listOperation], waitUntilFinished: false) + return listOperation } // MARK: - Fetch Subkingdom - public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) { - - guard let jwt = Trefle.shared.jwt else { - completed(Result.failure(TrefleError.noJWT)) - return - } + @discardableResult + public static func fetchItem(identifier: String, completed: @escaping (Result, Error>) -> Void) -> ItemOperation? { guard let url = itemURL(identifier: identifier) else { completed(Result.failure(TrefleError.badURL)) - return + return nil } - guard Trefle.shared.isValid == false else { - fetchItem(jwt: jwt, url: url, completed: completed) - return - } + let itemOperation = ItemOperation(url: url, completionBlock: completed) - Trefle.claimToken { (result) in + guard Trefle.shared.isValid == false else { - switch result { - case .success: - fetchItem(jwt: jwt, url: url, completed: completed) - case .failure(let error): - completed(Result.failure(error)) - } + Trefle.operationQueue.addOperation(itemOperation) + return itemOperation } - } - - internal static func fetchItem(jwt: String, url: URL, completed: @escaping (Result, Error>) -> Void) { - let urlRequest = URLRequest.jsonRequest(url: url, jwt: jwt) - let downloadTask = URLSession.shared.dataTask(with: urlRequest) { (data, _, error) in - - if let error = error { - completed(Result.failure(error)) - return - } - - guard let data = data else { - completed(Result.failure(TrefleError.noData)) - return - } - - let decoder = JSONDecoder.customJSONDecoder - let result: ResponseItem - do { - result = try decoder.decode(ResponseItem.self, from: data) - } catch { - completed(Result.failure(error)) - return - } - - completed(Result.success(result)) - } - downloadTask.resume() + let claimTokenOperation = ClaimTokenOperation() + itemOperation.addDependency(claimTokenOperation) + + Trefle.operationQueue.addOperations([claimTokenOperation, itemOperation], waitUntilFinished: false) + return itemOperation } } From eb062ee051fa38d42302342aa92cb1aea8a0d2ae Mon Sep 17 00:00:00 2001 From: James Barrow Date: Mon, 12 Oct 2020 16:33:06 +0200 Subject: [PATCH 12/15] Updated tests for operations --- Tests/DistributionZonesTests.swift | 6 ++++-- Tests/DivisionClassesTests.swift | 9 ++++++--- Tests/DivisionOrdersTests.swift | 9 ++++++--- Tests/DivisionsTests.swift | 6 ++++-- Tests/FamiliesTests.swift | 12 ++++++++---- Tests/GenusTests.swift | 12 ++++++++---- Tests/KingdomsTests.swift | 6 ++++-- Tests/SpeciesTests.swift | 15 ++++++++++----- Tests/SubkingdomsTests.swift | 6 ++++-- 9 files changed, 54 insertions(+), 27 deletions(-) diff --git a/Tests/DistributionZonesTests.swift b/Tests/DistributionZonesTests.swift index dfa4251..59a46d6 100644 --- a/Tests/DistributionZonesTests.swift +++ b/Tests/DistributionZonesTests.swift @@ -27,7 +27,7 @@ class DistributionZonesTests: XCTestCase { let expectation = self.expectation(description: #function) - DistributionZonesManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let page): @@ -39,6 +39,7 @@ class DistributionZonesTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -59,7 +60,7 @@ class DistributionZonesTests: XCTestCase { let expectation = self.expectation(description: #function) - DistributionZonesManager.fetchItem(jwt: config.accessToken, url: url) { (result) in + let operation = ItemOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -71,6 +72,7 @@ class DistributionZonesTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") diff --git a/Tests/DivisionClassesTests.swift b/Tests/DivisionClassesTests.swift index f9ab671..8a6fce3 100644 --- a/Tests/DivisionClassesTests.swift +++ b/Tests/DivisionClassesTests.swift @@ -27,7 +27,7 @@ class DivisionClassesTests: XCTestCase { let expectation = self.expectation(description: #function) - DivisionClassesManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let page): @@ -39,6 +39,7 @@ class DivisionClassesTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -60,7 +61,7 @@ class DivisionClassesTests: XCTestCase { let expectation = self.expectation(description: #function) - DivisionClassesManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -78,6 +79,7 @@ class DivisionClassesTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -98,7 +100,7 @@ class DivisionClassesTests: XCTestCase { let expectation = self.expectation(description: #function) - DivisionClassesManager.fetchItem(jwt: config.accessToken, url: url) { (result) in + let operation = ItemOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -110,6 +112,7 @@ class DivisionClassesTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") diff --git a/Tests/DivisionOrdersTests.swift b/Tests/DivisionOrdersTests.swift index f5fa7c8..b32b2bb 100644 --- a/Tests/DivisionOrdersTests.swift +++ b/Tests/DivisionOrdersTests.swift @@ -27,7 +27,7 @@ class DivisionOrdersTests: XCTestCase { let expectation = self.expectation(description: #function) - DivisionOrdersManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let page): @@ -39,6 +39,7 @@ class DivisionOrdersTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -60,7 +61,7 @@ class DivisionOrdersTests: XCTestCase { let expectation = self.expectation(description: #function) - DivisionOrdersManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -78,6 +79,7 @@ class DivisionOrdersTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -98,7 +100,7 @@ class DivisionOrdersTests: XCTestCase { let expectation = self.expectation(description: #function) - DivisionOrdersManager.fetchItem(jwt: config.accessToken, url: url) { (result) in + let operation = ItemOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -110,6 +112,7 @@ class DivisionOrdersTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") diff --git a/Tests/DivisionsTests.swift b/Tests/DivisionsTests.swift index 6b510bd..92e21c1 100644 --- a/Tests/DivisionsTests.swift +++ b/Tests/DivisionsTests.swift @@ -27,7 +27,7 @@ class DivisionsTests: XCTestCase { let expectation = self.expectation(description: #function) - DivisionsManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let page): @@ -39,6 +39,7 @@ class DivisionsTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -59,7 +60,7 @@ class DivisionsTests: XCTestCase { let expectation = self.expectation(description: #function) - DivisionsManager.fetchItem(jwt: config.accessToken, url: url) { (result) in + let operation = ItemOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -71,6 +72,7 @@ class DivisionsTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") diff --git a/Tests/FamiliesTests.swift b/Tests/FamiliesTests.swift index a662ce5..8086bb2 100644 --- a/Tests/FamiliesTests.swift +++ b/Tests/FamiliesTests.swift @@ -27,7 +27,7 @@ class FamiliesTests: XCTestCase { let expectation = self.expectation(description: #function) - FamiliesManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let page): @@ -39,6 +39,7 @@ class FamiliesTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -59,7 +60,7 @@ class FamiliesTests: XCTestCase { let expectation = self.expectation(description: #function) - FamiliesManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -71,6 +72,7 @@ class FamiliesTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -92,7 +94,7 @@ class FamiliesTests: XCTestCase { let expectation = self.expectation(description: #function) - FamiliesManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -110,6 +112,7 @@ class FamiliesTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -130,7 +133,7 @@ class FamiliesTests: XCTestCase { let expectation = self.expectation(description: #function) - FamiliesManager.fetchItem(jwt: config.accessToken, url: url) { (result) in + let operation = ItemOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -142,6 +145,7 @@ class FamiliesTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") diff --git a/Tests/GenusTests.swift b/Tests/GenusTests.swift index 90f33a1..2399521 100644 --- a/Tests/GenusTests.swift +++ b/Tests/GenusTests.swift @@ -27,7 +27,7 @@ class GenusTests: XCTestCase { let expectation = self.expectation(description: #function) - GenusManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let page): @@ -39,6 +39,7 @@ class GenusTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -59,7 +60,7 @@ class GenusTests: XCTestCase { let expectation = self.expectation(description: #function) - GenusManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -71,6 +72,7 @@ class GenusTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -92,7 +94,7 @@ class GenusTests: XCTestCase { let expectation = self.expectation(description: #function) - GenusManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -110,6 +112,7 @@ class GenusTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -130,7 +133,7 @@ class GenusTests: XCTestCase { let expectation = self.expectation(description: #function) - GenusManager.fetchItem(jwt: config.accessToken, url: url) { (result) in + let operation = ItemOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -142,6 +145,7 @@ class GenusTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") diff --git a/Tests/KingdomsTests.swift b/Tests/KingdomsTests.swift index 0ba6c60..74e8aaf 100644 --- a/Tests/KingdomsTests.swift +++ b/Tests/KingdomsTests.swift @@ -27,7 +27,7 @@ class KingdomsTests: XCTestCase { let expectation = self.expectation(description: #function) - KingdomsManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let page): @@ -39,6 +39,7 @@ class KingdomsTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -59,7 +60,7 @@ class KingdomsTests: XCTestCase { let expectation = self.expectation(description: #function) - KingdomsManager.fetchItem(jwt: config.accessToken, url: url) { (result) in + let operation = ItemOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -71,6 +72,7 @@ class KingdomsTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") diff --git a/Tests/SpeciesTests.swift b/Tests/SpeciesTests.swift index f3d534c..ed09664 100644 --- a/Tests/SpeciesTests.swift +++ b/Tests/SpeciesTests.swift @@ -27,7 +27,7 @@ class SpeciesTests: XCTestCase { let expectation = self.expectation(description: #function) - SpeciesManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let page): @@ -39,6 +39,7 @@ class SpeciesTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -59,7 +60,7 @@ class SpeciesTests: XCTestCase { let expectation = self.expectation(description: #function) - SpeciesManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -71,6 +72,7 @@ class SpeciesTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -92,7 +94,7 @@ class SpeciesTests: XCTestCase { let expectation = self.expectation(description: #function) - SpeciesManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -110,6 +112,7 @@ class SpeciesTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -130,7 +133,7 @@ class SpeciesTests: XCTestCase { let expectation = self.expectation(description: #function) - SpeciesManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -142,6 +145,7 @@ class SpeciesTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -162,7 +166,7 @@ class SpeciesTests: XCTestCase { let expectation = self.expectation(description: #function) - SpeciesManager.fetchItem(jwt: config.accessToken, url: url) { (result) in + let operation = ItemOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -174,6 +178,7 @@ class SpeciesTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") diff --git a/Tests/SubkingdomsTests.swift b/Tests/SubkingdomsTests.swift index d54f08c..d7038a0 100644 --- a/Tests/SubkingdomsTests.swift +++ b/Tests/SubkingdomsTests.swift @@ -27,7 +27,7 @@ class SubkingdomsTests: XCTestCase { let expectation = self.expectation(description: #function) - SubkingdomsManager.fetch(jwt: config.accessToken, url: url) { (result) in + let operation = ListOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let page): @@ -39,6 +39,7 @@ class SubkingdomsTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") @@ -59,7 +60,7 @@ class SubkingdomsTests: XCTestCase { let expectation = self.expectation(description: #function) - SubkingdomsManager.fetchItem(jwt: config.accessToken, url: url) { (result) in + let operation = ItemOperation(jwt: config.accessToken, url: url) { (result) in switch result { case .success(let response): @@ -71,6 +72,7 @@ class SubkingdomsTests: XCTestCase { expectation.fulfill() } + Trefle.operationQueue.addOperation(operation) waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, error?.localizedDescription ?? "") From 57c59f6483ea300d46f4c11e35f549cb55f40b14 Mon Sep 17 00:00:00 2001 From: James Barrow Date: Mon, 12 Oct 2020 16:33:15 +0200 Subject: [PATCH 13/15] Updated readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 332df7c..c0e70e7 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,9 @@ This is currently a work in progress. There is a list of currently supported fea - [x] Plants - [x] Species - [x] Distribution Zones -- [ ] Operations for all types +- [x] Operation support - [ ] Combine support -- [ ] Error Handling +- [ ] Full error handling - [x] Basic test suite - [ ] Deep test suite From b30c537f6319656e73e0db5fe132f152b687b219 Mon Sep 17 00:00:00 2001 From: James Barrow Date: Mon, 12 Oct 2020 16:34:30 +0200 Subject: [PATCH 14/15] Removed no longer needed plant operations --- Source/Operations/Plants/PlantOperation.swift | 90 ----------------- .../Plants/PlantRefsOperation.swift | 98 ------------------- TrefleSwiftSDK.xcodeproj/project.pbxproj | 16 --- 3 files changed, 204 deletions(-) delete mode 100644 Source/Operations/Plants/PlantOperation.swift delete mode 100644 Source/Operations/Plants/PlantRefsOperation.swift diff --git a/Source/Operations/Plants/PlantOperation.swift b/Source/Operations/Plants/PlantOperation.swift deleted file mode 100644 index 6984785..0000000 --- a/Source/Operations/Plants/PlantOperation.swift +++ /dev/null @@ -1,90 +0,0 @@ -// -// PlantOperation.swift -// TrefleSwiftSDK -// -// Created by James Barrow on 2020-10-06. -// Copyright © 2020 Pig on a Hill Productions. All rights reserved. -// - -import Foundation - -public class PlantOperation: Operation { - - public var plantCompletionBlock: ((_ result: Result, Error>) -> Void)? - - public var identifier: String - public var response: ResponseItem? - public var error: Error? - public override var isAsynchronous: Bool { - return true - } - public override var isConcurrent: Bool { - return true - } - private var _isExecuting: Bool = false { - willSet { willChangeValue(forKey: "isExecuting") } - didSet { didChangeValue(forKey: "isExecuting") } - } - public override var isExecuting: Bool { - return _isExecuting - } - private var _isFinished: Bool = false { - willSet { willChangeValue(forKey: "isFinished") } - didSet { didChangeValue(forKey: "isFinished") } - } - public override var isFinished: Bool { - return _isFinished - } - - public init(identifier: String, completionBlock: ((_ result: Result, Error>) -> Void)? = nil) { - self.identifier = identifier - self.plantCompletionBlock = completionBlock - } - - public override func start() { - - if isExecuting == true { - return - } - - // Check if canceled, if so then return - if isCancelled == true { - - // Finish - _isFinished = true - return - } - - _isExecuting = true - - PlantsManager.fetchItem(identifier: identifier) { [weak self] (result) in - - guard let self = self else { - return - } - - // Check if canceled, if so then return - if self.isCancelled == true { - - // Finish - self._isExecuting = false - self._isFinished = true - return - } - - switch result { - case .success(let response): - self.response = response - case .failure(let error): - self.error = error - } - - self.plantCompletionBlock?(result) - - // Finish - self._isExecuting = false - self._isFinished = true - } - } - -} diff --git a/Source/Operations/Plants/PlantRefsOperation.swift b/Source/Operations/Plants/PlantRefsOperation.swift deleted file mode 100644 index f6ebe91..0000000 --- a/Source/Operations/Plants/PlantRefsOperation.swift +++ /dev/null @@ -1,98 +0,0 @@ -// -// PlantRefsOperation.swift -// TrefleSwiftSDK -// -// Created by James Barrow on 2020-04-25. -// Copyright © 2020 Pig on a Hill Productions. All rights reserved. -// - -import Foundation - -public class PlantRefsOperation: Operation { - - public var plantRefsCompletionBlock: ((_ result: Result, Error>) -> Void)? - - public let filter: PlantsManager.Filter? - public let exclude: PlantsManager.Exclude? - public let order: PlantsManager.SortOrder? - public let range: PlantsManager.Range? - public let page: Int? - public var response: ResponseList? - public var error: Error? - public override var isAsynchronous: Bool { - return true - } - public override var isConcurrent: Bool { - return true - } - private var _isExecuting: Bool = false { - willSet { willChangeValue(forKey: "isExecuting") } - didSet { didChangeValue(forKey: "isExecuting") } - } - public override var isExecuting: Bool { - return _isExecuting - } - private var _isFinished: Bool = false { - willSet { willChangeValue(forKey: "isFinished") } - didSet { didChangeValue(forKey: "isFinished") } - } - public override var isFinished: Bool { - return _isFinished - } - - public init(filter: PlantsManager.Filter? = nil, exclude: PlantsManager.Exclude? = nil, order: PlantsManager.SortOrder? = nil, range: PlantsManager.Range? = nil, page: Int? = nil, completionBlock: ((_ result: Result, Error>) -> Void)? = nil) { - self.filter = filter - self.exclude = exclude - self.order = order - self.range = range - self.page = page - self.plantRefsCompletionBlock = completionBlock - } - - public override func start() { - - if isExecuting == true { - return - } - - // Check if canceled, if so then return - if isCancelled == true { - - // Finish - _isFinished = true - return - } - - _isExecuting = true - - PlantsManager.fetch(filter: filter, exclude: exclude, order: order, range: range, page: page) { [weak self] (result) in - - guard let self = self else { - return - } - - // Check if canceled, if so then return - if self.isCancelled == true { - - // Finish - self._isExecuting = false - self._isFinished = true - return - } - - switch result { - case .success(let response): - self.response = response - case .failure(let error): - self.error = error - } - - self.plantRefsCompletionBlock?(result) - - // Finish - self._isExecuting = false - self._isFinished = true - } - } - -} diff --git a/TrefleSwiftSDK.xcodeproj/project.pbxproj b/TrefleSwiftSDK.xcodeproj/project.pbxproj index 7400a20..e1d104b 100644 --- a/TrefleSwiftSDK.xcodeproj/project.pbxproj +++ b/TrefleSwiftSDK.xcodeproj/project.pbxproj @@ -50,7 +50,6 @@ 188CA1622528941200C26F55 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 188CA1612528941200C26F55 /* Color.swift */; }; 188CA1662528942600C26F55 /* Texture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 188CA1652528942600C26F55 /* Texture.swift */; }; 1893393C252C80280099AADF /* GenusManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1893393B252C80280099AADF /* GenusManager.swift */; }; - 18933944252CE75F0099AADF /* PlantOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18933943252CE75F0099AADF /* PlantOperation.swift */; }; 18C3D77A25260B69006B6413 /* Order.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C3D77925260B69006B6413 /* Order.swift */; }; 18C3D77E2526636F006B6413 /* ImageCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C3D77D2526636F006B6413 /* ImageCollection.swift */; }; 18C3D78225266BC9006B6413 /* Synonym.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C3D78125266BC9006B6413 /* Synonym.swift */; }; @@ -76,7 +75,6 @@ 18D1185F252C6ED90004DC72 /* SpeciesRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18D1185E252C6ED90004DC72 /* SpeciesRange.swift */; }; 18D11863252C77810004DC72 /* DistributionZonesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18D11862252C77810004DC72 /* DistributionZonesManager.swift */; }; 18D11869252C78DA0004DC72 /* DistributionZonesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18D11868252C78DA0004DC72 /* DistributionZonesTests.swift */; }; - 18DF92662454D9800034A058 /* PlantRefsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18DF92652454D9800034A058 /* PlantRefsOperation.swift */; }; 18E787E7245623B80064F78D /* Plant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18E787E6245623B80064F78D /* Plant.swift */; }; 18E787EA2456278F0064F78D /* ImageRef.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18E787E92456278F0064F78D /* ImageRef.swift */; }; 18E787F224562BAF0064F78D /* Kingdom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18E787F124562BAF0064F78D /* Kingdom.swift */; }; @@ -162,7 +160,6 @@ 188CA1612528941200C26F55 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; 188CA1652528942600C26F55 /* Texture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Texture.swift; sourceTree = ""; }; 1893393B252C80280099AADF /* GenusManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenusManager.swift; sourceTree = ""; }; - 18933943252CE75F0099AADF /* PlantOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlantOperation.swift; sourceTree = ""; }; 18C3D77925260B69006B6413 /* Order.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Order.swift; sourceTree = ""; }; 18C3D77D2526636F006B6413 /* ImageCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCollection.swift; sourceTree = ""; }; 18C3D78125266BC9006B6413 /* Synonym.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Synonym.swift; sourceTree = ""; }; @@ -188,7 +185,6 @@ 18D1185E252C6ED90004DC72 /* SpeciesRange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpeciesRange.swift; sourceTree = ""; }; 18D11862252C77810004DC72 /* DistributionZonesManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DistributionZonesManager.swift; sourceTree = ""; }; 18D11868252C78DA0004DC72 /* DistributionZonesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DistributionZonesTests.swift; sourceTree = ""; }; - 18DF92652454D9800034A058 /* PlantRefsOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlantRefsOperation.swift; sourceTree = ""; }; 18E787E6245623B80064F78D /* Plant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Plant.swift; sourceTree = ""; }; 18E787E92456278F0064F78D /* ImageRef.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRef.swift; sourceTree = ""; }; 18E787F124562BAF0064F78D /* Kingdom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Kingdom.swift; sourceTree = ""; }; @@ -456,20 +452,10 @@ 181CAAD4253329F5009A252C /* ListOperation.swift */, 181CAADA25338DC6009A252C /* ItemOperation.swift */, 181CAACF2533232E009A252C /* Authentication */, - 18DF92642454D9640034A058 /* Plants */, ); path = Operations; sourceTree = ""; }; - 18DF92642454D9640034A058 /* Plants */ = { - isa = PBXGroup; - children = ( - 18DF92652454D9800034A058 /* PlantRefsOperation.swift */, - 18933943252CE75F0099AADF /* PlantOperation.swift */, - ); - path = Plants; - sourceTree = ""; - }; 18E787E8245627750064F78D /* Image */ = { isa = PBXGroup; children = ( @@ -710,7 +696,6 @@ 18C3D78A252674FE006B6413 /* Zone.swift in Sources */, 187A8FA424E704510021B640 /* Metadata.swift in Sources */, 18E7882424576B1D0064F78D /* FruitOrSeed.swift in Sources */, - 18DF92662454D9800034A058 /* PlantRefsOperation.swift in Sources */, 18D11853252C6EB80004DC72 /* SpeciesFilter.swift in Sources */, 18E787F424562C700064F78D /* SubkingdomRef.swift in Sources */, 18E7880E245631FB0064F78D /* Genus.swift in Sources */, @@ -722,7 +707,6 @@ 18D11815252BA3EB0004DC72 /* FamilyFilter.swift in Sources */, 18C3D77A25260B69006B6413 /* Order.swift in Sources */, 18C3D77E2526636F006B6413 /* ImageCollection.swift in Sources */, - 18933944252CE75F0099AADF /* PlantOperation.swift in Sources */, 18D1185B252C6ED00004DC72 /* SpeciesSortOrder.swift in Sources */, 1893393C252C80280099AADF /* GenusManager.swift in Sources */, 183B16C2252A6006007C7A72 /* DivisionsManager.swift in Sources */, From 31b02df3ff3715b03a65279bb5c1cbd195d450d7 Mon Sep 17 00:00:00 2001 From: James Barrow Date: Mon, 12 Oct 2020 16:35:12 +0200 Subject: [PATCH 15/15] Bumped to 0.0.3 (3) --- TrefleSwiftSDK.podspec | 2 +- TrefleSwiftSDK.xcodeproj/project.pbxproj | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/TrefleSwiftSDK.podspec b/TrefleSwiftSDK.podspec index 54705c5..0441d38 100644 --- a/TrefleSwiftSDK.podspec +++ b/TrefleSwiftSDK.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "TrefleSwiftSDK" - s.version = "0.0.2" + s.version = "0.0.3" s.summary = "TrefleSwiftSDK is a Swift wrapper around the Trefle API." s.homepage = "https://github.com/Baza207/TrefleSwiftSDK" s.license = { :type => "MIT", :file => "LICENSE" } diff --git a/TrefleSwiftSDK.xcodeproj/project.pbxproj b/TrefleSwiftSDK.xcodeproj/project.pbxproj index e1d104b..ef33e86 100644 --- a/TrefleSwiftSDK.xcodeproj/project.pbxproj +++ b/TrefleSwiftSDK.xcodeproj/project.pbxproj @@ -902,7 +902,7 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = M5BBZ59SV2; DYLIB_COMPATIBILITY_VERSION = 1; @@ -916,7 +916,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 0.0.2; + MARKETING_VERSION = 0.0.3; PRODUCT_BUNDLE_IDENTIFIER = com.PigonaHill.TrefleSwiftSDK; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -932,7 +932,7 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = M5BBZ59SV2; DYLIB_COMPATIBILITY_VERSION = 1; @@ -946,7 +946,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 0.0.2; + MARKETING_VERSION = 0.0.3; PRODUCT_BUNDLE_IDENTIFIER = com.PigonaHill.TrefleSwiftSDK; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES;