From bc4f9835a5ca5d21ea3eb4893dd9c7c948cca5a5 Mon Sep 17 00:00:00 2001 From: Madhas Date: Sat, 12 May 2018 14:44:45 +0300 Subject: [PATCH 01/32] update Post model --- Tests/Models/Post.swift | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Tests/Models/Post.swift b/Tests/Models/Post.swift index ab6a170d..dfb71c3b 100644 --- a/Tests/Models/Post.swift +++ b/Tests/Models/Post.swift @@ -22,19 +22,23 @@ import ObjectMapper -struct Post: ImmutableMappable { +struct Post: Decodable { + + enum CodingKeys: String, CodingKey { + case userId + case postId = "id" + case title + case body + } let userId: Int let postId: Int let title: String let body: String - init(userId: Int, postId: Int, title: String, body: String) { - self.userId = userId - self.postId = postId - self.title = title - self.body = body - } +} + +extension Post: ImmutableMappable { init(map: Map) throws { userId = try map.value("userId") @@ -42,14 +46,13 @@ struct Post: ImmutableMappable { title = try map.value("title") body = try map.value("body") } - + mutating func mapping(map: Map) { userId >>> map["userId"] postId >>> map["id"] title >>> map["title"] body >>> map["body"] } - } extension Post: Equatable { From d53db408fd77302c18f9d0c677a109d630d1c57c Mon Sep 17 00:00:00 2001 From: Madhas Date: Sat, 12 May 2018 15:34:56 +0300 Subject: [PATCH 02/32] remove some files from tests target --- LeadKit.xcodeproj/project.pbxproj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index 3d14bcd8..896bdc19 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -503,9 +503,7 @@ 67FDC2621FA310EA00C76A77 /* RequestError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67FDC25E1FA310EA00C76A77 /* RequestError.swift */; }; 82F8BB181F5DDED100C1061B /* Single+DeferredJust.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F8BB171F5DDED100C1061B /* Single+DeferredJust.swift */; }; A658E54D1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A658E54C1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift */; }; - A658E54E1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A658E54C1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift */; }; A658E5501F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A658E54F1F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift */; }; - A658E5511F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A658E54F1F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift */; }; A676AE481F97D28A001F9214 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A676AE471F97D28A001F9214 /* String+Extensions.swift */; }; A676AE491F97D28A001F9214 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A676AE471F97D28A001F9214 /* String+Extensions.swift */; }; A676AE4A1F97D28A001F9214 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A676AE471F97D28A001F9214 /* String+Extensions.swift */; }; @@ -527,8 +525,6 @@ A6E0DDDE1F8A696F002CA74E /* EmptyCellRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A66428A71F8A654600C6308D /* EmptyCellRow.swift */; }; A6E0DDDF1F8A696F002CA74E /* SeparatorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A66428A61F8A653600C6308D /* SeparatorCell.swift */; }; A6E0DDE11F8A696F002CA74E /* SeparatorRowBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = A66428A81F8A655600C6308D /* SeparatorRowBox.swift */; }; - A6E0DDE31F8A696F002CA74E /* SeparatorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A66428A61F8A653600C6308D /* SeparatorCell.swift */; }; - A6E0DDE51F8A696F002CA74E /* SeparatorRowBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = A66428A81F8A655600C6308D /* SeparatorRowBox.swift */; }; A6E0DDF11F8A6C80002CA74E /* SeparatorConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6E0DDF01F8A6C80002CA74E /* SeparatorConfiguration.swift */; }; A6F32C081F6EBDAA00AC08EE /* String+LocalizedComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6F32C071F6EBDAA00AC08EE /* String+LocalizedComponent.swift */; }; A6F32C0A1F6EBE5B00AC08EE /* String+LocalizedComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6F32C071F6EBDAA00AC08EE /* String+LocalizedComponent.swift */; }; @@ -2723,15 +2719,11 @@ A6C9A5051F8BC78F009311CC /* SeparatorConfiguration.swift in Sources */, 671463CA1EB34B1E00EAB194 /* TestView.swift in Sources */, 671463B81EB34B1E00EAB194 /* StubCursor.swift in Sources */, - A658E54E1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift in Sources */, - A658E5511F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift in Sources */, 671463BB1EB34B1E00EAB194 /* CursorTests.swift in Sources */, A6F32C101F6EBE9600AC08EE /* StringExtensionTests.swift in Sources */, 671463BE1EB34B1E00EAB194 /* LoadFromNibTests.swift in Sources */, - A6E0DDE31F8A696F002CA74E /* SeparatorCell.swift in Sources */, A6C9A50F1F8BC79D009311CC /* Comparable+Extensions.swift in Sources */, 671463C41EB34B1E00EAB194 /* Post.swift in Sources */, - A6E0DDE51F8A696F002CA74E /* SeparatorRowBox.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 17cd260d1e520d647a7883e2db40fd08541a66c9 Mon Sep 17 00:00:00 2001 From: Madhas Date: Sat, 12 May 2018 15:46:42 +0300 Subject: [PATCH 03/32] test request --- LeadKit.xcodeproj/project.pbxproj | 8 ++++ Tests/NetworkServiceTests.swift | 79 +++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 Tests/NetworkServiceTests.swift diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index 896bdc19..8db125c4 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -533,6 +533,9 @@ A6F32C101F6EBE9600AC08EE /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.swift */; }; A6F32C111F6EBE9700AC08EE /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.swift */; }; A6F32C121F6EBE9800AC08EE /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.swift */; }; + B84D64B120A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; + B84D64B220A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; + B84D64B320A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; BA6C6DB45950382041948FC5 /* Pods_LeadKit_LeadKit_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CFE9323150A9760008093F73 /* Pods_LeadKit_LeadKit_iOS.framework */; }; D6EE55093E404DEA62B03DDF /* Pods_LeadKit_LeadKit_watchOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8590CA7831555C295C5DC572 /* Pods_LeadKit_LeadKit_watchOS.framework */; }; DEE25FE98D40ED1C168F384A /* Pods_LeadKit_LeadKit_iOS_Extensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 887F99C5326BD220C2811BD6 /* Pods_LeadKit_LeadKit_iOS_Extensions.framework */; }; @@ -780,6 +783,7 @@ A6F32C071F6EBDAA00AC08EE /* String+LocalizedComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+LocalizedComponent.swift"; sourceTree = ""; }; A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtensionTests.swift; sourceTree = ""; }; A854A36EB179651E6D0CC9FB /* Pods_LeadKit_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKit_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkServiceTests.swift; sourceTree = ""; }; BECC6E4BF63781403877B059 /* Pods-LeadKit-LeadKit watchOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit-LeadKit watchOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit-LeadKit watchOS/Pods-LeadKit-LeadKit watchOS.release.xcconfig"; sourceTree = ""; }; CB02EAC4E52AF48AD64EC045 /* Pods-LeadKit iOS ExtensionsTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit iOS ExtensionsTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit iOS ExtensionsTests/Pods-LeadKit iOS ExtensionsTests.debug.xcconfig"; sourceTree = ""; }; CD7003F75FD6DDC97DC99A7A /* Pods-LeadKit iOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit iOSTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit iOSTests/Pods-LeadKit iOSTests.debug.xcconfig"; sourceTree = ""; }; @@ -1279,6 +1283,7 @@ 67186C1A1EB24B7800CFAFFB /* Info-iOS.plist */, 6782BBB91EB31DD90086E0B8 /* Info-tvOS.plist */, 671463B01EB34B1E00EAB194 /* LoadFromNibTests.swift */, + B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */, ); path = Tests; sourceTree = ""; @@ -2724,6 +2729,7 @@ 671463BE1EB34B1E00EAB194 /* LoadFromNibTests.swift in Sources */, A6C9A50F1F8BC79D009311CC /* Comparable+Extensions.swift in Sources */, 671463C41EB34B1E00EAB194 /* Post.swift in Sources */, + B84D64B120A70B7000DD76DA /* NetworkServiceTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2980,6 +2986,7 @@ buildActionMask = 2147483647; files = ( 671463CC1EB34B1E00EAB194 /* TestView.swift in Sources */, + B84D64B320A70B7000DD76DA /* NetworkServiceTests.swift in Sources */, 671463BA1EB34B1E00EAB194 /* StubCursor.swift in Sources */, 671463BD1EB34B1E00EAB194 /* CursorTests.swift in Sources */, A6F32C121F6EBE9800AC08EE /* StringExtensionTests.swift in Sources */, @@ -3136,6 +3143,7 @@ files = ( A6C9A5111F8BC79D009311CC /* Comparable+Extensions.swift in Sources */, 671463BF1EB34B1E00EAB194 /* LoadFromNibTests.swift in Sources */, + B84D64B220A70B7000DD76DA /* NetworkServiceTests.swift in Sources */, 671463C51EB34B1E00EAB194 /* Post.swift in Sources */, 671463CB1EB34B1E00EAB194 /* TestView.swift in Sources */, A6F32C111F6EBE9700AC08EE /* StringExtensionTests.swift in Sources */, diff --git a/Tests/NetworkServiceTests.swift b/Tests/NetworkServiceTests.swift new file mode 100644 index 00000000..47c281ca --- /dev/null +++ b/Tests/NetworkServiceTests.swift @@ -0,0 +1,79 @@ +// +// Copyright (c) 2017 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import XCTest +import LeadKit +import RxSwift + +class NetworkServiceTests: XCTestCase { + + var disposeBag: DisposeBag! + + var networkService: NetworkService! + + override func setUp() { + super.setUp() + + let configuration = NetworkServiceConfiguration(baseUrl: "") + networkService = NetworkService(configuration: configuration) + disposeBag = DisposeBag() + } + + override func tearDown() { + disposeBag = nil + networkService = nil + super.tearDown() + } + + func testModelRequest() { + // given + let expectedModel = Post(userId: 1, + postId: 1, + title: "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", + body: "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto") + + var receivedModel: Post? + var error: Error? + let requestCompletedExpectation = expectation(description: "Request completed") + let apiRequest = ApiRequestParameters(url: "https://jsonplaceholder.typicode.com/posts/1", + headers: ["Content-Type": "application/json"]) + + // when + networkService.rxRequest(with: apiRequest) + .subscribe(onNext: { (_, model: Post) in + receivedModel = model + requestCompletedExpectation.fulfill() + }, onError: { + error = $0 + requestCompletedExpectation.fulfill() + }) + .disposed(by: disposeBag) + + waitForExpectations(timeout: 20, handler: nil) + + // then + XCTAssertNil(error) + XCTAssertNotNil(receivedModel) + XCTAssertEqual(receivedModel, expectedModel) + } + +} From 0209e1b02183f832b1f025a34d443ac437a30106 Mon Sep 17 00:00:00 2001 From: Madhas Date: Sat, 12 May 2018 16:04:30 +0300 Subject: [PATCH 04/32] add ObservableMappable model --- LeadKit.xcodeproj/project.pbxproj | 8 ++++ Tests/Models/ObservableMappablePost.swift | 57 +++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 Tests/Models/ObservableMappablePost.swift diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index 8db125c4..645a270f 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -536,6 +536,9 @@ B84D64B120A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; B84D64B220A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; B84D64B320A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; + B84D64B620A71A8400DD76DA /* ObservableMappablePost.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B520A71A8400DD76DA /* ObservableMappablePost.swift */; }; + B84D64B720A71A8400DD76DA /* ObservableMappablePost.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B520A71A8400DD76DA /* ObservableMappablePost.swift */; }; + B84D64B820A71A8400DD76DA /* ObservableMappablePost.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B520A71A8400DD76DA /* ObservableMappablePost.swift */; }; BA6C6DB45950382041948FC5 /* Pods_LeadKit_LeadKit_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CFE9323150A9760008093F73 /* Pods_LeadKit_LeadKit_iOS.framework */; }; D6EE55093E404DEA62B03DDF /* Pods_LeadKit_LeadKit_watchOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8590CA7831555C295C5DC572 /* Pods_LeadKit_LeadKit_watchOS.framework */; }; DEE25FE98D40ED1C168F384A /* Pods_LeadKit_LeadKit_iOS_Extensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 887F99C5326BD220C2811BD6 /* Pods_LeadKit_LeadKit_iOS_Extensions.framework */; }; @@ -784,6 +787,7 @@ A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtensionTests.swift; sourceTree = ""; }; A854A36EB179651E6D0CC9FB /* Pods_LeadKit_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKit_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkServiceTests.swift; sourceTree = ""; }; + B84D64B520A71A8400DD76DA /* ObservableMappablePost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservableMappablePost.swift; sourceTree = ""; }; BECC6E4BF63781403877B059 /* Pods-LeadKit-LeadKit watchOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit-LeadKit watchOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit-LeadKit watchOS/Pods-LeadKit-LeadKit watchOS.release.xcconfig"; sourceTree = ""; }; CB02EAC4E52AF48AD64EC045 /* Pods-LeadKit iOS ExtensionsTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit iOS ExtensionsTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit iOS ExtensionsTests/Pods-LeadKit iOS ExtensionsTests.debug.xcconfig"; sourceTree = ""; }; CD7003F75FD6DDC97DC99A7A /* Pods-LeadKit iOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit iOSTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit iOSTests/Pods-LeadKit iOSTests.debug.xcconfig"; sourceTree = ""; }; @@ -1232,6 +1236,7 @@ isa = PBXGroup; children = ( 671463B31EB34B1E00EAB194 /* Post.swift */, + B84D64B520A71A8400DD76DA /* ObservableMappablePost.swift */, ); path = Models; sourceTree = ""; @@ -2723,6 +2728,7 @@ files = ( A6C9A5051F8BC78F009311CC /* SeparatorConfiguration.swift in Sources */, 671463CA1EB34B1E00EAB194 /* TestView.swift in Sources */, + B84D64B620A71A8400DD76DA /* ObservableMappablePost.swift in Sources */, 671463B81EB34B1E00EAB194 /* StubCursor.swift in Sources */, 671463BB1EB34B1E00EAB194 /* CursorTests.swift in Sources */, A6F32C101F6EBE9600AC08EE /* StringExtensionTests.swift in Sources */, @@ -2989,6 +2995,7 @@ B84D64B320A70B7000DD76DA /* NetworkServiceTests.swift in Sources */, 671463BA1EB34B1E00EAB194 /* StubCursor.swift in Sources */, 671463BD1EB34B1E00EAB194 /* CursorTests.swift in Sources */, + B84D64B820A71A8400DD76DA /* ObservableMappablePost.swift in Sources */, A6F32C121F6EBE9800AC08EE /* StringExtensionTests.swift in Sources */, 671463C01EB34B1E00EAB194 /* LoadFromNibTests.swift in Sources */, 671463C61EB34B1E00EAB194 /* Post.swift in Sources */, @@ -3146,6 +3153,7 @@ B84D64B220A70B7000DD76DA /* NetworkServiceTests.swift in Sources */, 671463C51EB34B1E00EAB194 /* Post.swift in Sources */, 671463CB1EB34B1E00EAB194 /* TestView.swift in Sources */, + B84D64B720A71A8400DD76DA /* ObservableMappablePost.swift in Sources */, A6F32C111F6EBE9700AC08EE /* StringExtensionTests.swift in Sources */, 671463BC1EB34B1E00EAB194 /* CursorTests.swift in Sources */, 671463B91EB34B1E00EAB194 /* StubCursor.swift in Sources */, diff --git a/Tests/Models/ObservableMappablePost.swift b/Tests/Models/ObservableMappablePost.swift new file mode 100644 index 00000000..b0df39b0 --- /dev/null +++ b/Tests/Models/ObservableMappablePost.swift @@ -0,0 +1,57 @@ +// +// ObservableMappablePost.swift +// LeadKit +// +// Created by Andrey Ovsyannikov on 12.05.2018. +// Copyright © 2018 Touch Instinct. All rights reserved. +// + +import ObjectMapper +import LeadKit +import RxSwift + +struct ObservableMappablePost: Decodable { + + enum CodingKeys: String, CodingKey { + case userId + case postId = "id" + case title + case body + } + + let userId: Int + let postId: Int + let title: String + let body: String + +} + +extension ObservableMappablePost: ObservableMappable { + + static func createFrom(map: Map) -> Observable { + + return Observable.deferredJust { + let userId: Int = try map.value("userId") + let postId: Int = try map.value("id") + let title: String = try map.value("title") + let body: String = try map.value("body") + + return ObservableMappablePost(userId: userId, + postId: postId, + title: title, + body: body) + } + } +} + +extension ObservableMappablePost: Equatable { + + static func == (lhs: ObservableMappablePost, rhs: ObservableMappablePost) -> Bool { + return lhs.userId == rhs.userId && + lhs.postId == rhs.postId && + lhs.title == rhs.title && + lhs.body == rhs.body + } + +} + From fb34bdb51ba719ae5c07a1d425085374864a95a1 Mon Sep 17 00:00:00 2001 From: Madhas Date: Sat, 12 May 2018 16:04:49 +0300 Subject: [PATCH 05/32] test observable mappable model request --- Tests/NetworkServiceTests.swift | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Tests/NetworkServiceTests.swift b/Tests/NetworkServiceTests.swift index 47c281ca..b5729107 100644 --- a/Tests/NetworkServiceTests.swift +++ b/Tests/NetworkServiceTests.swift @@ -76,4 +76,36 @@ class NetworkServiceTests: XCTestCase { XCTAssertEqual(receivedModel, expectedModel) } + func testObservableModelRequest() { + // given + let expectedModel = ObservableMappablePost(userId: 1, + postId: 1, + title: "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", + body: "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto") + + var receivedModel: ObservableMappablePost? + var error: Error? + let requestCompletedExpectation = expectation(description: "Request completed") + let apiRequest = ApiRequestParameters(url: "https://jsonplaceholder.typicode.com/posts/1", + headers: ["Content-Type": "application/json"]) + + // when + networkService.rxRequest(with: apiRequest) + .subscribe(onNext: { (_, model: ObservableMappablePost) in + receivedModel = model + requestCompletedExpectation.fulfill() + }, onError: { + error = $0 + requestCompletedExpectation.fulfill() + }) + .disposed(by: disposeBag) + + waitForExpectations(timeout: 20, handler: nil) + + // then + XCTAssertNil(error) + XCTAssertNotNil(receivedModel) + XCTAssertEqual(receivedModel, expectedModel) + } + } From 5a60cf68a5486bbc4c787d0fa7f8a28436c6498b Mon Sep 17 00:00:00 2001 From: Madhas Date: Tue, 15 May 2018 12:34:41 +0300 Subject: [PATCH 06/32] corrections --- Tests/Models/ObservableMappablePost.swift | 22 ++++++++++++++++++---- Tests/NetworkServiceTests.swift | 4 ++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Tests/Models/ObservableMappablePost.swift b/Tests/Models/ObservableMappablePost.swift index b0df39b0..127a3566 100644 --- a/Tests/Models/ObservableMappablePost.swift +++ b/Tests/Models/ObservableMappablePost.swift @@ -1,9 +1,23 @@ // -// ObservableMappablePost.swift -// LeadKit +// Copyright (c) 2018 Touch Instinct // -// Created by Andrey Ovsyannikov on 12.05.2018. -// Copyright © 2018 Touch Instinct. All rights reserved. +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. // import ObjectMapper diff --git a/Tests/NetworkServiceTests.swift b/Tests/NetworkServiceTests.swift index b5729107..b0f0f989 100644 --- a/Tests/NetworkServiceTests.swift +++ b/Tests/NetworkServiceTests.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Touch Instinct +// Copyright (c) 2018 Touch Instinct // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the Software), to deal @@ -24,7 +24,7 @@ import XCTest import LeadKit import RxSwift -class NetworkServiceTests: XCTestCase { +final class NetworkServiceTests: XCTestCase { var disposeBag: DisposeBag! From 9d3b3bd223522863a7874e4a946272655b7413d5 Mon Sep 17 00:00:00 2001 From: Madhas Date: Tue, 15 May 2018 22:10:24 +0300 Subject: [PATCH 07/32] move normal request to Decodable --- Sources/Classes/Services/NetworkService.swift | 3 +- .../AlamofireManager+Extensions.swift | 52 +-------- .../AlamofireRequest+Extensions.swift | 104 +++++++----------- 3 files changed, 46 insertions(+), 113 deletions(-) diff --git a/Sources/Classes/Services/NetworkService.swift b/Sources/Classes/Services/NetworkService.swift index 3de3ec92..41bec740 100644 --- a/Sources/Classes/Services/NetworkService.swift +++ b/Sources/Classes/Services/NetworkService.swift @@ -71,10 +71,11 @@ open class NetworkService { /// /// - Parameter parameters: api parameters to pass Alamofire /// - Returns: Observable of tuple containing (HTTPURLResponse, ImmutableMappable) - public func rxRequest(with parameters: ApiRequestParameters) + public func rxRequest(with parameters: ApiRequestParameters, decoder: JSONDecoder = JSONDecoder()) -> Observable<(response: HTTPURLResponse, model: T)> { return sessionManager.rx.responseModel(requestParameters: parameters, + decoder: decoder, acceptableStatusCodes: configuration.acceptableStatusCodes) .counterTracking(for: self) } diff --git a/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift b/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift index 351323df..19579a69 100644 --- a/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift +++ b/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift @@ -53,43 +53,17 @@ public extension Reactive where Base: Alamofire.SessionManager { /// Method that executes request and serializes response into target object /// /// - Parameter requestParameters: api parameters to pass Alamofire + /// - Parameter decoder: JSONDecoder to use for parsing /// - Parameter mappingQueue: The dispatch queue to use for mapping /// - Returns: Observable with HTTP URL Response and target object - func responseModel(requestParameters: ApiRequestParameters, - mappingQueue: DispatchQueue = .global(), - acceptableStatusCodes: Set = Base.defaultAcceptableStatusCodes) + func responseModel(requestParameters: ApiRequestParameters, + decoder: JSONDecoder, + mappingQueue: DispatchQueue = .global(), + acceptableStatusCodes: Set = Base.defaultAcceptableStatusCodes) -> Observable<(response: HTTPURLResponse, model: T)> { return apiRequest(requestParameters: requestParameters, acceptableStatusCodes: acceptableStatusCodes) - .flatMap { $0.rx.apiResponse(mappingQueue: mappingQueue) } - } - - /// Method that executes request and serializes response into array of target objects - /// - /// - Parameter requestParameters: api parameters to pass Alamofire - /// - Parameter mappingQueue: The dispatch queue to use for mapping - /// - Returns: Observable with HTTP URL Response and array of target objects - func responseModel(requestParameters: ApiRequestParameters, - mappingQueue: DispatchQueue = .global(), - acceptableStatusCodes: Set = Base.defaultAcceptableStatusCodes) - -> Observable<(response: HTTPURLResponse, models: [T])> { - - return apiRequest(requestParameters: requestParameters, acceptableStatusCodes: acceptableStatusCodes) - .flatMap { $0.rx.apiResponse(mappingQueue: mappingQueue) } - } - - /// Method that executes request and serializes response into target type - /// - /// - Parameter requestParameters: api parameters to pass Alamofire - /// - Parameter mappingQueue: The dispatch queue to use for mapping - /// - Returns: Observable with HTTP URL Response and target object - func responseObject(requestParameters: ApiRequestParameters, - mappingQueue: DispatchQueue = .global(), - acceptableStatusCodes: Set = Base.defaultAcceptableStatusCodes) - -> Observable<(response: HTTPURLResponse, object: T)> { - - return apiRequest(requestParameters: requestParameters, acceptableStatusCodes: acceptableStatusCodes) - .flatMap { $0.rx.apiResponse(mappingQueue: mappingQueue) } + .flatMap { $0.rx.apiResponse(mappingQueue: mappingQueue, decoder: decoder) } } /// Method that executes request and serializes response into target object @@ -106,18 +80,4 @@ public extension Reactive where Base: Alamofire.SessionManager { .flatMap { $0.rx.observableApiResponse(mappingQueue: mappingQueue) } } - /// Method that executes request and serializes response into array of target objects - /// - /// - Parameter requestParameters: api parameters to pass Alamofire - /// - Parameter mappingQueue: The dispatch queue to use for mapping - /// - Returns: Observable with HTTP URL Response and array of target objects - func responseObservableModel(requestParameters: ApiRequestParameters, - mappingQueue: DispatchQueue = .global(), - acceptableStatusCodes: Set = Base.defaultAcceptableStatusCodes) - -> Observable<(response: HTTPURLResponse, models: [T])> where T.ModelType == T { - - return apiRequest(requestParameters: requestParameters, acceptableStatusCodes: acceptableStatusCodes) - .flatMap { $0.rx.observableApiResponse(mappingQueue: mappingQueue) } - } - } diff --git a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift b/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift index 01d2d61b..1df5bff3 100644 --- a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift +++ b/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift @@ -25,52 +25,24 @@ import RxSwift import ObjectMapper import RxAlamofire -typealias ServerResponse = (response: HTTPURLResponse, result: Any) +typealias ServerResponse = (HTTPURLResponse, Data) public extension Reactive where Base: DataRequest { - private typealias JSON = [String: Any] + //private typealias JSON = [String: Any] /// Method that serializes response into target object /// /// - Parameter mappingQueue: The dispatch queue to use for mapping + /// - Parameter decoder: JSONDecoder used to decode a decodable type /// - Returns: Observable with HTTP URL Response and target object - func apiResponse(mappingQueue: DispatchQueue = .global()) + func apiResponse(mappingQueue: DispatchQueue = .global(), decoder: JSONDecoder) -> Observable<(response: HTTPURLResponse, model: T)> { - return responseJSONOnQueue(mappingQueue) - .tryMapResult { resp, value in - let json = try cast(value) as JSON - - return (resp, try T(JSON: json)) - } - } - - /// Method that serializes response into array of target objects - /// - /// - Parameter mappingQueue: The dispatch queue to use for mapping - /// - Returns: Observable with HTTP URL Response and array of target objects - func apiResponse(mappingQueue: DispatchQueue = .global()) - -> Observable<(response: HTTPURLResponse, models: [T])> { - - return responseJSONOnQueue(mappingQueue) - .tryMapResult { resp, value in - let jsonArray = try cast(value) as [JSON] - - return (resp, try Mapper().mapArray(JSONArray: jsonArray)) - } - } - - /// Method that serializes response into target type - /// - /// - Parameter mappingQueue: The dispatch queue to use for mapping - /// - Returns: Observable with HTTP URL Response and target object - func apiResponse(mappingQueue: DispatchQueue = .global()) - -> Observable<(response: HTTPURLResponse, object: T)> { - - return responseJSONOnQueue(mappingQueue) - .tryMapResult { resp, value in - (resp, try cast(value) as T) + return responseData() + .observeOn(SerialDispatchQueueScheduler(queue: mappingQueue, internalSerialQueueName: mappingQueue.label)) + .tryMapResult { response, data in + (response, try decoder.decode(T.self, from: data)) } } @@ -110,32 +82,32 @@ public extension Reactive where Base: DataRequest { } } - internal func responseJSONOnQueue(_ queue: DispatchQueue) -> Observable { - let responseSerializer = DataRequest.jsonResponseSerializer(options: .allowFragments) - - return responseResult(queue: queue, responseSerializer: responseSerializer) - .map { ServerResponse(response: $0.0, result: $0.1) } - .catchError { - switch $0 { - case let urlError as URLError: - switch urlError.code { - case .notConnectedToInternet, .timedOut: - throw RequestError.noConnection - default: - throw RequestError.network(error: urlError) - } - case let afError as AFError: - switch afError { - case .responseSerializationFailed, .responseValidationFailed: - throw RequestError.invalidResponse(error: afError) - default: - throw RequestError.network(error: afError) - } - default: - throw RequestError.network(error: $0) - } - } - } +// internal func responseJSONOnQueue(_ queue: DispatchQueue) -> Observable { +// let responseSerializer = DataRequest.jsonResponseSerializer(options: .allowFragments) +// +// return responseResult(queue: queue, responseSerializer: responseSerializer) +// .map { ServerResponse($0.0, $0.1) } +// .catchError { +// switch $0 { +// case let urlError as URLError: +// switch urlError.code { +// case .notConnectedToInternet, .timedOut: +// throw RequestError.noConnection +// default: +// throw RequestError.network(error: urlError) +// } +// case let afError as AFError: +// switch afError { +// case .responseSerializationFailed, .responseValidationFailed: +// throw RequestError.invalidResponse(error: afError) +// default: +// throw RequestError.network(error: afError) +// } +// default: +// throw RequestError.network(error: $0) +// } +// } +// } } @@ -152,14 +124,14 @@ private extension ObservableType where E == ServerResponse { } func tryMapObservableResult(_ transform: @escaping (E) throws -> Observable) -> Observable { - return flatMap { response -> Observable in + return flatMap { response, result -> Observable in do { - return try transform(response) + return try transform((response, result)) .catchError { - throw RequestError.mapping(error: $0, response: response.result) + throw RequestError.mapping(error: $0, response: result) } } catch { - throw RequestError.mapping(error: error, response: response.result) + throw RequestError.mapping(error: error, response: result) } } } From 83b8f40e938fc12162b72f00a17cf430344c6789 Mon Sep 17 00:00:00 2001 From: Madhas Date: Wed, 16 May 2018 15:51:49 +0300 Subject: [PATCH 08/32] test models updated --- LeadKit.xcodeproj/project.pbxproj | 24 ++++++--- ...servableMappablePost.swift => Album.swift} | 53 +++++++------------ Tests/Models/AlbumsContainer.swift | 46 ++++++++++++++++ Tests/Models/Post.swift | 12 +++++ 4 files changed, 93 insertions(+), 42 deletions(-) rename Tests/Models/{ObservableMappablePost.swift => Album.swift} (58%) create mode 100644 Tests/Models/AlbumsContainer.swift diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index 791c4862..3c8fc233 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -538,9 +538,12 @@ B84D64B120A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; B84D64B220A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; B84D64B320A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; - B84D64B620A71A8400DD76DA /* ObservableMappablePost.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B520A71A8400DD76DA /* ObservableMappablePost.swift */; }; - B84D64B720A71A8400DD76DA /* ObservableMappablePost.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B520A71A8400DD76DA /* ObservableMappablePost.swift */; }; - B84D64B820A71A8400DD76DA /* ObservableMappablePost.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B520A71A8400DD76DA /* ObservableMappablePost.swift */; }; + B85B766820AC4EC600F837C4 /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B766620AC4EA300F837C4 /* Album.swift */; }; + B85B766920AC4EC700F837C4 /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B766620AC4EA300F837C4 /* Album.swift */; }; + B85B766A20AC4EC700F837C4 /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B766620AC4EA300F837C4 /* Album.swift */; }; + B85B766D20AC51C600F837C4 /* AlbumsContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B766B20AC51BE00F837C4 /* AlbumsContainer.swift */; }; + B85B766E20AC51C600F837C4 /* AlbumsContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B766B20AC51BE00F837C4 /* AlbumsContainer.swift */; }; + B85B766F20AC51C700F837C4 /* AlbumsContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B766B20AC51BE00F837C4 /* AlbumsContainer.swift */; }; BA6C6DB45950382041948FC5 /* Pods_LeadKit_LeadKit_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CFE9323150A9760008093F73 /* Pods_LeadKit_LeadKit_iOS.framework */; }; D6EE55093E404DEA62B03DDF /* Pods_LeadKit_LeadKit_watchOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8590CA7831555C295C5DC572 /* Pods_LeadKit_LeadKit_watchOS.framework */; }; DEE25FE98D40ED1C168F384A /* Pods_LeadKit_LeadKit_iOS_Extensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 887F99C5326BD220C2811BD6 /* Pods_LeadKit_LeadKit_iOS_Extensions.framework */; }; @@ -790,7 +793,8 @@ A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtensionTests.swift; sourceTree = ""; }; A854A36EB179651E6D0CC9FB /* Pods_LeadKit_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKit_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkServiceTests.swift; sourceTree = ""; }; - B84D64B520A71A8400DD76DA /* ObservableMappablePost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservableMappablePost.swift; sourceTree = ""; }; + B85B766620AC4EA300F837C4 /* Album.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = ""; }; + B85B766B20AC51BE00F837C4 /* AlbumsContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumsContainer.swift; sourceTree = ""; }; BECC6E4BF63781403877B059 /* Pods-LeadKit-LeadKit watchOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit-LeadKit watchOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit-LeadKit watchOS/Pods-LeadKit-LeadKit watchOS.release.xcconfig"; sourceTree = ""; }; CB02EAC4E52AF48AD64EC045 /* Pods-LeadKit iOS ExtensionsTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit iOS ExtensionsTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit iOS ExtensionsTests/Pods-LeadKit iOS ExtensionsTests.debug.xcconfig"; sourceTree = ""; }; CD7003F75FD6DDC97DC99A7A /* Pods-LeadKit iOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit iOSTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit iOSTests/Pods-LeadKit iOSTests.debug.xcconfig"; sourceTree = ""; }; @@ -1238,8 +1242,9 @@ 671463B21EB34B1E00EAB194 /* Models */ = { isa = PBXGroup; children = ( + B85B766620AC4EA300F837C4 /* Album.swift */, + B85B766B20AC51BE00F837C4 /* AlbumsContainer.swift */, 671463B31EB34B1E00EAB194 /* Post.swift */, - B84D64B520A71A8400DD76DA /* ObservableMappablePost.swift */, ); path = Models; sourceTree = ""; @@ -2749,12 +2754,13 @@ files = ( A6C9A5051F8BC78F009311CC /* SeparatorConfiguration.swift in Sources */, 671463CA1EB34B1E00EAB194 /* TestView.swift in Sources */, - B84D64B620A71A8400DD76DA /* ObservableMappablePost.swift in Sources */, 671463B81EB34B1E00EAB194 /* StubCursor.swift in Sources */, + B85B766D20AC51C600F837C4 /* AlbumsContainer.swift in Sources */, 671463BB1EB34B1E00EAB194 /* CursorTests.swift in Sources */, A6F32C101F6EBE9600AC08EE /* StringExtensionTests.swift in Sources */, 671463BE1EB34B1E00EAB194 /* LoadFromNibTests.swift in Sources */, A6C9A50F1F8BC79D009311CC /* Comparable+Extensions.swift in Sources */, + B85B766820AC4EC600F837C4 /* Album.swift in Sources */, 671463C41EB34B1E00EAB194 /* Post.swift in Sources */, B84D64B120A70B7000DD76DA /* NetworkServiceTests.swift in Sources */, ); @@ -3013,11 +3019,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + B85B766F20AC51C700F837C4 /* AlbumsContainer.swift in Sources */, 671463CC1EB34B1E00EAB194 /* TestView.swift in Sources */, B84D64B320A70B7000DD76DA /* NetworkServiceTests.swift in Sources */, 671463BA1EB34B1E00EAB194 /* StubCursor.swift in Sources */, 671463BD1EB34B1E00EAB194 /* CursorTests.swift in Sources */, - B84D64B820A71A8400DD76DA /* ObservableMappablePost.swift in Sources */, + B85B766A20AC4EC700F837C4 /* Album.swift in Sources */, A6F32C121F6EBE9800AC08EE /* StringExtensionTests.swift in Sources */, 671463C01EB34B1E00EAB194 /* LoadFromNibTests.swift in Sources */, 671463C61EB34B1E00EAB194 /* Post.swift in Sources */, @@ -3175,10 +3182,11 @@ B84D64B220A70B7000DD76DA /* NetworkServiceTests.swift in Sources */, 671463C51EB34B1E00EAB194 /* Post.swift in Sources */, 671463CB1EB34B1E00EAB194 /* TestView.swift in Sources */, - B84D64B720A71A8400DD76DA /* ObservableMappablePost.swift in Sources */, + B85B766E20AC51C600F837C4 /* AlbumsContainer.swift in Sources */, A6F32C111F6EBE9700AC08EE /* StringExtensionTests.swift in Sources */, 671463BC1EB34B1E00EAB194 /* CursorTests.swift in Sources */, 671463B91EB34B1E00EAB194 /* StubCursor.swift in Sources */, + B85B766920AC4EC700F837C4 /* Album.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Tests/Models/ObservableMappablePost.swift b/Tests/Models/Album.swift similarity index 58% rename from Tests/Models/ObservableMappablePost.swift rename to Tests/Models/Album.swift index 127a3566..975aef29 100644 --- a/Tests/Models/ObservableMappablePost.swift +++ b/Tests/Models/Album.swift @@ -20,52 +20,37 @@ // THE SOFTWARE. // -import ObjectMapper import LeadKit import RxSwift -struct ObservableMappablePost: Decodable { - +struct Album: Decodable { + enum CodingKeys: String, CodingKey { case userId - case postId = "id" + case albumId = "id" case title - case body } - + let userId: Int - let postId: Int + let albumId: Int let title: String - let body: String - } -extension ObservableMappablePost: ObservableMappable { - - static func createFrom(map: Map) -> Observable { - +extension Album: Equatable { + + static func == (lhs: Album, rhs: Album) -> Bool { + return lhs.userId == rhs.userId && + lhs.albumId == rhs.albumId && + lhs.title == rhs.title + } +} + +extension Album: ObservableMappable { + + static func createFrom(decoder: JSONDecoder, jsonObject: Any) -> Observable { return Observable.deferredJust { - let userId: Int = try map.value("userId") - let postId: Int = try map.value("id") - let title: String = try map.value("title") - let body: String = try map.value("body") - - return ObservableMappablePost(userId: userId, - postId: postId, - title: title, - body: body) + let data = try JSONSerialization.data(withJSONObject: jsonObject, options: []) + return try decoder.decode(Album.self, from: data) } } } - -extension ObservableMappablePost: Equatable { - - static func == (lhs: ObservableMappablePost, rhs: ObservableMappablePost) -> Bool { - return lhs.userId == rhs.userId && - lhs.postId == rhs.postId && - lhs.title == rhs.title && - lhs.body == rhs.body - } - -} - diff --git a/Tests/Models/AlbumsContainer.swift b/Tests/Models/AlbumsContainer.swift new file mode 100644 index 00000000..16436892 --- /dev/null +++ b/Tests/Models/AlbumsContainer.swift @@ -0,0 +1,46 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import LeadKit +import RxSwift + +struct AlbumContainer: Decodable { + + let albums: [Album] +} + +extension AlbumContainer: ObservableMappable { + + static func createFrom(decoder: JSONDecoder, jsonObject: Any) -> Observable { + return Observable.deferredJust { try cast(jsonObject) as [Any] } + .flatMap { + $0.concurrentRxMap { json -> Album in + let data = try JSONSerialization.data(withJSONObject: json, options: []) + return try decoder.decode(Album.self, from: data) + } + } + .map { + AlbumContainer(albums: $0) + } + } +} + diff --git a/Tests/Models/Post.swift b/Tests/Models/Post.swift index dfb71c3b..2cce006f 100644 --- a/Tests/Models/Post.swift +++ b/Tests/Models/Post.swift @@ -21,6 +21,8 @@ // import ObjectMapper +import LeadKit +import RxSwift struct Post: Decodable { @@ -55,6 +57,16 @@ extension Post: ImmutableMappable { } } +extension Post: ObservableMappable { + + static func createFrom(decoder: JSONDecoder, jsonObject: Any) -> Observable { + return Observable.deferredJust { + let data = try JSONSerialization.data(withJSONObject: jsonObject, options: []) + return try decoder.decode(Post.self, from: data) + } + } +} + extension Post: Equatable { static func == (lhs: Post, rhs: Post) -> Bool { From 91b49d8f9402217a66b1925b367f58c997e7d3e9 Mon Sep 17 00:00:00 2001 From: Madhas Date: Wed, 16 May 2018 15:52:01 +0300 Subject: [PATCH 09/32] observable mappable protocol updated --- Sources/Protocols/ObservableMappable.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Protocols/ObservableMappable.swift b/Sources/Protocols/ObservableMappable.swift index 5d97a040..25ad6f90 100644 --- a/Sources/Protocols/ObservableMappable.swift +++ b/Sources/Protocols/ObservableMappable.swift @@ -26,8 +26,8 @@ import RxSwift /// Protocol for concurrent model mapping public protocol ObservableMappable { - associatedtype ModelType + associatedtype ModelType: Decodable - static func createFrom(map: Map) -> Observable + static func createFrom(decoder: JSONDecoder, jsonObject: Any) -> Observable } From 98ef4ca86ec3f6c067e80efd39b05a999d998d24 Mon Sep 17 00:00:00 2001 From: Madhas Date: Wed, 16 May 2018 15:52:32 +0300 Subject: [PATCH 10/32] all methods moved to Decodable --- Sources/Classes/Services/NetworkService.swift | 6 +- .../AlamofireManager+Extensions.swift | 6 +- .../AlamofireRequest+Extensions.swift | 61 +++---------------- 3 files changed, 16 insertions(+), 57 deletions(-) diff --git a/Sources/Classes/Services/NetworkService.swift b/Sources/Classes/Services/NetworkService.swift index 41bec740..a768c651 100644 --- a/Sources/Classes/Services/NetworkService.swift +++ b/Sources/Classes/Services/NetworkService.swift @@ -58,11 +58,14 @@ open class NetworkService { /// Perform reactive request to get mapped ObservableMappable model and http response /// /// - Parameter parameters: api parameters to pass Alamofire + /// - Parameter decoder: json decoder to decode response data /// - Returns: Observable of tuple containing (HTTPURLResponse, ObservableMappable) - public func rxRequest(with parameters: ApiRequestParameters) + public func rxRequest(with parameters: ApiRequestParameters, + decoder: JSONDecoder = JSONDecoder()) -> Observable<(response: HTTPURLResponse, model: T)> where T.ModelType == T { return sessionManager.rx.responseObservableModel(requestParameters: parameters, + decoder: decoder, acceptableStatusCodes: configuration.acceptableStatusCodes) .counterTracking(for: self) } @@ -70,6 +73,7 @@ open class NetworkService { /// Perform reactive request to get mapped ImmutableMappable model and http response /// /// - Parameter parameters: api parameters to pass Alamofire + /// - Parameter decoder: json decoder to decode response data /// - Returns: Observable of tuple containing (HTTPURLResponse, ImmutableMappable) public func rxRequest(with parameters: ApiRequestParameters, decoder: JSONDecoder = JSONDecoder()) -> Observable<(response: HTTPURLResponse, model: T)> { diff --git a/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift b/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift index 19579a69..63d62cb2 100644 --- a/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift +++ b/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift @@ -53,7 +53,7 @@ public extension Reactive where Base: Alamofire.SessionManager { /// Method that executes request and serializes response into target object /// /// - Parameter requestParameters: api parameters to pass Alamofire - /// - Parameter decoder: JSONDecoder to use for parsing + /// - Parameter decoder: json decoder to decode response data /// - Parameter mappingQueue: The dispatch queue to use for mapping /// - Returns: Observable with HTTP URL Response and target object func responseModel(requestParameters: ApiRequestParameters, @@ -69,15 +69,17 @@ public extension Reactive where Base: Alamofire.SessionManager { /// Method that executes request and serializes response into target object /// /// - Parameter requestParameters: api parameters to pass Alamofire + /// - Parameter decoder: json decoder to decode response data /// - Parameter mappingQueue: The dispatch queue to use for mapping /// - Returns: Observable with HTTP URL Response and target object func responseObservableModel(requestParameters: ApiRequestParameters, + decoder: JSONDecoder, mappingQueue: DispatchQueue = .global(), acceptableStatusCodes: Set = Base.defaultAcceptableStatusCodes) -> Observable<(response: HTTPURLResponse, model: T)> where T.ModelType == T { return apiRequest(requestParameters: requestParameters, acceptableStatusCodes: acceptableStatusCodes) - .flatMap { $0.rx.observableApiResponse(mappingQueue: mappingQueue) } + .flatMap { $0.rx.observableApiResponse(mappingQueue: mappingQueue, decoder: decoder) } } } diff --git a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift b/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift index 1df5bff3..ec14d87b 100644 --- a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift +++ b/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift @@ -50,65 +50,18 @@ public extension Reactive where Base: DataRequest { /// /// - Parameter mappingQueue: The dispatch queue to use for mapping /// - Returns: Observable with HTTP URL Response and target object - func observableApiResponse(mappingQueue: DispatchQueue = .global()) + func observableApiResponse(mappingQueue: DispatchQueue = .global(), decoder: JSONDecoder) -> Observable<(response: HTTPURLResponse, model: T)> where T.ModelType == T { - return responseJSONOnQueue(mappingQueue) - .tryMapObservableResult { resp, value in - let json = try cast(value) as JSON - - return T.createFrom(map: Map(mappingType: .fromJSON, JSON: json)) - .map { (resp, $0) } + return responseData() + .observeOn(SerialDispatchQueueScheduler(queue: mappingQueue, internalSerialQueueName: mappingQueue.label)) + .tryMapObservableResult { response, value in + let json = try JSONSerialization.jsonObject(with: value, options: []) + return T.createFrom(decoder: decoder, jsonObject: json) + .map { (response, $0) } } } - /// Method that serializes response into array of target objects - /// - /// - Parameter mappingQueue: The dispatch queue to use for mapping - /// - Returns: Observable with HTTP URL Response and array of target objects - func observableApiResponse(mappingQueue: DispatchQueue = .global()) - -> Observable<(response: HTTPURLResponse, models: [T])> where T.ModelType == T { - - return responseJSONOnQueue(mappingQueue) - .tryMapObservableResult { resp, value in - let jsonArray = try cast(value) as [JSON] - - let createFromList = jsonArray.map { - T.createFrom(map: Map(mappingType: .fromJSON, JSON: $0)) - } - - return Observable.zip(createFromList) { $0 } - .map { (resp, $0) } - } - } - -// internal func responseJSONOnQueue(_ queue: DispatchQueue) -> Observable { -// let responseSerializer = DataRequest.jsonResponseSerializer(options: .allowFragments) -// -// return responseResult(queue: queue, responseSerializer: responseSerializer) -// .map { ServerResponse($0.0, $0.1) } -// .catchError { -// switch $0 { -// case let urlError as URLError: -// switch urlError.code { -// case .notConnectedToInternet, .timedOut: -// throw RequestError.noConnection -// default: -// throw RequestError.network(error: urlError) -// } -// case let afError as AFError: -// switch afError { -// case .responseSerializationFailed, .responseValidationFailed: -// throw RequestError.invalidResponse(error: afError) -// default: -// throw RequestError.network(error: afError) -// } -// default: -// throw RequestError.network(error: $0) -// } -// } -// } - } private extension ObservableType where E == ServerResponse { From b181344f289725fbc2024fe82291e3094a775505 Mon Sep 17 00:00:00 2001 From: Madhas Date: Wed, 16 May 2018 15:52:40 +0300 Subject: [PATCH 11/32] tests updated --- Tests/NetworkServiceTests.swift | 81 +++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 15 deletions(-) diff --git a/Tests/NetworkServiceTests.swift b/Tests/NetworkServiceTests.swift index b0f0f989..07fb3c5c 100644 --- a/Tests/NetworkServiceTests.swift +++ b/Tests/NetworkServiceTests.swift @@ -46,20 +46,19 @@ final class NetworkServiceTests: XCTestCase { func testModelRequest() { // given - let expectedModel = Post(userId: 1, - postId: 1, - title: "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", - body: "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto") + let expectedModel = Album(userId: 1, + albumId: 1, + title: "quidem molestiae enim") - var receivedModel: Post? + var receivedModel: Album? var error: Error? let requestCompletedExpectation = expectation(description: "Request completed") - let apiRequest = ApiRequestParameters(url: "https://jsonplaceholder.typicode.com/posts/1", + let apiRequest = ApiRequestParameters(url: "https://jsonplaceholder.typicode.com/albums/1", headers: ["Content-Type": "application/json"]) // when networkService.rxRequest(with: apiRequest) - .subscribe(onNext: { (_, model: Post) in + .subscribe(onNext: { (_, model: Album) in receivedModel = model requestCompletedExpectation.fulfill() }, onError: { @@ -75,23 +74,49 @@ final class NetworkServiceTests: XCTestCase { XCTAssertNotNil(receivedModel) XCTAssertEqual(receivedModel, expectedModel) } + + func testModelArrayRequest() { + // given + var response: [Album]? + var error: Error? + let requestCompletedExpectation = expectation(description: "Request completed") + let apiRequest = ApiRequestParameters(url: "https://jsonplaceholder.typicode.com/albums", + headers: ["Content-Type": "application/json"]) + + //when + networkService.rxRequest(with: apiRequest) + .subscribe(onNext: { ( _, model: [Album]) in + response = model + requestCompletedExpectation.fulfill() + }, onError: { + error = $0 + requestCompletedExpectation.fulfill() + }) + .disposed(by: disposeBag) + + waitForExpectations(timeout: 20, handler: nil) + + // then + XCTAssertNil(error) + XCTAssertNotNil(response) + XCTAssert(response?.count == 100) + } func testObservableModelRequest() { // given - let expectedModel = ObservableMappablePost(userId: 1, - postId: 1, - title: "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", - body: "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto") + let expectedModel = Album(userId: 1, + albumId: 1, + title: "quidem molestiae enim") - var receivedModel: ObservableMappablePost? + var receivedModel: Album? var error: Error? let requestCompletedExpectation = expectation(description: "Request completed") - let apiRequest = ApiRequestParameters(url: "https://jsonplaceholder.typicode.com/posts/1", + let apiRequest = ApiRequestParameters(url: "https://jsonplaceholder.typicode.com/albums/1", headers: ["Content-Type": "application/json"]) // when networkService.rxRequest(with: apiRequest) - .subscribe(onNext: { (_, model: ObservableMappablePost) in + .subscribe(onNext: { (_, model: Album) in receivedModel = model requestCompletedExpectation.fulfill() }, onError: { @@ -107,5 +132,31 @@ final class NetworkServiceTests: XCTestCase { XCTAssertNotNil(receivedModel) XCTAssertEqual(receivedModel, expectedModel) } - + + func testObservableModelArrayRequest() { + // given + var receivedModel: AlbumContainer? + var error: Error? + let requestCompletedExpectation = expectation(description: "Request completed") + let apiRequest = ApiRequestParameters(url: "https://jsonplaceholder.typicode.com/albums", + headers: ["Content-Type": "application/json"]) + + // when + networkService.rxRequest(with: apiRequest) + .subscribe(onNext: { (_, model: AlbumContainer) in + receivedModel = model + requestCompletedExpectation.fulfill() + }, onError: { + error = $0 + requestCompletedExpectation.fulfill() + }) + .disposed(by: disposeBag) + + waitForExpectations(timeout: 20, handler: nil) + + //then + XCTAssertNil(error) + XCTAssertNotNil(receivedModel) + XCTAssert(receivedModel?.albums.count == 100) + } } From 2733a159ed778feef5fe51128f2f9a6ceb093412 Mon Sep 17 00:00:00 2001 From: Madhas Date: Wed, 16 May 2018 16:01:35 +0300 Subject: [PATCH 12/32] update observable model array request test --- Tests/NetworkServiceTests.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tests/NetworkServiceTests.swift b/Tests/NetworkServiceTests.swift index 07fb3c5c..6c3228b9 100644 --- a/Tests/NetworkServiceTests.swift +++ b/Tests/NetworkServiceTests.swift @@ -158,5 +158,8 @@ final class NetworkServiceTests: XCTestCase { XCTAssertNil(error) XCTAssertNotNil(receivedModel) XCTAssert(receivedModel?.albums.count == 100) + receivedModel?.albums.enumerated().forEach { index, element in + XCTAssertEqual(element.albumId, index + 1) + } } } From a28805846b8d77c3e04d53ac191604d92bc30266 Mon Sep 17 00:00:00 2001 From: Madhas Date: Sun, 20 May 2018 18:53:31 +0300 Subject: [PATCH 13/32] toJSON method on encodable --- LeadKit.xcodeproj/project.pbxproj | 12 ++++++ .../Codable/Codable+Extensions.swift | 38 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 Sources/Extensions/Codable/Codable+Extensions.swift diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index 3c8fc233..143b9111 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -544,6 +544,7 @@ B85B766D20AC51C600F837C4 /* AlbumsContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B766B20AC51BE00F837C4 /* AlbumsContainer.swift */; }; B85B766E20AC51C600F837C4 /* AlbumsContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B766B20AC51BE00F837C4 /* AlbumsContainer.swift */; }; B85B766F20AC51C700F837C4 /* AlbumsContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B766B20AC51BE00F837C4 /* AlbumsContainer.swift */; }; + B85B768720B1CF6700F837C4 /* Codable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B768620B1CF6700F837C4 /* Codable+Extensions.swift */; }; BA6C6DB45950382041948FC5 /* Pods_LeadKit_LeadKit_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CFE9323150A9760008093F73 /* Pods_LeadKit_LeadKit_iOS.framework */; }; D6EE55093E404DEA62B03DDF /* Pods_LeadKit_LeadKit_watchOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8590CA7831555C295C5DC572 /* Pods_LeadKit_LeadKit_watchOS.framework */; }; DEE25FE98D40ED1C168F384A /* Pods_LeadKit_LeadKit_iOS_Extensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 887F99C5326BD220C2811BD6 /* Pods_LeadKit_LeadKit_iOS_Extensions.framework */; }; @@ -795,6 +796,7 @@ B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkServiceTests.swift; sourceTree = ""; }; B85B766620AC4EA300F837C4 /* Album.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = ""; }; B85B766B20AC51BE00F837C4 /* AlbumsContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumsContainer.swift; sourceTree = ""; }; + B85B768620B1CF6700F837C4 /* Codable+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Codable+Extensions.swift"; sourceTree = ""; }; BECC6E4BF63781403877B059 /* Pods-LeadKit-LeadKit watchOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit-LeadKit watchOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit-LeadKit watchOS/Pods-LeadKit-LeadKit watchOS.release.xcconfig"; sourceTree = ""; }; CB02EAC4E52AF48AD64EC045 /* Pods-LeadKit iOS ExtensionsTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit iOS ExtensionsTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit iOS ExtensionsTests/Pods-LeadKit iOS ExtensionsTests.debug.xcconfig"; sourceTree = ""; }; CD7003F75FD6DDC97DC99A7A /* Pods-LeadKit iOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit iOSTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit iOSTests/Pods-LeadKit iOSTests.debug.xcconfig"; sourceTree = ""; }; @@ -954,6 +956,7 @@ EFBE57CE1EC35ED90040E00A /* Array */, 67A1FF921EBCA64A00D6C89F /* CABasicAnimation */, 671461E01EB3396E00EAB194 /* CGFloat */, + B85B768520B1CF4C00F837C4 /* Codable */, A6D10EA91F8A9269003E69DD /* Comparable */, 67745284206259C20024EEEF /* DataLoading */, 6771DFE81EEA7C8F002DCDAE /* DateFormattingService */, @@ -1770,6 +1773,14 @@ path = Extensions; sourceTree = ""; }; + B85B768520B1CF4C00F837C4 /* Codable */ = { + isa = PBXGroup; + children = ( + B85B768620B1CF6700F837C4 /* Codable+Extensions.swift */, + ); + path = Codable; + sourceTree = ""; + }; C90516DF61394D92FF071C0C /* Frameworks */ = { isa = PBXGroup; children = ( @@ -2682,6 +2693,7 @@ 67EB7FEB2061667900BDD9FB /* DefaultTotalCountCursorListingResult.swift in Sources */, 671AD26C206A3E8500EAF887 /* Array+TotalCountCursorListingResult.swift in Sources */, 673CF4382063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.swift in Sources */, + B85B768720B1CF6700F837C4 /* Codable+Extensions.swift in Sources */, 671AD267206A365100EAF887 /* UIApplication+OpenUrlSupport.swift in Sources */, 673CF40B2063AB7C00C329F6 /* GeneralDataLoadingViewModel.swift in Sources */, 6714636C1EB3396E00EAB194 /* XibNameProtocol.swift in Sources */, diff --git a/Sources/Extensions/Codable/Codable+Extensions.swift b/Sources/Extensions/Codable/Codable+Extensions.swift new file mode 100644 index 00000000..dedf4cea --- /dev/null +++ b/Sources/Extensions/Codable/Codable+Extensions.swift @@ -0,0 +1,38 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +extension Encodable { + + func toJSON(with encoder: JSONEncoder = JSONEncoder()) -> [String: Any] { + guard let data = try? encoder.encode(self) else { + return [:] + } + + guard let json = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any] else { + return [:] + } + + return json + } +} From 35270f2b32bb9425ff975f1f43ac0f0da432b3c9 Mon Sep 17 00:00:00 2001 From: Madhas Date: Thu, 24 May 2018 12:27:42 +0300 Subject: [PATCH 14/32] LeadKitError case added --- Sources/Enums/LeadKitError.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Enums/LeadKitError.swift b/Sources/Enums/LeadKitError.swift index de264fac..90e2324f 100644 --- a/Sources/Enums/LeadKitError.swift +++ b/Sources/Enums/LeadKitError.swift @@ -28,5 +28,5 @@ import Foundation public enum LeadKitError: Error { case failedToCastValue(expectedType: Any.Type, givenType: Any.Type) - + case failedToDecode(reason: String) } From 0ee26e3e8cb52719b5b6712d4df5ae9ecb9f7baf Mon Sep 17 00:00:00 2001 From: Madhas Date: Thu, 24 May 2018 12:37:36 +0300 Subject: [PATCH 15/32] remove occurrences of ObjectMapper --- LeadKit.xcodeproj/project.pbxproj | 58 --------------- Sources/Classes/Services/NetworkService.swift | 1 - .../AlamofireManager+Extensions.swift | 1 - .../AlamofireRequest+Extensions.swift | 1 - ...teFormattingService+MappingTransform.swift | 60 ---------------- .../UniversalMappable+Extensions.swift | 31 -------- .../UniversalMappable+ImmutableMappable.swift | 35 ---------- .../UniversalMappable+SwiftStandard.swift | 70 ------------------- Sources/Protocols/ObservableMappable.swift | 1 - Sources/Protocols/UniversalMappable.swift | 34 --------- Tests/Models/Post.swift | 18 ----- 11 files changed, 310 deletions(-) delete mode 100644 Sources/Extensions/DateFormattingService/DateFormattingService+MappingTransform.swift delete mode 100644 Sources/Extensions/UniversalMappable/UniversalMappable+Extensions.swift delete mode 100644 Sources/Extensions/UniversalMappable/UniversalMappable+ImmutableMappable.swift delete mode 100644 Sources/Extensions/UniversalMappable/UniversalMappable+SwiftStandard.swift delete mode 100644 Sources/Protocols/UniversalMappable.swift diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index 143b9111..3300d099 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -353,10 +353,6 @@ 676B22A3206A626D002E9F8A /* NSAttributedString+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 676B22A1206A626D002E9F8A /* NSAttributedString+Extensions.swift */; }; 676B22A4206A626D002E9F8A /* NSAttributedString+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 676B22A1206A626D002E9F8A /* NSAttributedString+Extensions.swift */; }; 676B22A5206A626D002E9F8A /* NSAttributedString+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 676B22A1206A626D002E9F8A /* NSAttributedString+Extensions.swift */; }; - 6771DFEA1EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6771DFE91EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift */; }; - 6771DFEB1EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6771DFE91EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift */; }; - 6771DFEC1EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6771DFE91EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift */; }; - 6771DFED1EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6771DFE91EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift */; }; 67745268206249360024EEEF /* UITableView+PaginationWrappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67745267206249360024EEEF /* UITableView+PaginationWrappable.swift */; }; 67745269206249360024EEEF /* UITableView+PaginationWrappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67745267206249360024EEEF /* UITableView+PaginationWrappable.swift */; }; 6774526A206249360024EEEF /* UITableView+PaginationWrappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67745267206249360024EEEF /* UITableView+PaginationWrappable.swift */; }; @@ -552,22 +548,6 @@ EF24213B2076D5C700FA9BE6 /* NetworkServiceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF2421392076D5BD00FA9BE6 /* NetworkServiceConfiguration.swift */; }; EF24213C2076D5C900FA9BE6 /* NetworkServiceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF2421392076D5BD00FA9BE6 /* NetworkServiceConfiguration.swift */; }; EF24213D2076D5CA00FA9BE6 /* NetworkServiceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF2421392076D5BD00FA9BE6 /* NetworkServiceConfiguration.swift */; }; - EFA4C66420864F9C008C4DD8 /* UniversalMappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFA4C66320864F9C008C4DD8 /* UniversalMappable.swift */; }; - EFA4C66520864F9C008C4DD8 /* UniversalMappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFA4C66320864F9C008C4DD8 /* UniversalMappable.swift */; }; - EFA4C66620864F9C008C4DD8 /* UniversalMappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFA4C66320864F9C008C4DD8 /* UniversalMappable.swift */; }; - EFA4C66720864F9C008C4DD8 /* UniversalMappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFA4C66320864F9C008C4DD8 /* UniversalMappable.swift */; }; - EFA4C66A208650B4008C4DD8 /* UniversalMappable+ImmutableMappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFA4C669208650B4008C4DD8 /* UniversalMappable+ImmutableMappable.swift */; }; - EFA4C66B208650B4008C4DD8 /* UniversalMappable+ImmutableMappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFA4C669208650B4008C4DD8 /* UniversalMappable+ImmutableMappable.swift */; }; - EFA4C66C208650B4008C4DD8 /* UniversalMappable+ImmutableMappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFA4C669208650B4008C4DD8 /* UniversalMappable+ImmutableMappable.swift */; }; - EFA4C66D208650B4008C4DD8 /* UniversalMappable+ImmutableMappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFA4C669208650B4008C4DD8 /* UniversalMappable+ImmutableMappable.swift */; }; - EFA4C66F20865126008C4DD8 /* UniversalMappable+SwiftStandard.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFA4C66E20865126008C4DD8 /* UniversalMappable+SwiftStandard.swift */; }; - EFA4C67020865126008C4DD8 /* UniversalMappable+SwiftStandard.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFA4C66E20865126008C4DD8 /* UniversalMappable+SwiftStandard.swift */; }; - EFA4C67120865126008C4DD8 /* UniversalMappable+SwiftStandard.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFA4C66E20865126008C4DD8 /* UniversalMappable+SwiftStandard.swift */; }; - EFA4C67220865126008C4DD8 /* UniversalMappable+SwiftStandard.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFA4C66E20865126008C4DD8 /* UniversalMappable+SwiftStandard.swift */; }; - EFA4C6742086514A008C4DD8 /* UniversalMappable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFA4C6732086514A008C4DD8 /* UniversalMappable+Extensions.swift */; }; - EFA4C6752086514A008C4DD8 /* UniversalMappable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFA4C6732086514A008C4DD8 /* UniversalMappable+Extensions.swift */; }; - EFA4C6762086514A008C4DD8 /* UniversalMappable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFA4C6732086514A008C4DD8 /* UniversalMappable+Extensions.swift */; }; - EFA4C6772086514A008C4DD8 /* UniversalMappable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFA4C6732086514A008C4DD8 /* UniversalMappable+Extensions.swift */; }; EFBE57D01EC35EF20040E00A /* Array+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFBE57CF1EC35EF20040E00A /* Array+Extensions.swift */; }; EFBE57D11EC35EF20040E00A /* Array+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFBE57CF1EC35EF20040E00A /* Array+Extensions.swift */; }; EFBE57D21EC35EF20040E00A /* Array+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFBE57CF1EC35EF20040E00A /* Array+Extensions.swift */; }; @@ -720,7 +700,6 @@ 674AF55B1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIActivityIndicatorView+LoadingIndicator.swift"; sourceTree = ""; }; 6762131720A0BBA30034EEF1 /* TableSection+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TableSection+Extensions.swift"; sourceTree = ""; }; 676B22A1206A626D002E9F8A /* NSAttributedString+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+Extensions.swift"; sourceTree = ""; }; - 6771DFE91EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DateFormattingService+MappingTransform.swift"; sourceTree = ""; }; 67745267206249360024EEEF /* UITableView+PaginationWrappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+PaginationWrappable.swift"; sourceTree = ""; }; 6774526B206249E30024EEEF /* UICollectionView+PaginationWrappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionView+PaginationWrappable.swift"; sourceTree = ""; }; 6774526F20624A2A0024EEEF /* PaginationWrapperDelegate+DefaultImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PaginationWrapperDelegate+DefaultImplementation.swift"; sourceTree = ""; }; @@ -805,10 +784,6 @@ D840E55867DC9BB63460B856 /* Pods-LeadKit tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit tvOSTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit tvOSTests/Pods-LeadKit tvOSTests.release.xcconfig"; sourceTree = ""; }; DF1148A279C7AC7A42B0A0F8 /* Pods_LeadKit_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKit_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EF2421392076D5BD00FA9BE6 /* NetworkServiceConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkServiceConfiguration.swift; sourceTree = ""; }; - EFA4C66320864F9C008C4DD8 /* UniversalMappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalMappable.swift; sourceTree = ""; }; - EFA4C669208650B4008C4DD8 /* UniversalMappable+ImmutableMappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UniversalMappable+ImmutableMappable.swift"; sourceTree = ""; }; - EFA4C66E20865126008C4DD8 /* UniversalMappable+SwiftStandard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UniversalMappable+SwiftStandard.swift"; sourceTree = ""; }; - EFA4C6732086514A008C4DD8 /* UniversalMappable+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UniversalMappable+Extensions.swift"; sourceTree = ""; }; EFBE57CF1EC35EF20040E00A /* Array+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Extensions.swift"; sourceTree = ""; }; EFBE57DA1EC361620040E00A /* UIView+Layout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Layout.swift"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -975,7 +950,6 @@ 671462021EB3396E00EAB194 /* TimeInterval */, 671462081EB3396E00EAB194 /* UIColor */, 672947E0206EA36B00AC6B6B /* UIKit */, - EFA4C6682086508B008C4DD8 /* UniversalMappable */, 6727476C206CCD3100725163 /* Views */, ); path = Extensions; @@ -1173,7 +1147,6 @@ 67955D51206D216B0021ECD2 /* Singleton.swift */, 6714622E1EB3396E00EAB194 /* StaticViewHeightProtocol.swift */, 671462311EB3396E00EAB194 /* SupportProtocol.swift */, - EFA4C66320864F9C008C4DD8 /* UniversalMappable.swift */, 671462321EB3396E00EAB194 /* ViewHeightProtocol.swift */, 678D269C20692BFF00B05B93 /* Views */, 671462341EB3396E00EAB194 /* XibNameProtocol.swift */, @@ -1470,7 +1443,6 @@ 6771DFE81EEA7C8F002DCDAE /* DateFormattingService */ = { isa = PBXGroup; children = ( - 6771DFE91EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift */, 67386A8B206CF3F6004EDA6C /* DateFormattingService+DefaultImplementation.swift */, ); path = DateFormattingService; @@ -1830,16 +1802,6 @@ path = NetworkService; sourceTree = ""; }; - EFA4C6682086508B008C4DD8 /* UniversalMappable */ = { - isa = PBXGroup; - children = ( - EFA4C6732086514A008C4DD8 /* UniversalMappable+Extensions.swift */, - EFA4C669208650B4008C4DD8 /* UniversalMappable+ImmutableMappable.swift */, - EFA4C66E20865126008C4DD8 /* UniversalMappable+SwiftStandard.swift */, - ); - path = UniversalMappable; - sourceTree = ""; - }; EFBE57CE1EC35ED90040E00A /* Array */ = { isa = PBXGroup; children = ( @@ -2635,7 +2597,6 @@ 671463401EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */, 67A1FF8F1EBCA09B00D6C89F /* UIImage+Spinner.swift in Sources */, 673564F62068C68D00F0CBED /* NumberFormat.swift in Sources */, - EFA4C66420864F9C008C4DD8 /* UniversalMappable.swift in Sources */, 671462901EB3396E00EAB194 /* CGImage+Crop.swift in Sources */, 671462FC1EB3396E00EAB194 /* UIView+XibNameProtocol.swift in Sources */, 67EB7FC0206140E600BDD9FB /* TotalCountCursor.swift in Sources */, @@ -2654,7 +2615,6 @@ 67FDC25F1FA310EA00C76A77 /* RequestError.swift in Sources */, 67745268206249360024EEEF /* UITableView+PaginationWrappable.swift in Sources */, 6714624C1EB3396E00EAB194 /* MapCursor.swift in Sources */, - EFA4C66F20865126008C4DD8 /* UniversalMappable+SwiftStandard.swift in Sources */, A6C9A4FA1F8BBCF2009311CC /* EmptyCell.swift in Sources */, 6737CFA3207220960063E056 /* SeparatorConfiguration+Extensions.swift in Sources */, 671463241EB3396E00EAB194 /* Any+TypeName.swift in Sources */, @@ -2664,7 +2624,6 @@ 671463281EB3396E00EAB194 /* BaseViewModel.swift in Sources */, 671AD25C206A343300EAF887 /* VoidBlock.swift in Sources */, A6E0DDDF1F8A696F002CA74E /* SeparatorCell.swift in Sources */, - EFA4C6742086514A008C4DD8 /* UniversalMappable+Extensions.swift in Sources */, 67153E40207DFBA80049D8C0 /* FloatingPoint+DegreesRadiansConvertion.swift in Sources */, 671462AC1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */, 671463001EB3396E00EAB194 /* UIView+LoadFromNib.swift in Sources */, @@ -2680,7 +2639,6 @@ 671463041EB3396E00EAB194 /* UIView+LoadingIndicator.swift in Sources */, 6774527420624E820024EEEF /* DataLoadingModel.swift in Sources */, 40F118491F8FF223004AADAF /* TableRow+AppearanceExtension.swift in Sources */, - EFA4C66A208650B4008C4DD8 /* UniversalMappable+ImmutableMappable.swift in Sources */, 6727476E206CCDDB00725163 /* ViewBackground+Configuration.swift in Sources */, 671463701EB3396E00EAB194 /* ApiRequestParameters.swift in Sources */, 676B22A2206A626D002E9F8A /* NSAttributedString+Extensions.swift in Sources */, @@ -2699,7 +2657,6 @@ 6714636C1EB3396E00EAB194 /* XibNameProtocol.swift in Sources */, 67274772206CCF1200725163 /* ViewText.swift in Sources */, 67153E3A207DFADA0049D8C0 /* RotateDrawingOperation.swift in Sources */, - 6771DFEA1EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift in Sources */, 671462A01EB3396E00EAB194 /* Double+Rounding.swift in Sources */, 671463081EB3396E00EAB194 /* UIView+Rotation.swift in Sources */, 6714626C1EB3396E00EAB194 /* XibView.swift in Sources */, @@ -2785,7 +2742,6 @@ 67EB7FE620615DE000BDD9FB /* DataSource.swift in Sources */, 6714634A1EB3396E00EAB194 /* ResettableType.swift in Sources */, 671462E61EB3396E00EAB194 /* UIColor+Hex.swift in Sources */, - EFA4C6762086514A008C4DD8 /* UniversalMappable+Extensions.swift in Sources */, A676AE4D1F9810C1001F9214 /* Any+Cast.swift in Sources */, 67FD4384206BD24B005B0C64 /* EqutableOptionalArray.swift in Sources */, EFBE57D21EC35EF20040E00A /* Array+Extensions.swift in Sources */, @@ -2797,7 +2753,6 @@ 67274781206CD3BD00725163 /* ViewText+Extensions.swift in Sources */, 671463561EB3396E00EAB194 /* StaticViewHeightProtocol.swift in Sources */, 671463621EB3396E00EAB194 /* SupportProtocol.swift in Sources */, - 6771DFEC1EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift in Sources */, 678D26A220692BFF00B05B93 /* TextFieldViewEvents.swift in Sources */, 671462861EB3396E00EAB194 /* CGContext+Initializers.swift in Sources */, 6774527B206252020024EEEF /* DataLoadingState.swift in Sources */, @@ -2824,10 +2779,8 @@ 6714632A1EB3396E00EAB194 /* BaseViewModel.swift in Sources */, 671462AE1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */, 67EB7FDC20615D5B00BDD9FB /* ResettableRxCursorDataSource.swift in Sources */, - EFA4C66620864F9C008C4DD8 /* UniversalMappable.swift in Sources */, A6F32C0B1F6EBE5C00AC08EE /* String+LocalizedComponent.swift in Sources */, 6714627E1EB3396E00EAB194 /* AlamofireManager+Extensions.swift in Sources */, - EFA4C66C208650B4008C4DD8 /* UniversalMappable+ImmutableMappable.swift in Sources */, 677452AB206263360024EEEF /* CursorType+RxDataSourceDefaultImplementation.swift in Sources */, 673564F32068C2AD00F0CBED /* NumberFormattingService+DefaultImplementation.swift in Sources */, 67EB7FD620615D1700BDD9FB /* ResettableCursorType.swift in Sources */, @@ -2874,7 +2827,6 @@ 671462DA1EB3396E00EAB194 /* TimeInterval+DateComponents.swift in Sources */, 6714638E1EB3396E00EAB194 /* SolidFillDrawingOperation.swift in Sources */, 6774529420625D170024EEEF /* GeneralDataLoadingModel.swift in Sources */, - EFA4C67120865126008C4DD8 /* UniversalMappable+SwiftStandard.swift in Sources */, 67FDC2611FA310EA00C76A77 /* RequestError.swift in Sources */, 671AD25E206A343300EAF887 /* VoidBlock.swift in Sources */, 671462521EB3396E00EAB194 /* StaticCursor.swift in Sources */, @@ -2929,7 +2881,6 @@ 67FD4385206BD24B005B0C64 /* EqutableOptionalArray.swift in Sources */, 67CAF8AE2065189C00527085 /* NetworkService+ActivityIndicator.swift in Sources */, 6714638B1EB3396E00EAB194 /* RoundDrawingOperation.swift in Sources */, - EFA4C66D208650B4008C4DD8 /* UniversalMappable+ImmutableMappable.swift in Sources */, 67EB7FFF206176C900BDD9FB /* AnyPaginationWrappable.swift in Sources */, A676AE4A1F97D28A001F9214 /* String+Extensions.swift in Sources */, 671463831EB3396E00EAB194 /* PaddingDrawingOperation.swift in Sources */, @@ -2937,7 +2888,6 @@ 677452AC206263360024EEEF /* CursorType+RxDataSourceDefaultImplementation.swift in Sources */, 6714632B1EB3396E00EAB194 /* BaseViewModel.swift in Sources */, 673564F42068C2AD00F0CBED /* NumberFormattingService+DefaultImplementation.swift in Sources */, - EFA4C67220865126008C4DD8 /* UniversalMappable+SwiftStandard.swift in Sources */, 677452A220625EEE0024EEEF /* PaginationDataLoadingModel.swift in Sources */, 673CF4362063E29B00C329F6 /* TextWithButtonPlaceholder.swift in Sources */, A6F32C0C1F6EBE5C00AC08EE /* String+LocalizedComponent.swift in Sources */, @@ -2951,7 +2901,6 @@ 67386A8F206CF3F6004EDA6C /* DateFormattingService+DefaultImplementation.swift in Sources */, 671463071EB3396E00EAB194 /* UIView+LoadingIndicator.swift in Sources */, 6774526E206249E30024EEEF /* UICollectionView+PaginationWrappable.swift in Sources */, - 6771DFED1EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift in Sources */, 671463A91EB340C000EAB194 /* UIViewController+ConfigurableController.swift in Sources */, 673564F92068C68D00F0CBED /* NumberFormat.swift in Sources */, 67274792206CD88600725163 /* DateFormattingService.swift in Sources */, @@ -2968,7 +2917,6 @@ 671462A31EB3396E00EAB194 /* Double+Rounding.swift in Sources */, 6714630B1EB3396E00EAB194 /* UIView+Rotation.swift in Sources */, 673CF4192063D50700C329F6 /* GeneralDataLoadingController.swift in Sources */, - EFA4C66720864F9C008C4DD8 /* UniversalMappable.swift in Sources */, 6792623E206EB0EC00308E62 /* CellSeparatorType+Extensions.swift in Sources */, 6714626F1EB3396E00EAB194 /* XibView.swift in Sources */, 6714637F1EB3396E00EAB194 /* ImageDrawingOperation.swift in Sources */, @@ -2982,7 +2930,6 @@ 67EB7FDD20615D5B00BDD9FB /* ResettableRxCursorDataSource.swift in Sources */, 677452A720625FA90024EEEF /* RxDataSource.swift in Sources */, 6774527720624E820024EEEF /* DataLoadingModel.swift in Sources */, - EFA4C6772086514A008C4DD8 /* UniversalMappable+Extensions.swift in Sources */, 67926239206EB0AE00308E62 /* CellSeparatorType.swift in Sources */, 678D267C20691D8200B05B93 /* DataModelFieldBinding.swift in Sources */, 6714639B1EB3396E00EAB194 /* AnyLoadingIndicator.swift in Sources */, @@ -3059,7 +3006,6 @@ 678D26A520692BFF00B05B93 /* TextFieldViewModelEvents.swift in Sources */, 677452B720627FE00024EEEF /* PaginationWrappable.swift in Sources */, 67EB7FC1206140E600BDD9FB /* TotalCountCursor.swift in Sources */, - 6771DFEB1EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift in Sources */, 67A1FF951EBCA65E00D6C89F /* CABasicAnimation+Rotation.swift in Sources */, 671462811EB3396E00EAB194 /* AlamofireRequest+Extensions.swift in Sources */, 67E6C2361EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */, @@ -3073,7 +3019,6 @@ 671462691EB3396E00EAB194 /* NetworkService.swift in Sources */, 671463111EB3396E00EAB194 /* UIViewController+DefaultXibName.swift in Sources */, 671463411EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */, - EFA4C67020865126008C4DD8 /* UniversalMappable+SwiftStandard.swift in Sources */, 67153E41207DFBA80049D8C0 /* FloatingPoint+DegreesRadiansConvertion.swift in Sources */, 671462911EB3396E00EAB194 /* CGImage+Crop.swift in Sources */, 673564F72068C68D00F0CBED /* NumberFormat.swift in Sources */, @@ -3151,11 +3096,8 @@ 673CF4122063ABD100C329F6 /* GeneralDataLoadingState+Extensions.swift in Sources */, 6714633D1EB3396E00EAB194 /* LoadingIndicator.swift in Sources */, 671463191EB3396E00EAB194 /* UIWindow+Extensions.swift in Sources */, - EFA4C6752086514A008C4DD8 /* UniversalMappable+Extensions.swift in Sources */, 6727478B206CD83600725163 /* DateFormat.swift in Sources */, EFBE57DC1EC361620040E00A /* UIView+Layout.swift in Sources */, - EFA4C66B208650B4008C4DD8 /* UniversalMappable+ImmutableMappable.swift in Sources */, - EFA4C66520864F9C008C4DD8 /* UniversalMappable.swift in Sources */, 67A1FF901EBCA09B00D6C89F /* UIImage+Spinner.swift in Sources */, 6774529B20625E5B0024EEEF /* PaginationDataLoadingState.swift in Sources */, 671463791EB3396E00EAB194 /* CALayerDrawingOperation.swift in Sources */, diff --git a/Sources/Classes/Services/NetworkService.swift b/Sources/Classes/Services/NetworkService.swift index a768c651..edac7141 100644 --- a/Sources/Classes/Services/NetworkService.swift +++ b/Sources/Classes/Services/NetworkService.swift @@ -23,7 +23,6 @@ import RxSwift import RxCocoa import Alamofire -import ObjectMapper import RxAlamofire /// Base network service implementation build on top of LeadKit extensions for Alamofire. diff --git a/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift b/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift index 63d62cb2..deacaa73 100644 --- a/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift +++ b/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift @@ -23,7 +23,6 @@ import Alamofire import RxSwift import RxAlamofire -import ObjectMapper public extension Alamofire.SessionManager { diff --git a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift b/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift index ec14d87b..9a57ae7f 100644 --- a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift +++ b/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift @@ -22,7 +22,6 @@ import Alamofire import RxSwift -import ObjectMapper import RxAlamofire typealias ServerResponse = (HTTPURLResponse, Data) diff --git a/Sources/Extensions/DateFormattingService/DateFormattingService+MappingTransform.swift b/Sources/Extensions/DateFormattingService/DateFormattingService+MappingTransform.swift deleted file mode 100644 index 975118fa..00000000 --- a/Sources/Extensions/DateFormattingService/DateFormattingService+MappingTransform.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright (c) 2017 Touch Instinct -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the Software), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -import ObjectMapper -import SwiftDate - -public extension DateFormattingService { - - /// Creates transform for date to string and string to date mapping. - /// - /// - Parameter arguments: A formatting arguments structure. - /// - Returns: A transform for given formatting arguments. - func mappingTransform(with format: DateFormatType) -> TransformOf { - return TransformOf(fromJSON: { stringValue in - if let stringValue = stringValue { - return self.date(from: stringValue, format: format) - } else { - return nil - } - }, toJSON: { dateValue in - if let dateValue = dateValue { - return self.string(from: dateValue, format: format) - } else { - return nil - } - }) - } - -} - -public extension DateFormattingService where Self: Singleton { - - /// Creates transform for date to string and string to date mapping. - /// - /// - Parameter arguments: A formatting arguments structure. - /// - Returns: A transform for given formatting arguments. - static func mappingTransform(with format: DateFormatType) -> TransformOf { - return shared.mappingTransform(with: format) - } - -} diff --git a/Sources/Extensions/UniversalMappable/UniversalMappable+Extensions.swift b/Sources/Extensions/UniversalMappable/UniversalMappable+Extensions.swift deleted file mode 100644 index 313d90d5..00000000 --- a/Sources/Extensions/UniversalMappable/UniversalMappable+Extensions.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) 2018 Touch Instinct -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the Software), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -import ObjectMapper - -public extension UniversalMappable { - - func encode(to map: Map, key: String) { - self >>> map[key] - } - -} diff --git a/Sources/Extensions/UniversalMappable/UniversalMappable+ImmutableMappable.swift b/Sources/Extensions/UniversalMappable/UniversalMappable+ImmutableMappable.swift deleted file mode 100644 index 4b982fa1..00000000 --- a/Sources/Extensions/UniversalMappable/UniversalMappable+ImmutableMappable.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (c) 2018 Touch Instinct -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the Software), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -import ObjectMapper - -public extension UniversalMappable where Self: ImmutableMappable { - - func encode(to map: Map, key: String) { - self >>> map[key] - } - - static func decode(from map: Map, key: String) throws -> ImmutableMappable { - return try map.value(key) - } - -} diff --git a/Sources/Extensions/UniversalMappable/UniversalMappable+SwiftStandard.swift b/Sources/Extensions/UniversalMappable/UniversalMappable+SwiftStandard.swift deleted file mode 100644 index b43efc17..00000000 --- a/Sources/Extensions/UniversalMappable/UniversalMappable+SwiftStandard.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// Copyright (c) 2018 Touch Instinct -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the Software), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -import ObjectMapper - -extension Int: UniversalMappable {} -extension Int8: UniversalMappable {} -extension Int16: UniversalMappable {} -extension Int32: UniversalMappable {} -extension Int64: UniversalMappable {} - -extension UInt: UniversalMappable {} -extension UInt8: UniversalMappable {} -extension UInt16: UniversalMappable {} -extension UInt32: UniversalMappable {} -extension UInt64: UniversalMappable {} - -extension Float: UniversalMappable {} // aka float32 -extension Float64: UniversalMappable {} // aka double - -public extension BinaryInteger where Self: UniversalMappable { - - static func decode(from map: Map, key: String) throws -> Self { - return try map.value(key) - } - -} - -public extension BinaryFloatingPoint where Self: UniversalMappable { - - static func decode(from map: Map, key: String) throws -> Self { - return try map.value(key) - } - -} - -extension Bool: UniversalMappable { - - public static func decode(from map: Map, key: String) throws -> Bool { - return try map.value(key) - } - -} - -extension String: UniversalMappable { - - public static func decode(from map: Map, key: String) throws -> String { - return try map.value(key) - } - -} diff --git a/Sources/Protocols/ObservableMappable.swift b/Sources/Protocols/ObservableMappable.swift index 25ad6f90..3d157025 100644 --- a/Sources/Protocols/ObservableMappable.swift +++ b/Sources/Protocols/ObservableMappable.swift @@ -20,7 +20,6 @@ // THE SOFTWARE. // -import ObjectMapper import RxSwift /// Protocol for concurrent model mapping diff --git a/Sources/Protocols/UniversalMappable.swift b/Sources/Protocols/UniversalMappable.swift deleted file mode 100644 index 3f2071ad..00000000 --- a/Sources/Protocols/UniversalMappable.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copyright (c) 2018 Touch Instinct -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the Software), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -import ObjectMapper - -/// Protocol for map uniformly generated models -public protocol UniversalMappable { - - /// Method to serialize object into JSON - func encode(to map: Map, key: String) - - /// Method to deserialize object from JSON - static func decode(from map: Map, key: String) throws -> Self - -} diff --git a/Tests/Models/Post.swift b/Tests/Models/Post.swift index 2cce006f..c2bb5e71 100644 --- a/Tests/Models/Post.swift +++ b/Tests/Models/Post.swift @@ -20,7 +20,6 @@ // THE SOFTWARE. // -import ObjectMapper import LeadKit import RxSwift @@ -40,23 +39,6 @@ struct Post: Decodable { } -extension Post: ImmutableMappable { - - init(map: Map) throws { - userId = try map.value("userId") - postId = try map.value("id") - title = try map.value("title") - body = try map.value("body") - } - - mutating func mapping(map: Map) { - userId >>> map["userId"] - postId >>> map["id"] - title >>> map["title"] - body >>> map["body"] - } -} - extension Post: ObservableMappable { static func createFrom(decoder: JSONDecoder, jsonObject: Any) -> Observable { From f88c8efb149694be8eaf3e27e8ab0285585c33b7 Mon Sep 17 00:00:00 2001 From: Madhas Date: Thu, 24 May 2018 12:57:11 +0300 Subject: [PATCH 16/32] correction in network service configuration --- .../NetworkService/NetworkServiceConfiguration.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Structures/NetworkService/NetworkServiceConfiguration.swift b/Sources/Structures/NetworkService/NetworkServiceConfiguration.swift index bd410e6c..a5c3d03a 100644 --- a/Sources/Structures/NetworkService/NetworkServiceConfiguration.swift +++ b/Sources/Structures/NetworkService/NetworkServiceConfiguration.swift @@ -48,12 +48,12 @@ public struct NetworkServiceConfiguration { public init(baseUrl: String, timeoutInterval: TimeInterval = 20, encoding: ParameterEncoding = URLEncoding.default, - additionalHttpHeaders: HTTPHeaders = SessionManager.defaultHTTPHeaders) { + additionalHttpHeaders: HTTPHeaders = [:]) { self.baseUrl = baseUrl self.timeoutInterval = timeoutInterval self.encoding = encoding - self.additionalHttpHeaders = additionalHttpHeaders + self.additionalHttpHeaders = additionalHttpHeaders.merging(SessionManager.defaultHTTPHeaders) { current, _ in current } sessionConfiguration = URLSessionConfiguration.default sessionConfiguration.timeoutIntervalForResource = timeoutInterval From 3edfe50164005062dc14207a772247eebdb9aa1f Mon Sep 17 00:00:00 2001 From: Madhas Date: Thu, 24 May 2018 12:57:30 +0300 Subject: [PATCH 17/32] code review corrections --- .../Alamofire/AlamofireRequest+Extensions.swift | 2 -- Tests/NetworkServiceTests.swift | 15 ++++++--------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift b/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift index 9a57ae7f..86b6dd88 100644 --- a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift +++ b/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift @@ -28,8 +28,6 @@ typealias ServerResponse = (HTTPURLResponse, Data) public extension Reactive where Base: DataRequest { - //private typealias JSON = [String: Any] - /// Method that serializes response into target object /// /// - Parameter mappingQueue: The dispatch queue to use for mapping diff --git a/Tests/NetworkServiceTests.swift b/Tests/NetworkServiceTests.swift index 6c3228b9..72aa157a 100644 --- a/Tests/NetworkServiceTests.swift +++ b/Tests/NetworkServiceTests.swift @@ -33,7 +33,8 @@ final class NetworkServiceTests: XCTestCase { override func setUp() { super.setUp() - let configuration = NetworkServiceConfiguration(baseUrl: "") + let configuration = NetworkServiceConfiguration(baseUrl: "https://jsonplaceholder.typicode.com", + additionalHttpHeaders: ["Content-Type": "application/json"]) networkService = NetworkService(configuration: configuration) disposeBag = DisposeBag() } @@ -53,8 +54,7 @@ final class NetworkServiceTests: XCTestCase { var receivedModel: Album? var error: Error? let requestCompletedExpectation = expectation(description: "Request completed") - let apiRequest = ApiRequestParameters(url: "https://jsonplaceholder.typicode.com/albums/1", - headers: ["Content-Type": "application/json"]) + let apiRequest = ApiRequestParameters(url: networkService.configuration.baseUrl + "/albums/1") // when networkService.rxRequest(with: apiRequest) @@ -80,8 +80,7 @@ final class NetworkServiceTests: XCTestCase { var response: [Album]? var error: Error? let requestCompletedExpectation = expectation(description: "Request completed") - let apiRequest = ApiRequestParameters(url: "https://jsonplaceholder.typicode.com/albums", - headers: ["Content-Type": "application/json"]) + let apiRequest = ApiRequestParameters(url: networkService.configuration.baseUrl + "/albums") //when networkService.rxRequest(with: apiRequest) @@ -111,8 +110,7 @@ final class NetworkServiceTests: XCTestCase { var receivedModel: Album? var error: Error? let requestCompletedExpectation = expectation(description: "Request completed") - let apiRequest = ApiRequestParameters(url: "https://jsonplaceholder.typicode.com/albums/1", - headers: ["Content-Type": "application/json"]) + let apiRequest = ApiRequestParameters(url: networkService.configuration.baseUrl + "/albums/1") // when networkService.rxRequest(with: apiRequest) @@ -138,8 +136,7 @@ final class NetworkServiceTests: XCTestCase { var receivedModel: AlbumContainer? var error: Error? let requestCompletedExpectation = expectation(description: "Request completed") - let apiRequest = ApiRequestParameters(url: "https://jsonplaceholder.typicode.com/albums", - headers: ["Content-Type": "application/json"]) + let apiRequest = ApiRequestParameters(url: networkService.configuration.baseUrl + "/albums") // when networkService.rxRequest(with: apiRequest) From 32eefa77a6cb7f5c65e10eae4aaa3371ff9530f7 Mon Sep 17 00:00:00 2001 From: Madhas Date: Thu, 24 May 2018 13:02:13 +0300 Subject: [PATCH 18/32] rename observable mappable method --- Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift | 2 +- Sources/Protocols/ObservableMappable.swift | 2 +- Tests/Models/Album.swift | 2 +- Tests/Models/AlbumsContainer.swift | 2 +- Tests/Models/Post.swift | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift b/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift index 86b6dd88..da192e17 100644 --- a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift +++ b/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift @@ -54,7 +54,7 @@ public extension Reactive where Base: DataRequest { .observeOn(SerialDispatchQueueScheduler(queue: mappingQueue, internalSerialQueueName: mappingQueue.label)) .tryMapObservableResult { response, value in let json = try JSONSerialization.jsonObject(with: value, options: []) - return T.createFrom(decoder: decoder, jsonObject: json) + return T.create(from: json, with: decoder) .map { (response, $0) } } } diff --git a/Sources/Protocols/ObservableMappable.swift b/Sources/Protocols/ObservableMappable.swift index 3d157025..b6027d09 100644 --- a/Sources/Protocols/ObservableMappable.swift +++ b/Sources/Protocols/ObservableMappable.swift @@ -27,6 +27,6 @@ public protocol ObservableMappable { associatedtype ModelType: Decodable - static func createFrom(decoder: JSONDecoder, jsonObject: Any) -> Observable + static func create(from jsonObject: Any, with decoder: JSONDecoder) -> Observable } diff --git a/Tests/Models/Album.swift b/Tests/Models/Album.swift index 975aef29..d772afa4 100644 --- a/Tests/Models/Album.swift +++ b/Tests/Models/Album.swift @@ -47,7 +47,7 @@ extension Album: Equatable { extension Album: ObservableMappable { - static func createFrom(decoder: JSONDecoder, jsonObject: Any) -> Observable { + static func create(from jsonObject: Any, with decoder: JSONDecoder) -> Observable { return Observable.deferredJust { let data = try JSONSerialization.data(withJSONObject: jsonObject, options: []) return try decoder.decode(Album.self, from: data) diff --git a/Tests/Models/AlbumsContainer.swift b/Tests/Models/AlbumsContainer.swift index 16436892..cc1d6879 100644 --- a/Tests/Models/AlbumsContainer.swift +++ b/Tests/Models/AlbumsContainer.swift @@ -30,7 +30,7 @@ struct AlbumContainer: Decodable { extension AlbumContainer: ObservableMappable { - static func createFrom(decoder: JSONDecoder, jsonObject: Any) -> Observable { + static func create(from jsonObject: Any, with decoder: JSONDecoder) -> Observable { return Observable.deferredJust { try cast(jsonObject) as [Any] } .flatMap { $0.concurrentRxMap { json -> Album in diff --git a/Tests/Models/Post.swift b/Tests/Models/Post.swift index c2bb5e71..a277c6fe 100644 --- a/Tests/Models/Post.swift +++ b/Tests/Models/Post.swift @@ -41,7 +41,7 @@ struct Post: Decodable { extension Post: ObservableMappable { - static func createFrom(decoder: JSONDecoder, jsonObject: Any) -> Observable { + static func create(from jsonObject: Any, with decoder: JSONDecoder) -> Observable { return Observable.deferredJust { let data = try JSONSerialization.data(withJSONObject: jsonObject, options: []) return try decoder.decode(Post.self, from: data) From 20bf8bf8611b8dd46711af4e57ba175065e9624a Mon Sep 17 00:00:00 2001 From: Madhas Date: Thu, 24 May 2018 16:56:21 +0300 Subject: [PATCH 19/32] remove ObjectMapper from podfile update podspec --- LeadKit.podspec | 2 +- LeadKit.xcodeproj/project.pbxproj | 7 ------- Podfile | 1 - Podfile.lock | 5 +---- 4 files changed, 2 insertions(+), 13 deletions(-) diff --git a/LeadKit.podspec b/LeadKit.podspec index 9969cdad..bc6afabe 100644 --- a/LeadKit.podspec +++ b/LeadKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "LeadKit" - s.version = "0.7.18" + s.version = "0.7.19" s.summary = "iOS framework with a bunch of tools for rapid development" s.homepage = "https://github.com/TouchInstinct/LeadKit" s.license = "Apache License, Version 2.0" diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index 9e35565a..332aee93 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -2481,7 +2481,6 @@ inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-LeadKit iOSTests/Pods-LeadKit iOSTests-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Alamofire-iOS/Alamofire.framework", - "${BUILT_PRODUCTS_DIR}/ObjectMapper-iOS/ObjectMapper.framework", "${BUILT_PRODUCTS_DIR}/RxAlamofire-iOS/RxAlamofire.framework", "${BUILT_PRODUCTS_DIR}/RxCocoa-iOS/RxCocoa.framework", "${BUILT_PRODUCTS_DIR}/RxSwift-iOS/RxSwift.framework", @@ -2492,7 +2491,6 @@ name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ObjectMapper.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxAlamofire.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxCocoa.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework", @@ -2546,7 +2544,6 @@ inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-LeadKit tvOSTests/Pods-LeadKit tvOSTests-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Alamofire-tvOS/Alamofire.framework", - "${BUILT_PRODUCTS_DIR}/ObjectMapper-tvOS/ObjectMapper.framework", "${BUILT_PRODUCTS_DIR}/RxAlamofire-tvOS/RxAlamofire.framework", "${BUILT_PRODUCTS_DIR}/RxCocoa-tvOS/RxCocoa.framework", "${BUILT_PRODUCTS_DIR}/RxSwift-tvOS/RxSwift.framework", @@ -2555,7 +2552,6 @@ name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ObjectMapper.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxAlamofire.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxCocoa.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework", @@ -2574,7 +2570,6 @@ inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-LeadKit iOS ExtensionsTests/Pods-LeadKit iOS ExtensionsTests-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Alamofire-iOS/Alamofire.framework", - "${BUILT_PRODUCTS_DIR}/ObjectMapper-iOS/ObjectMapper.framework", "${BUILT_PRODUCTS_DIR}/RxAlamofire-iOS/RxAlamofire.framework", "${BUILT_PRODUCTS_DIR}/RxCocoa-iOS/RxCocoa.framework", "${BUILT_PRODUCTS_DIR}/RxSwift-iOS/RxSwift.framework", @@ -2583,7 +2578,6 @@ name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ObjectMapper.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxAlamofire.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxCocoa.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework", @@ -3069,7 +3063,6 @@ 671462F11EB3396E00EAB194 /* UIImage+SupportExtensions.swift in Sources */, 671462691EB3396E00EAB194 /* NetworkService.swift in Sources */, 671463111EB3396E00EAB194 /* UIViewController+DefaultXibName.swift in Sources */, - 671463411EB3396E00EAB194 /* ModuleConfigurator.swift in Sources */, 67153E41207DFBA80049D8C0 /* FloatingPoint+DegreesRadiansConvertion.swift in Sources */, 671462911EB3396E00EAB194 /* CGImage+Crop.swift in Sources */, 673564F72068C68D00F0CBED /* NumberFormat.swift in Sources */, diff --git a/Podfile b/Podfile index 65552a2c..5a94d11e 100644 --- a/Podfile +++ b/Podfile @@ -2,7 +2,6 @@ abstract_target 'LeadKit' do pod "RxSwift", '~> 4.1' pod "RxCocoa", '~> 4.1' pod "RxAlamofire", '~> 4.1' - pod "ObjectMapper", '~> 3.1' pod "SwiftLint", '~> 0.25' pod "SwiftDate", '~> 4.5' diff --git a/Podfile.lock b/Podfile.lock index 441e4d61..918b2bf6 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,6 +1,5 @@ PODS: - Alamofire (4.7.2) - - ObjectMapper (3.1.0) - RxAlamofire (4.2.0): - RxAlamofire/Core (= 4.2.0) - RxAlamofire/Core (4.2.0): @@ -15,7 +14,6 @@ PODS: - UIScrollView-InfiniteScroll (1.0.2) DEPENDENCIES: - - ObjectMapper (~> 3.1) - RxAlamofire (~> 4.1) - RxCocoa (~> 4.1) - RxSwift (~> 4.1) @@ -26,7 +24,6 @@ DEPENDENCIES: SPEC CHECKSUMS: Alamofire: e4fa87002c137ba2d8d634d2c51fabcda0d5c223 - ObjectMapper: 20505058f54e5c3ca69e1d6de9897d152a5369a6 RxAlamofire: 87a9c588541210cc3e4a1f843ccc3ecf3eb98b31 RxCocoa: d88ba0f1f6abf040011a9eb4b539324fc426843a RxSwift: e49536837d9901277638493ea537394d4b55f570 @@ -35,6 +32,6 @@ SPEC CHECKSUMS: TableKit: 61880e4c13ac0ba396a308fcb1ae48f6dec8b458 UIScrollView-InfiniteScroll: c132d6d5851daff229ab4a1060ccf70a05a051c9 -PODFILE CHECKSUM: c664ef2965e7a828be2da9711aaa145b256e7d99 +PODFILE CHECKSUM: ba4643ffb69782038740755d5b65769fe04b0113 COCOAPODS: 1.4.0 From 69e28eaf5bfbfe9b90baaf68d1fc38f3a84d4542 Mon Sep 17 00:00:00 2001 From: Madhas Date: Thu, 24 May 2018 17:02:38 +0300 Subject: [PATCH 20/32] update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index adc80e97..de2c0595 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### 0.7.19 +- **Add**: tests for `NetworkService` +- **Add**: `toJSON(with encoder: JSONEncoder)` method to `Encodable` +- **Add**: `failedToDecode` error case to `LeadKitError` +- **Remove**: occurrences `ObjectMapper` pod and its occurrences in code +- **Update**: replace `ObjectMapper` mapping with `Decodable` + ### 0.7.18 - **Update**: default implementation of `PaginationWrapperUIDelegate`. From 3dc7b4fe9dd92022b349b3537bf8d228ac8110e1 Mon Sep 17 00:00:00 2001 From: Madhas Date: Thu, 24 May 2018 17:27:15 +0300 Subject: [PATCH 21/32] add Encodable extension to all targets --- LeadKit.xcodeproj/project.pbxproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index 332aee93..99199189 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -548,6 +548,9 @@ A6F32C101F6EBE9600AC08EE /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.swift */; }; A6F32C111F6EBE9700AC08EE /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.swift */; }; A6F32C121F6EBE9800AC08EE /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.swift */; }; + B84CB06920B702240090DB91 /* Codable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B768620B1CF6700F837C4 /* Codable+Extensions.swift */; }; + B84CB06A20B702240090DB91 /* Codable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B768620B1CF6700F837C4 /* Codable+Extensions.swift */; }; + B84CB06B20B702260090DB91 /* Codable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B768620B1CF6700F837C4 /* Codable+Extensions.swift */; }; B84D64B120A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; B84D64B220A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; B84D64B320A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; @@ -2812,6 +2815,7 @@ 6714638A1EB3396E00EAB194 /* RoundDrawingOperation.swift in Sources */, 67153E3C207DFADA0049D8C0 /* RotateDrawingOperation.swift in Sources */, 6774529C20625E5B0024EEEF /* PaginationDataLoadingState.swift in Sources */, + B84CB06A20B702240090DB91 /* Codable+Extensions.swift in Sources */, 67ED2BE020B44DEB00508B3E /* InitializableView.swift in Sources */, 671463821EB3396E00EAB194 /* PaddingDrawingOperation.swift in Sources */, 6714632A1EB3396E00EAB194 /* BaseViewModel.swift in Sources */, @@ -2966,6 +2970,7 @@ 67153E3D207DFADA0049D8C0 /* RotateDrawingOperation.swift in Sources */, 67274782206CD3BD00725163 /* ViewText+Extensions.swift in Sources */, 673CF42E2063DE5900C329F6 /* TextPlaceholderView.swift in Sources */, + B84CB06B20B702260090DB91 /* Codable+Extensions.swift in Sources */, 671462731EB3396E00EAB194 /* CursorError.swift in Sources */, 6727478D206CD83600725163 /* DateFormat.swift in Sources */, 67EB7FDD20615D5B00BDD9FB /* ResettableRxCursorDataSource.swift in Sources */, @@ -3085,6 +3090,7 @@ 67EB7FD520615D1700BDD9FB /* ResettableCursorType.swift in Sources */, 671463251EB3396E00EAB194 /* Any+TypeName.swift in Sources */, 671463891EB3396E00EAB194 /* RoundDrawingOperation.swift in Sources */, + B84CB06920B702240090DB91 /* Codable+Extensions.swift in Sources */, 675C1FB61F97CA33007D5249 /* AppearanceConfigurable.swift in Sources */, 67FD4383206BD24B005B0C64 /* EqutableOptionalArray.swift in Sources */, 671463811EB3396E00EAB194 /* PaddingDrawingOperation.swift in Sources */, From dcc095a233dacc7bbade3be028c68ac08b04d8ae Mon Sep 17 00:00:00 2001 From: Madhas Date: Thu, 24 May 2018 17:27:58 +0300 Subject: [PATCH 22/32] remove ObjectMapper dependancy from podspec, change version --- CHANGELOG.md | 2 +- LeadKit.podspec | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de2c0595..fa508d2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -### 0.7.19 +### 0.8.0 - **Add**: tests for `NetworkService` - **Add**: `toJSON(with encoder: JSONEncoder)` method to `Encodable` - **Add**: `failedToDecode` error case to `LeadKitError` diff --git a/LeadKit.podspec b/LeadKit.podspec index bc6afabe..c8740462 100644 --- a/LeadKit.podspec +++ b/LeadKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "LeadKit" - s.version = "0.7.19" + s.version = "0.8.0" s.summary = "iOS framework with a bunch of tools for rapid development" s.homepage = "https://github.com/TouchInstinct/LeadKit" s.license = "Apache License, Version 2.0" @@ -78,7 +78,6 @@ Pod::Spec.new do |s| ss.dependency "RxSwift", '~> 4.1' ss.dependency "RxCocoa", '~> 4.1' ss.dependency "RxAlamofire", '~> 4.1' - ss.dependency "ObjectMapper", '~> 3.1' ss.dependency "SwiftDate", '~> 4.5' ss.ios.dependency "TableKit", '~> 2.6' @@ -108,7 +107,6 @@ Pod::Spec.new do |s| ss.dependency "RxSwift", '~> 4.1' ss.dependency "RxCocoa", '~> 4.1' ss.dependency "RxAlamofire", '~> 4.1' - ss.dependency "ObjectMapper", '~> 3.1' ss.dependency "SwiftDate", '~> 4.5' end From 475e801393ab142061fcab8047c6b22fc5d30b3c Mon Sep 17 00:00:00 2001 From: Madhas Date: Fri, 25 May 2018 14:36:12 +0300 Subject: [PATCH 23/32] correct ObservableMappable --- Sources/Classes/Services/NetworkService.swift | 6 +++--- .../Extensions/Alamofire/AlamofireManager+Extensions.swift | 2 +- .../Extensions/Alamofire/AlamofireRequest+Extensions.swift | 2 +- Sources/Protocols/ObservableMappable.swift | 6 +++--- Tests/NetworkServiceTests.swift | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Sources/Classes/Services/NetworkService.swift b/Sources/Classes/Services/NetworkService.swift index edac7141..cf91bffa 100644 --- a/Sources/Classes/Services/NetworkService.swift +++ b/Sources/Classes/Services/NetworkService.swift @@ -59,9 +59,9 @@ open class NetworkService { /// - Parameter parameters: api parameters to pass Alamofire /// - Parameter decoder: json decoder to decode response data /// - Returns: Observable of tuple containing (HTTPURLResponse, ObservableMappable) - public func rxRequest(with parameters: ApiRequestParameters, - decoder: JSONDecoder = JSONDecoder()) - -> Observable<(response: HTTPURLResponse, model: T)> where T.ModelType == T { + public func rxObservableRequest(with parameters: ApiRequestParameters, + decoder: JSONDecoder = JSONDecoder()) + -> Observable<(response: HTTPURLResponse, model: T)> { return sessionManager.rx.responseObservableModel(requestParameters: parameters, decoder: decoder, diff --git a/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift b/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift index deacaa73..f25d700f 100644 --- a/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift +++ b/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift @@ -75,7 +75,7 @@ public extension Reactive where Base: Alamofire.SessionManager { decoder: JSONDecoder, mappingQueue: DispatchQueue = .global(), acceptableStatusCodes: Set = Base.defaultAcceptableStatusCodes) - -> Observable<(response: HTTPURLResponse, model: T)> where T.ModelType == T { + -> Observable<(response: HTTPURLResponse, model: T)> { return apiRequest(requestParameters: requestParameters, acceptableStatusCodes: acceptableStatusCodes) .flatMap { $0.rx.observableApiResponse(mappingQueue: mappingQueue, decoder: decoder) } diff --git a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift b/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift index da192e17..e63cf671 100644 --- a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift +++ b/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift @@ -48,7 +48,7 @@ public extension Reactive where Base: DataRequest { /// - Parameter mappingQueue: The dispatch queue to use for mapping /// - Returns: Observable with HTTP URL Response and target object func observableApiResponse(mappingQueue: DispatchQueue = .global(), decoder: JSONDecoder) - -> Observable<(response: HTTPURLResponse, model: T)> where T.ModelType == T { + -> Observable<(response: HTTPURLResponse, model: T)> { return responseData() .observeOn(SerialDispatchQueueScheduler(queue: mappingQueue, internalSerialQueueName: mappingQueue.label)) diff --git a/Sources/Protocols/ObservableMappable.swift b/Sources/Protocols/ObservableMappable.swift index b6027d09..559da931 100644 --- a/Sources/Protocols/ObservableMappable.swift +++ b/Sources/Protocols/ObservableMappable.swift @@ -23,10 +23,10 @@ import RxSwift /// Protocol for concurrent model mapping -public protocol ObservableMappable { +public protocol ObservableMappable where Self: Decodable { - associatedtype ModelType: Decodable + //associatedtype ModelType: Decodable - static func create(from jsonObject: Any, with decoder: JSONDecoder) -> Observable + static func create(from jsonObject: Any, with decoder: JSONDecoder) -> Observable } diff --git a/Tests/NetworkServiceTests.swift b/Tests/NetworkServiceTests.swift index 72aa157a..c310fffe 100644 --- a/Tests/NetworkServiceTests.swift +++ b/Tests/NetworkServiceTests.swift @@ -113,7 +113,7 @@ final class NetworkServiceTests: XCTestCase { let apiRequest = ApiRequestParameters(url: networkService.configuration.baseUrl + "/albums/1") // when - networkService.rxRequest(with: apiRequest) + networkService.rxObservableRequest(with: apiRequest) .subscribe(onNext: { (_, model: Album) in receivedModel = model requestCompletedExpectation.fulfill() @@ -139,7 +139,7 @@ final class NetworkServiceTests: XCTestCase { let apiRequest = ApiRequestParameters(url: networkService.configuration.baseUrl + "/albums") // when - networkService.rxRequest(with: apiRequest) + networkService.rxObservableRequest(with: apiRequest) .subscribe(onNext: { (_, model: AlbumContainer) in receivedModel = model requestCompletedExpectation.fulfill() From e647052af2648869b1df9b91b393618ef2550e9b Mon Sep 17 00:00:00 2001 From: Madhas Date: Fri, 25 May 2018 14:47:16 +0300 Subject: [PATCH 24/32] correct response processing --- .../AlamofireRequest+Extensions.swift | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift b/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift index e63cf671..e46d9703 100644 --- a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift +++ b/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift @@ -36,8 +36,7 @@ public extension Reactive where Base: DataRequest { func apiResponse(mappingQueue: DispatchQueue = .global(), decoder: JSONDecoder) -> Observable<(response: HTTPURLResponse, model: T)> { - return responseData() - .observeOn(SerialDispatchQueueScheduler(queue: mappingQueue, internalSerialQueueName: mappingQueue.label)) + return response(onQueue: mappingQueue) .tryMapResult { response, data in (response, try decoder.decode(T.self, from: data)) } @@ -50,8 +49,7 @@ public extension Reactive where Base: DataRequest { func observableApiResponse(mappingQueue: DispatchQueue = .global(), decoder: JSONDecoder) -> Observable<(response: HTTPURLResponse, model: T)> { - return responseData() - .observeOn(SerialDispatchQueueScheduler(queue: mappingQueue, internalSerialQueueName: mappingQueue.label)) + return response(onQueue: mappingQueue) .tryMapObservableResult { response, value in let json = try JSONSerialization.jsonObject(with: value, options: []) return T.create(from: json, with: decoder) @@ -59,6 +57,31 @@ public extension Reactive where Base: DataRequest { } } + func response(onQueue queue: DispatchQueue) -> Observable<(HTTPURLResponse, Data)> { + return responseData() + .observeOn(SerialDispatchQueueScheduler(queue: queue, internalSerialQueueName: queue.label)) + .catchError { + switch $0 { + case let urlError as URLError: + switch urlError.code { + case .notConnectedToInternet, .timedOut: + throw RequestError.noConnection + default: + throw RequestError.network(error: urlError) + } + case let afError as AFError: + switch afError { + case .responseSerializationFailed, .responseValidationFailed: + throw RequestError.invalidResponse(error: afError) + default: + throw RequestError.network(error: afError) + } + default: + throw RequestError.network(error: $0) + } + } + } + } private extension ObservableType where E == ServerResponse { From 85e58127b7c997d8725e44357fd0ab446fe8465b Mon Sep 17 00:00:00 2001 From: Madhas Date: Fri, 25 May 2018 15:19:30 +0300 Subject: [PATCH 25/32] add SesionManager class some refactor --- LeadKit.xcodeproj/project.pbxproj | 10 +++++ Sources/Classes/Services/NetworkService.swift | 8 ++-- Sources/Classes/Services/SessionManager.swift | 40 +++++++++++++++++++ .../AlamofireManager+Extensions.swift | 27 ++++--------- .../AlamofireRequest+Extensions.swift | 2 +- .../NetworkServiceConfiguration.swift | 7 ++-- 6 files changed, 65 insertions(+), 29 deletions(-) create mode 100644 Sources/Classes/Services/SessionManager.swift diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index 99199189..dc47f354 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -551,6 +551,10 @@ B84CB06920B702240090DB91 /* Codable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B768620B1CF6700F837C4 /* Codable+Extensions.swift */; }; B84CB06A20B702240090DB91 /* Codable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B768620B1CF6700F837C4 /* Codable+Extensions.swift */; }; B84CB06B20B702260090DB91 /* Codable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B768620B1CF6700F837C4 /* Codable+Extensions.swift */; }; + B84CB06D20B8325D0090DB91 /* SessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84CB06C20B8325D0090DB91 /* SessionManager.swift */; }; + B84CB06E20B8325D0090DB91 /* SessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84CB06C20B8325D0090DB91 /* SessionManager.swift */; }; + B84CB06F20B8325D0090DB91 /* SessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84CB06C20B8325D0090DB91 /* SessionManager.swift */; }; + B84CB07020B8325D0090DB91 /* SessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84CB06C20B8325D0090DB91 /* SessionManager.swift */; }; B84D64B120A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; B84D64B220A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; B84D64B320A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; @@ -801,6 +805,7 @@ A6F32C071F6EBDAA00AC08EE /* String+LocalizedComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+LocalizedComponent.swift"; sourceTree = ""; }; A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtensionTests.swift; sourceTree = ""; }; A854A36EB179651E6D0CC9FB /* Pods_LeadKit_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKit_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B84CB06C20B8325D0090DB91 /* SessionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionManager.swift; sourceTree = ""; }; B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkServiceTests.swift; sourceTree = ""; }; B85B766620AC4EA300F837C4 /* Album.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = ""; }; B85B766B20AC51BE00F837C4 /* AlbumsContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumsContainer.swift; sourceTree = ""; }; @@ -924,6 +929,7 @@ isa = PBXGroup; children = ( 671461D31EB3396E00EAB194 /* NetworkService.swift */, + B84CB06C20B8325D0090DB91 /* SessionManager.swift */, ); path = Services; sourceTree = ""; @@ -2674,6 +2680,7 @@ 6727476E206CCDDB00725163 /* ViewBackground+Configuration.swift in Sources */, 671463701EB3396E00EAB194 /* ApiRequestParameters.swift in Sources */, 676B22A2206A626D002E9F8A /* NSAttributedString+Extensions.swift in Sources */, + B84CB06D20B8325D0090DB91 /* SessionManager.swift in Sources */, A658E5501F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift in Sources */, 673564F12068C2AD00F0CBED /* NumberFormattingService+DefaultImplementation.swift in Sources */, 671462EC1EB3396E00EAB194 /* UIImage+Extensions.swift in Sources */, @@ -2842,6 +2849,7 @@ 671462A21EB3396E00EAB194 /* Double+Rounding.swift in Sources */, 67955D54206D216B0021ECD2 /* Singleton.swift in Sources */, 67EB7FF32061682F00BDD9FB /* TotalCountCursorListingResult+DefaultTotalCountCursorListingResult.swift in Sources */, + B84CB06F20B8325D0090DB91 /* SessionManager.swift in Sources */, 67EB7FED2061667900BDD9FB /* DefaultTotalCountCursorListingResult.swift in Sources */, 6714637E1EB3396E00EAB194 /* ImageDrawingOperation.swift in Sources */, 671463361EB3396E00EAB194 /* DrawingOperation.swift in Sources */, @@ -3018,6 +3026,7 @@ 671462531EB3396E00EAB194 /* StaticCursor.swift in Sources */, 6714629F1EB3396E00EAB194 /* CursorType+Slice.swift in Sources */, 6714636B1EB3396E00EAB194 /* ConfigurableView.swift in Sources */, + B84CB07020B8325D0090DB91 /* SessionManager.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3160,6 +3169,7 @@ A676AE561F98112F001F9214 /* ObservableMappable.swift in Sources */, 6737CFA4207220960063E056 /* SeparatorConfiguration+Extensions.swift in Sources */, 67926237206EB0AE00308E62 /* CellSeparatorType.swift in Sources */, + B84CB06E20B8325D0090DB91 /* SessionManager.swift in Sources */, 6774527A206252020024EEEF /* DataLoadingState.swift in Sources */, 6714628D1EB3396E00EAB194 /* CGImage+Alpha.swift in Sources */, 67745269206249360024EEEF /* UITableView+PaginationWrappable.swift in Sources */, diff --git a/Sources/Classes/Services/NetworkService.swift b/Sources/Classes/Services/NetworkService.swift index cf91bffa..04e8b0c8 100644 --- a/Sources/Classes/Services/NetworkService.swift +++ b/Sources/Classes/Services/NetworkService.swift @@ -36,7 +36,7 @@ open class NetworkService { private var disposeBag = DisposeBag() public let configuration: NetworkServiceConfiguration - public let sessionManager: Alamofire.SessionManager + public let sessionManager: SessionManager var requestCount: Driver { return requestCountRelay.asDriver() @@ -64,8 +64,7 @@ open class NetworkService { -> Observable<(response: HTTPURLResponse, model: T)> { return sessionManager.rx.responseObservableModel(requestParameters: parameters, - decoder: decoder, - acceptableStatusCodes: configuration.acceptableStatusCodes) + decoder: decoder) .counterTracking(for: self) } @@ -78,8 +77,7 @@ open class NetworkService { -> Observable<(response: HTTPURLResponse, model: T)> { return sessionManager.rx.responseModel(requestParameters: parameters, - decoder: decoder, - acceptableStatusCodes: configuration.acceptableStatusCodes) + decoder: decoder) .counterTracking(for: self) } diff --git a/Sources/Classes/Services/SessionManager.swift b/Sources/Classes/Services/SessionManager.swift new file mode 100644 index 00000000..b57a70d1 --- /dev/null +++ b/Sources/Classes/Services/SessionManager.swift @@ -0,0 +1,40 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Alamofire + +open class SessionManager: Alamofire.SessionManager { + + public let acceptableStatusCodes: Set + public let mappingQueue: DispatchQueue + + public init(configuration: URLSessionConfiguration, + serverTrustPolicyManager: ServerTrustPolicyManager, + acceptableStatusCodes: Set, + mappingQueue: DispatchQueue) { + + self.acceptableStatusCodes = acceptableStatusCodes + self.mappingQueue = mappingQueue + + super.init(configuration: configuration, serverTrustPolicyManager: serverTrustPolicyManager) + } +} diff --git a/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift b/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift index f25d700f..567f0e23 100644 --- a/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift +++ b/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift @@ -24,21 +24,14 @@ import Alamofire import RxSwift import RxAlamofire -public extension Alamofire.SessionManager { - - /// The default acceptable range 200...299 - static let defaultAcceptableStatusCodes = Set(200..<300) - -} - -public extension Reactive where Base: Alamofire.SessionManager { +public extension Reactive where Base: SessionManager { /// Method which executes request with given api parameters /// /// - Parameter requestParameters: api parameters to pass Alamofire /// - Returns: Observable with request func apiRequest(requestParameters: ApiRequestParameters, - acceptableStatusCodes: Set = Base.defaultAcceptableStatusCodes) + acceptableStatusCodes: Set) -> Observable { return request(requestParameters.method, @@ -56,13 +49,11 @@ public extension Reactive where Base: Alamofire.SessionManager { /// - Parameter mappingQueue: The dispatch queue to use for mapping /// - Returns: Observable with HTTP URL Response and target object func responseModel(requestParameters: ApiRequestParameters, - decoder: JSONDecoder, - mappingQueue: DispatchQueue = .global(), - acceptableStatusCodes: Set = Base.defaultAcceptableStatusCodes) + decoder: JSONDecoder) -> Observable<(response: HTTPURLResponse, model: T)> { - return apiRequest(requestParameters: requestParameters, acceptableStatusCodes: acceptableStatusCodes) - .flatMap { $0.rx.apiResponse(mappingQueue: mappingQueue, decoder: decoder) } + return apiRequest(requestParameters: requestParameters, acceptableStatusCodes: base.acceptableStatusCodes) + .flatMap { $0.rx.apiResponse(mappingQueue: self.base.mappingQueue, decoder: decoder) } } /// Method that executes request and serializes response into target object @@ -72,13 +63,11 @@ public extension Reactive where Base: Alamofire.SessionManager { /// - Parameter mappingQueue: The dispatch queue to use for mapping /// - Returns: Observable with HTTP URL Response and target object func responseObservableModel(requestParameters: ApiRequestParameters, - decoder: JSONDecoder, - mappingQueue: DispatchQueue = .global(), - acceptableStatusCodes: Set = Base.defaultAcceptableStatusCodes) + decoder: JSONDecoder) -> Observable<(response: HTTPURLResponse, model: T)> { - return apiRequest(requestParameters: requestParameters, acceptableStatusCodes: acceptableStatusCodes) - .flatMap { $0.rx.observableApiResponse(mappingQueue: mappingQueue, decoder: decoder) } + return apiRequest(requestParameters: requestParameters, acceptableStatusCodes: base.acceptableStatusCodes) + .flatMap { $0.rx.observableApiResponse(mappingQueue: self.base.mappingQueue, decoder: decoder) } } } diff --git a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift b/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift index e46d9703..47eef191 100644 --- a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift +++ b/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift @@ -57,7 +57,7 @@ public extension Reactive where Base: DataRequest { } } - func response(onQueue queue: DispatchQueue) -> Observable<(HTTPURLResponse, Data)> { + private func response(onQueue queue: DispatchQueue) -> Observable<(HTTPURLResponse, Data)> { return responseData() .observeOn(SerialDispatchQueueScheduler(queue: queue, internalSerialQueueName: queue.label)) .catchError { diff --git a/Sources/Structures/NetworkService/NetworkServiceConfiguration.swift b/Sources/Structures/NetworkService/NetworkServiceConfiguration.swift index a5c3d03a..0424a985 100644 --- a/Sources/Structures/NetworkService/NetworkServiceConfiguration.swift +++ b/Sources/Structures/NetworkService/NetworkServiceConfiguration.swift @@ -39,9 +39,6 @@ public struct NetworkServiceConfiguration { /// Server trust policies. public var serverTrustPolicies: [String: ServerTrustPolicy] - /// Acceptable status codes for validation - public var acceptableStatusCodes: Set = Alamofire.SessionManager.defaultAcceptableStatusCodes - /// Session configuration for potential fine tuning public var sessionConfiguration: URLSessionConfiguration @@ -69,7 +66,9 @@ public extension NetworkServiceConfiguration { /// SessionManager constructed with given parameters (session configuration and trust policies) var sessionManager: SessionManager { return SessionManager(configuration: sessionConfiguration, - serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)) + serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies), + acceptableStatusCodes: Set(200..<300), + mappingQueue: .global()) } /// Convenient method to create ApiRequestParameters. From 6db6258db5b4fa247e021d20e9a8bd84560dcd1b Mon Sep 17 00:00:00 2001 From: Madhas Date: Fri, 25 May 2018 15:22:17 +0300 Subject: [PATCH 26/32] changelog corrected --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c9b2bb6..ebfcdcbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - **Add**: tests for `NetworkService` - **Add**: `toJSON(with encoder: JSONEncoder)` method to `Encodable` - **Add**: `failedToDecode` error case to `LeadKitError` +- **Add**: `SessionManager` class - **Remove**: occurrences `ObjectMapper` pod and its occurrences in code - **Update**: replace `ObjectMapper` mapping with `Decodable` From 996081f65ef43838acb4fb1b6b6715206646a5d0 Mon Sep 17 00:00:00 2001 From: Madhas Date: Fri, 25 May 2018 15:55:48 +0300 Subject: [PATCH 27/32] corrections --- Sources/Classes/Services/SessionManager.swift | 4 ++++ .../Alamofire/AlamofireManager+Extensions.swift | 11 ++++------- Sources/Protocols/ObservableMappable.swift | 2 -- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Sources/Classes/Services/SessionManager.swift b/Sources/Classes/Services/SessionManager.swift index b57a70d1..512078b2 100644 --- a/Sources/Classes/Services/SessionManager.swift +++ b/Sources/Classes/Services/SessionManager.swift @@ -22,9 +22,13 @@ import Alamofire +/// Session Manager stored in NetworkService open class SessionManager: Alamofire.SessionManager { + /// Acceptable status codes for validation public let acceptableStatusCodes: Set + + /// Dispatch Queue on which mapping is performed public let mappingQueue: DispatchQueue public init(configuration: URLSessionConfiguration, diff --git a/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift b/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift index 567f0e23..aa9ef655 100644 --- a/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift +++ b/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift @@ -30,8 +30,7 @@ public extension Reactive where Base: SessionManager { /// /// - Parameter requestParameters: api parameters to pass Alamofire /// - Returns: Observable with request - func apiRequest(requestParameters: ApiRequestParameters, - acceptableStatusCodes: Set) + func apiRequest(requestParameters: ApiRequestParameters) -> Observable { return request(requestParameters.method, @@ -39,20 +38,19 @@ public extension Reactive where Base: SessionManager { parameters: requestParameters.parameters, encoding: requestParameters.encoding, headers: requestParameters.headers) - .map { $0.validate(statusCode: acceptableStatusCodes) } + .map { $0.validate(statusCode: self.base.acceptableStatusCodes) } } /// Method that executes request and serializes response into target object /// /// - Parameter requestParameters: api parameters to pass Alamofire /// - Parameter decoder: json decoder to decode response data - /// - Parameter mappingQueue: The dispatch queue to use for mapping /// - Returns: Observable with HTTP URL Response and target object func responseModel(requestParameters: ApiRequestParameters, decoder: JSONDecoder) -> Observable<(response: HTTPURLResponse, model: T)> { - return apiRequest(requestParameters: requestParameters, acceptableStatusCodes: base.acceptableStatusCodes) + return apiRequest(requestParameters: requestParameters) .flatMap { $0.rx.apiResponse(mappingQueue: self.base.mappingQueue, decoder: decoder) } } @@ -60,13 +58,12 @@ public extension Reactive where Base: SessionManager { /// /// - Parameter requestParameters: api parameters to pass Alamofire /// - Parameter decoder: json decoder to decode response data - /// - Parameter mappingQueue: The dispatch queue to use for mapping /// - Returns: Observable with HTTP URL Response and target object func responseObservableModel(requestParameters: ApiRequestParameters, decoder: JSONDecoder) -> Observable<(response: HTTPURLResponse, model: T)> { - return apiRequest(requestParameters: requestParameters, acceptableStatusCodes: base.acceptableStatusCodes) + return apiRequest(requestParameters: requestParameters) .flatMap { $0.rx.observableApiResponse(mappingQueue: self.base.mappingQueue, decoder: decoder) } } diff --git a/Sources/Protocols/ObservableMappable.swift b/Sources/Protocols/ObservableMappable.swift index 559da931..ca232fb6 100644 --- a/Sources/Protocols/ObservableMappable.swift +++ b/Sources/Protocols/ObservableMappable.swift @@ -25,8 +25,6 @@ import RxSwift /// Protocol for concurrent model mapping public protocol ObservableMappable where Self: Decodable { - //associatedtype ModelType: Decodable - static func create(from jsonObject: Any, with decoder: JSONDecoder) -> Observable } From bba41c7122a6b2c7f77f2818fc771f089675ba48 Mon Sep 17 00:00:00 2001 From: Madhas Date: Fri, 25 May 2018 16:22:43 +0300 Subject: [PATCH 28/32] add init to SessionManager --- Sources/Classes/Services/SessionManager.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Sources/Classes/Services/SessionManager.swift b/Sources/Classes/Services/SessionManager.swift index 512078b2..47ce6307 100644 --- a/Sources/Classes/Services/SessionManager.swift +++ b/Sources/Classes/Services/SessionManager.swift @@ -41,4 +41,16 @@ open class SessionManager: Alamofire.SessionManager { super.init(configuration: configuration, serverTrustPolicyManager: serverTrustPolicyManager) } + + public init?(session: URLSession, + delegate: SessionDelegate, + serverTrustPolicyManager: ServerTrustPolicyManager, + acceptableStatusCodes: Set, + mappingQueue: DispatchQueue) { + + self.acceptableStatusCodes = acceptableStatusCodes + self.mappingQueue = mappingQueue + + super.init(session: session, delegate: delegate, serverTrustPolicyManager: serverTrustPolicyManager) + } } From ca9b2eaca3511f33aa8e7b7501d654c612395b51 Mon Sep 17 00:00:00 2001 From: Madhas Date: Fri, 25 May 2018 16:23:59 +0300 Subject: [PATCH 29/32] rename AlamofireManager extension file --- LeadKit.xcodeproj/project.pbxproj | 20 +++++++++---------- ....swift => SessionManager+Extensions.swift} | 0 2 files changed, 10 insertions(+), 10 deletions(-) rename Sources/Extensions/Alamofire/{AlamofireManager+Extensions.swift => SessionManager+Extensions.swift} (100%) diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index dc47f354..a6314fca 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -60,10 +60,10 @@ 671462791EB3396E00EAB194 /* ResizeMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461D91EB3396E00EAB194 /* ResizeMode.swift */; }; 6714627A1EB3396E00EAB194 /* ResizeMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461D91EB3396E00EAB194 /* ResizeMode.swift */; }; 6714627B1EB3396E00EAB194 /* ResizeMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461D91EB3396E00EAB194 /* ResizeMode.swift */; }; - 6714627C1EB3396E00EAB194 /* AlamofireManager+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DC1EB3396E00EAB194 /* AlamofireManager+Extensions.swift */; }; - 6714627D1EB3396E00EAB194 /* AlamofireManager+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DC1EB3396E00EAB194 /* AlamofireManager+Extensions.swift */; }; - 6714627E1EB3396E00EAB194 /* AlamofireManager+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DC1EB3396E00EAB194 /* AlamofireManager+Extensions.swift */; }; - 6714627F1EB3396E00EAB194 /* AlamofireManager+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DC1EB3396E00EAB194 /* AlamofireManager+Extensions.swift */; }; + 6714627C1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DC1EB3396E00EAB194 /* SessionManager+Extensions.swift */; }; + 6714627D1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DC1EB3396E00EAB194 /* SessionManager+Extensions.swift */; }; + 6714627E1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DC1EB3396E00EAB194 /* SessionManager+Extensions.swift */; }; + 6714627F1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DC1EB3396E00EAB194 /* SessionManager+Extensions.swift */; }; 671462801EB3396E00EAB194 /* AlamofireRequest+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DD1EB3396E00EAB194 /* AlamofireRequest+Extensions.swift */; }; 671462811EB3396E00EAB194 /* AlamofireRequest+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DD1EB3396E00EAB194 /* AlamofireRequest+Extensions.swift */; }; 671462821EB3396E00EAB194 /* AlamofireRequest+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DD1EB3396E00EAB194 /* AlamofireRequest+Extensions.swift */; }; @@ -639,7 +639,7 @@ 671461D71EB3396E00EAB194 /* CursorError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CursorError.swift; sourceTree = ""; }; 671461D81EB3396E00EAB194 /* LeadKitError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LeadKitError.swift; sourceTree = ""; }; 671461D91EB3396E00EAB194 /* ResizeMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResizeMode.swift; sourceTree = ""; }; - 671461DC1EB3396E00EAB194 /* AlamofireManager+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AlamofireManager+Extensions.swift"; sourceTree = ""; }; + 671461DC1EB3396E00EAB194 /* SessionManager+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SessionManager+Extensions.swift"; sourceTree = ""; }; 671461DD1EB3396E00EAB194 /* AlamofireRequest+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AlamofireRequest+Extensions.swift"; sourceTree = ""; }; 671461DF1EB3396E00EAB194 /* CGContext+Initializers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGContext+Initializers.swift"; sourceTree = ""; }; 671461E11EB3396E00EAB194 /* CGFloat+Pixels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGFloat+Pixels.swift"; sourceTree = ""; }; @@ -994,7 +994,7 @@ 671461DB1EB3396E00EAB194 /* Alamofire */ = { isa = PBXGroup; children = ( - 671461DC1EB3396E00EAB194 /* AlamofireManager+Extensions.swift */, + 671461DC1EB3396E00EAB194 /* SessionManager+Extensions.swift */, 671461DD1EB3396E00EAB194 /* AlamofireRequest+Extensions.swift */, ); path = Alamofire; @@ -2666,7 +2666,7 @@ 671462AC1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */, 671463001EB3396E00EAB194 /* UIView+LoadFromNib.swift in Sources */, A676AE501F9810C1001F9214 /* Any+Cast.swift in Sources */, - 6714627C1EB3396E00EAB194 /* AlamofireManager+Extensions.swift in Sources */, + 6714627C1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */, 671462D41EB3396E00EAB194 /* TableDirector+Extensions.swift in Sources */, 671462781EB3396E00EAB194 /* ResizeMode.swift in Sources */, A676AE551F98112E001F9214 /* ObservableMappable.swift in Sources */, @@ -2829,7 +2829,7 @@ 671462AE1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */, 67EB7FDC20615D5B00BDD9FB /* ResettableRxCursorDataSource.swift in Sources */, A6F32C0B1F6EBE5C00AC08EE /* String+LocalizedComponent.swift in Sources */, - 6714627E1EB3396E00EAB194 /* AlamofireManager+Extensions.swift in Sources */, + 6714627E1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */, 677452AB206263360024EEEF /* CursorType+RxDataSourceDefaultImplementation.swift in Sources */, 673564F32068C2AD00F0CBED /* NumberFormattingService+DefaultImplementation.swift in Sources */, 67EB7FD620615D1700BDD9FB /* ResettableCursorType.swift in Sources */, @@ -2946,7 +2946,7 @@ 671462AF1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */, A676AE4F1F9810C1001F9214 /* Any+Cast.swift in Sources */, 671463031EB3396E00EAB194 /* UIView+LoadFromNib.swift in Sources */, - 6714627F1EB3396E00EAB194 /* AlamofireManager+Extensions.swift in Sources */, + 6714627F1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */, 6737CFA5207220960063E056 /* SeparatorConfiguration+Extensions.swift in Sources */, 6714627B1EB3396E00EAB194 /* ResizeMode.swift in Sources */, 67745289206259CF0024EEEF /* Rx+RxDataSourceProtocol.swift in Sources */, @@ -3109,7 +3109,7 @@ 671462AD1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */, 671463011EB3396E00EAB194 /* UIView+LoadFromNib.swift in Sources */, 6774526D206249E30024EEEF /* UICollectionView+PaginationWrappable.swift in Sources */, - 6714627D1EB3396E00EAB194 /* AlamofireManager+Extensions.swift in Sources */, + 6714627D1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */, 673CF4352063E29B00C329F6 /* TextWithButtonPlaceholder.swift in Sources */, 6727476F206CCDDB00725163 /* ViewBackground+Configuration.swift in Sources */, 673CF4232063D90600C329F6 /* DisposeBagHolder.swift in Sources */, diff --git a/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift b/Sources/Extensions/Alamofire/SessionManager+Extensions.swift similarity index 100% rename from Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift rename to Sources/Extensions/Alamofire/SessionManager+Extensions.swift From 3ef5795bfc55587960a660a18ddbb8c894455aec Mon Sep 17 00:00:00 2001 From: Madhas Date: Fri, 25 May 2018 16:26:36 +0300 Subject: [PATCH 30/32] rename AlamofireRequest file --- LeadKit.xcodeproj/project.pbxproj | 20 +++++++++---------- ...ons.swift => DataRequest+Extensions.swift} | 0 2 files changed, 10 insertions(+), 10 deletions(-) rename Sources/Extensions/Alamofire/{AlamofireRequest+Extensions.swift => DataRequest+Extensions.swift} (100%) diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index a6314fca..a58df88c 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -64,10 +64,10 @@ 6714627D1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DC1EB3396E00EAB194 /* SessionManager+Extensions.swift */; }; 6714627E1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DC1EB3396E00EAB194 /* SessionManager+Extensions.swift */; }; 6714627F1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DC1EB3396E00EAB194 /* SessionManager+Extensions.swift */; }; - 671462801EB3396E00EAB194 /* AlamofireRequest+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DD1EB3396E00EAB194 /* AlamofireRequest+Extensions.swift */; }; - 671462811EB3396E00EAB194 /* AlamofireRequest+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DD1EB3396E00EAB194 /* AlamofireRequest+Extensions.swift */; }; - 671462821EB3396E00EAB194 /* AlamofireRequest+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DD1EB3396E00EAB194 /* AlamofireRequest+Extensions.swift */; }; - 671462831EB3396E00EAB194 /* AlamofireRequest+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DD1EB3396E00EAB194 /* AlamofireRequest+Extensions.swift */; }; + 671462801EB3396E00EAB194 /* DataRequest+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DD1EB3396E00EAB194 /* DataRequest+Extensions.swift */; }; + 671462811EB3396E00EAB194 /* DataRequest+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DD1EB3396E00EAB194 /* DataRequest+Extensions.swift */; }; + 671462821EB3396E00EAB194 /* DataRequest+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DD1EB3396E00EAB194 /* DataRequest+Extensions.swift */; }; + 671462831EB3396E00EAB194 /* DataRequest+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DD1EB3396E00EAB194 /* DataRequest+Extensions.swift */; }; 671462841EB3396E00EAB194 /* CGContext+Initializers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DF1EB3396E00EAB194 /* CGContext+Initializers.swift */; }; 671462851EB3396E00EAB194 /* CGContext+Initializers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DF1EB3396E00EAB194 /* CGContext+Initializers.swift */; }; 671462861EB3396E00EAB194 /* CGContext+Initializers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461DF1EB3396E00EAB194 /* CGContext+Initializers.swift */; }; @@ -640,7 +640,7 @@ 671461D81EB3396E00EAB194 /* LeadKitError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LeadKitError.swift; sourceTree = ""; }; 671461D91EB3396E00EAB194 /* ResizeMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResizeMode.swift; sourceTree = ""; }; 671461DC1EB3396E00EAB194 /* SessionManager+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SessionManager+Extensions.swift"; sourceTree = ""; }; - 671461DD1EB3396E00EAB194 /* AlamofireRequest+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AlamofireRequest+Extensions.swift"; sourceTree = ""; }; + 671461DD1EB3396E00EAB194 /* DataRequest+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DataRequest+Extensions.swift"; sourceTree = ""; }; 671461DF1EB3396E00EAB194 /* CGContext+Initializers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGContext+Initializers.swift"; sourceTree = ""; }; 671461E11EB3396E00EAB194 /* CGFloat+Pixels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGFloat+Pixels.swift"; sourceTree = ""; }; 671461E31EB3396E00EAB194 /* CGImage+Alpha.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGImage+Alpha.swift"; sourceTree = ""; }; @@ -995,7 +995,7 @@ isa = PBXGroup; children = ( 671461DC1EB3396E00EAB194 /* SessionManager+Extensions.swift */, - 671461DD1EB3396E00EAB194 /* AlamofireRequest+Extensions.swift */, + 671461DD1EB3396E00EAB194 /* DataRequest+Extensions.swift */, ); path = Alamofire; sourceTree = ""; @@ -2616,7 +2616,7 @@ 678D26A020692BFF00B05B93 /* TextFieldViewEvents.swift in Sources */, 6727478F206CD88600725163 /* DateFormattingService.swift in Sources */, 678D26A420692BFF00B05B93 /* TextFieldViewModelEvents.swift in Sources */, - 671462801EB3396E00EAB194 /* AlamofireRequest+Extensions.swift in Sources */, + 671462801EB3396E00EAB194 /* DataRequest+Extensions.swift in Sources */, 67EB7FF8206175F700BDD9FB /* PaginationWrappable.swift in Sources */, 671463541EB3396E00EAB194 /* StaticViewHeightProtocol.swift in Sources */, 673CF4112063ABD100C329F6 /* GeneralDataLoadingState+Extensions.swift in Sources */, @@ -2793,7 +2793,7 @@ EFBE57D21EC35EF20040E00A /* Array+Extensions.swift in Sources */, 6727478C206CD83600725163 /* DateFormat.swift in Sources */, 67EB7FC2206140E600BDD9FB /* TotalCountCursor.swift in Sources */, - 671462821EB3396E00EAB194 /* AlamofireRequest+Extensions.swift in Sources */, + 671462821EB3396E00EAB194 /* DataRequest+Extensions.swift in Sources */, 67745288206259CF0024EEEF /* Rx+RxDataSourceProtocol.swift in Sources */, 67E6C2371EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */, 67274781206CD3BD00725163 /* ViewText+Extensions.swift in Sources */, @@ -2895,7 +2895,7 @@ 67ED2BE120B44DEB00508B3E /* InitializableView.swift in Sources */, 67274775206CCF1200725163 /* ViewText.swift in Sources */, 6727476B206CCCA500725163 /* ViewBackground.swift in Sources */, - 671462831EB3396E00EAB194 /* AlamofireRequest+Extensions.swift in Sources */, + 671462831EB3396E00EAB194 /* DataRequest+Extensions.swift in Sources */, 67ED2BE820B44F4300508B3E /* InitializableView+DefaultImplementation.swift in Sources */, 677452B820627FE00024EEEF /* PaginationWrappable.swift in Sources */, 673CF40E2063AB7C00C329F6 /* GeneralDataLoadingViewModel.swift in Sources */, @@ -3065,7 +3065,7 @@ 6713C23D20AF0D5900875921 /* NetworkOperationModel.swift in Sources */, 67EB7FC1206140E600BDD9FB /* TotalCountCursor.swift in Sources */, 67A1FF951EBCA65E00D6C89F /* CABasicAnimation+Rotation.swift in Sources */, - 671462811EB3396E00EAB194 /* AlamofireRequest+Extensions.swift in Sources */, + 671462811EB3396E00EAB194 /* DataRequest+Extensions.swift in Sources */, 67E6C2361EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */, 671463551EB3396E00EAB194 /* StaticViewHeightProtocol.swift in Sources */, 671463611EB3396E00EAB194 /* SupportProtocol.swift in Sources */, diff --git a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift b/Sources/Extensions/Alamofire/DataRequest+Extensions.swift similarity index 100% rename from Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift rename to Sources/Extensions/Alamofire/DataRequest+Extensions.swift From d408d1eed6a814ea35ab2879005dd69ccf0ddf9d Mon Sep 17 00:00:00 2001 From: Madhas Date: Fri, 25 May 2018 18:26:02 +0300 Subject: [PATCH 31/32] codable extension public --- .../DataLoading/PaginationDataLoading/PaginationWrapper.swift | 2 +- Sources/Extensions/Codable/Codable+Extensions.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/Classes/DataLoading/PaginationDataLoading/PaginationWrapper.swift b/Sources/Classes/DataLoading/PaginationDataLoading/PaginationWrapper.swift index 55abcb12..bcc6a3c1 100644 --- a/Sources/Classes/DataLoading/PaginationDataLoading/PaginationWrapper.swift +++ b/Sources/Classes/DataLoading/PaginationDataLoading/PaginationWrapper.swift @@ -210,7 +210,7 @@ final public class PaginationWrapper [String: Any] { + public func toJSON(with encoder: JSONEncoder = JSONEncoder()) -> [String: Any] { guard let data = try? encoder.encode(self) else { return [:] } From 754875556df9fb0b3ad263f3201f86c176cb1c47 Mon Sep 17 00:00:00 2001 From: Madhas Date: Fri, 25 May 2018 19:45:23 +0300 Subject: [PATCH 32/32] encodable extension renamed init from json added to Decodable --- LeadKit.xcodeproj/project.pbxproj | 30 ++++++++++++------ .../Codable/Decodable+Extensions.swift | 31 +++++++++++++++++++ ...sions.swift => Encodable+Extensions.swift} | 2 +- 3 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 Sources/Extensions/Codable/Decodable+Extensions.swift rename Sources/Extensions/Codable/{Codable+Extensions.swift => Encodable+Extensions.swift} (94%) diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index a58df88c..db4b61eb 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -548,13 +548,17 @@ A6F32C101F6EBE9600AC08EE /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.swift */; }; A6F32C111F6EBE9700AC08EE /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.swift */; }; A6F32C121F6EBE9800AC08EE /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.swift */; }; - B84CB06920B702240090DB91 /* Codable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B768620B1CF6700F837C4 /* Codable+Extensions.swift */; }; - B84CB06A20B702240090DB91 /* Codable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B768620B1CF6700F837C4 /* Codable+Extensions.swift */; }; - B84CB06B20B702260090DB91 /* Codable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B768620B1CF6700F837C4 /* Codable+Extensions.swift */; }; + B84CB06920B702240090DB91 /* Encodable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B768620B1CF6700F837C4 /* Encodable+Extensions.swift */; }; + B84CB06A20B702240090DB91 /* Encodable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B768620B1CF6700F837C4 /* Encodable+Extensions.swift */; }; + B84CB06B20B702260090DB91 /* Encodable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B768620B1CF6700F837C4 /* Encodable+Extensions.swift */; }; B84CB06D20B8325D0090DB91 /* SessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84CB06C20B8325D0090DB91 /* SessionManager.swift */; }; B84CB06E20B8325D0090DB91 /* SessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84CB06C20B8325D0090DB91 /* SessionManager.swift */; }; B84CB06F20B8325D0090DB91 /* SessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84CB06C20B8325D0090DB91 /* SessionManager.swift */; }; B84CB07020B8325D0090DB91 /* SessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84CB06C20B8325D0090DB91 /* SessionManager.swift */; }; + B84CB07820B872AD0090DB91 /* Decodable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84CB07720B872AD0090DB91 /* Decodable+Extensions.swift */; }; + B84CB07920B872AD0090DB91 /* Decodable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84CB07720B872AD0090DB91 /* Decodable+Extensions.swift */; }; + B84CB07A20B872AD0090DB91 /* Decodable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84CB07720B872AD0090DB91 /* Decodable+Extensions.swift */; }; + B84CB07B20B872AD0090DB91 /* Decodable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84CB07720B872AD0090DB91 /* Decodable+Extensions.swift */; }; B84D64B120A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; B84D64B220A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; B84D64B320A70B7000DD76DA /* NetworkServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */; }; @@ -564,7 +568,7 @@ B85B766D20AC51C600F837C4 /* AlbumsContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B766B20AC51BE00F837C4 /* AlbumsContainer.swift */; }; B85B766E20AC51C600F837C4 /* AlbumsContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B766B20AC51BE00F837C4 /* AlbumsContainer.swift */; }; B85B766F20AC51C700F837C4 /* AlbumsContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B766B20AC51BE00F837C4 /* AlbumsContainer.swift */; }; - B85B768720B1CF6700F837C4 /* Codable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B768620B1CF6700F837C4 /* Codable+Extensions.swift */; }; + B85B768720B1CF6700F837C4 /* Encodable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85B768620B1CF6700F837C4 /* Encodable+Extensions.swift */; }; BA6C6DB45950382041948FC5 /* Pods_LeadKit_LeadKit_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CFE9323150A9760008093F73 /* Pods_LeadKit_LeadKit_iOS.framework */; }; D6EE55093E404DEA62B03DDF /* Pods_LeadKit_LeadKit_watchOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8590CA7831555C295C5DC572 /* Pods_LeadKit_LeadKit_watchOS.framework */; }; D93221EE20A44896003799D5 /* Double+RoundingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D93221ED20A44896003799D5 /* Double+RoundingTests.swift */; }; @@ -806,10 +810,11 @@ A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtensionTests.swift; sourceTree = ""; }; A854A36EB179651E6D0CC9FB /* Pods_LeadKit_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKit_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B84CB06C20B8325D0090DB91 /* SessionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionManager.swift; sourceTree = ""; }; + B84CB07720B872AD0090DB91 /* Decodable+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Decodable+Extensions.swift"; sourceTree = ""; }; B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkServiceTests.swift; sourceTree = ""; }; B85B766620AC4EA300F837C4 /* Album.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = ""; }; B85B766B20AC51BE00F837C4 /* AlbumsContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumsContainer.swift; sourceTree = ""; }; - B85B768620B1CF6700F837C4 /* Codable+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Codable+Extensions.swift"; sourceTree = ""; }; + B85B768620B1CF6700F837C4 /* Encodable+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Encodable+Extensions.swift"; sourceTree = ""; }; BECC6E4BF63781403877B059 /* Pods-LeadKit-LeadKit watchOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit-LeadKit watchOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit-LeadKit watchOS/Pods-LeadKit-LeadKit watchOS.release.xcconfig"; sourceTree = ""; }; CB02EAC4E52AF48AD64EC045 /* Pods-LeadKit iOS ExtensionsTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit iOS ExtensionsTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit iOS ExtensionsTests/Pods-LeadKit iOS ExtensionsTests.debug.xcconfig"; sourceTree = ""; }; CD7003F75FD6DDC97DC99A7A /* Pods-LeadKit iOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKit iOSTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKit iOSTests/Pods-LeadKit iOSTests.debug.xcconfig"; sourceTree = ""; }; @@ -1791,7 +1796,8 @@ B85B768520B1CF4C00F837C4 /* Codable */ = { isa = PBXGroup; children = ( - B85B768620B1CF6700F837C4 /* Codable+Extensions.swift */, + B84CB07720B872AD0090DB91 /* Decodable+Extensions.swift */, + B85B768620B1CF6700F837C4 /* Encodable+Extensions.swift */, ); path = Codable; sourceTree = ""; @@ -2678,6 +2684,7 @@ 6774527420624E820024EEEF /* DataLoadingModel.swift in Sources */, 40F118491F8FF223004AADAF /* TableRow+AppearanceExtension.swift in Sources */, 6727476E206CCDDB00725163 /* ViewBackground+Configuration.swift in Sources */, + B84CB07820B872AD0090DB91 /* Decodable+Extensions.swift in Sources */, 671463701EB3396E00EAB194 /* ApiRequestParameters.swift in Sources */, 676B22A2206A626D002E9F8A /* NSAttributedString+Extensions.swift in Sources */, B84CB06D20B8325D0090DB91 /* SessionManager.swift in Sources */, @@ -2691,7 +2698,7 @@ 67EB7FEB2061667900BDD9FB /* DefaultTotalCountCursorListingResult.swift in Sources */, 671AD26C206A3E8500EAF887 /* Array+TotalCountCursorListingResult.swift in Sources */, 673CF4382063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.swift in Sources */, - B85B768720B1CF6700F837C4 /* Codable+Extensions.swift in Sources */, + B85B768720B1CF6700F837C4 /* Encodable+Extensions.swift in Sources */, 671AD267206A365100EAF887 /* UIApplication+OpenUrlSupport.swift in Sources */, 673CF40B2063AB7C00C329F6 /* GeneralDataLoadingViewModel.swift in Sources */, 6713C23720AF0C4D00875921 /* NetworkOperationState.swift in Sources */, @@ -2822,7 +2829,7 @@ 6714638A1EB3396E00EAB194 /* RoundDrawingOperation.swift in Sources */, 67153E3C207DFADA0049D8C0 /* RotateDrawingOperation.swift in Sources */, 6774529C20625E5B0024EEEF /* PaginationDataLoadingState.swift in Sources */, - B84CB06A20B702240090DB91 /* Codable+Extensions.swift in Sources */, + B84CB06A20B702240090DB91 /* Encodable+Extensions.swift in Sources */, 67ED2BE020B44DEB00508B3E /* InitializableView.swift in Sources */, 671463821EB3396E00EAB194 /* PaddingDrawingOperation.swift in Sources */, 6714632A1EB3396E00EAB194 /* BaseViewModel.swift in Sources */, @@ -2883,6 +2890,7 @@ 67ED2BE720B44F4300508B3E /* InitializableView+DefaultImplementation.swift in Sources */, 6714629E1EB3396E00EAB194 /* CursorType+Slice.swift in Sources */, 6714636A1EB3396E00EAB194 /* ConfigurableView.swift in Sources */, + B84CB07A20B872AD0090DB91 /* Decodable+Extensions.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2957,6 +2965,7 @@ 673564F92068C68D00F0CBED /* NumberFormat.swift in Sources */, 67274792206CD88600725163 /* DateFormattingService.swift in Sources */, A676AE581F981131001F9214 /* ObservableMappable.swift in Sources */, + B84CB07B20B872AD0090DB91 /* Decodable+Extensions.swift in Sources */, 671463731EB3396E00EAB194 /* ApiRequestParameters.swift in Sources */, 671462EF1EB3396E00EAB194 /* UIImage+Extensions.swift in Sources */, 671AD269206A365100EAF887 /* UIApplication+OpenUrlSupport.swift in Sources */, @@ -2978,7 +2987,7 @@ 67153E3D207DFADA0049D8C0 /* RotateDrawingOperation.swift in Sources */, 67274782206CD3BD00725163 /* ViewText+Extensions.swift in Sources */, 673CF42E2063DE5900C329F6 /* TextPlaceholderView.swift in Sources */, - B84CB06B20B702260090DB91 /* Codable+Extensions.swift in Sources */, + B84CB06B20B702260090DB91 /* Encodable+Extensions.swift in Sources */, 671462731EB3396E00EAB194 /* CursorError.swift in Sources */, 6727478D206CD83600725163 /* DateFormat.swift in Sources */, 67EB7FDD20615D5B00BDD9FB /* ResettableRxCursorDataSource.swift in Sources */, @@ -3053,6 +3062,7 @@ files = ( 678D267A20691D8200B05B93 /* DataModelFieldBinding.swift in Sources */, 67EB7FE520615DE000BDD9FB /* DataSource.swift in Sources */, + B84CB07920B872AD0090DB91 /* Decodable+Extensions.swift in Sources */, 671463491EB3396E00EAB194 /* ResettableType.swift in Sources */, 67386A8D206CF3F6004EDA6C /* DateFormattingService+DefaultImplementation.swift in Sources */, A676AE491F97D28A001F9214 /* String+Extensions.swift in Sources */, @@ -3099,7 +3109,7 @@ 67EB7FD520615D1700BDD9FB /* ResettableCursorType.swift in Sources */, 671463251EB3396E00EAB194 /* Any+TypeName.swift in Sources */, 671463891EB3396E00EAB194 /* RoundDrawingOperation.swift in Sources */, - B84CB06920B702240090DB91 /* Codable+Extensions.swift in Sources */, + B84CB06920B702240090DB91 /* Encodable+Extensions.swift in Sources */, 675C1FB61F97CA33007D5249 /* AppearanceConfigurable.swift in Sources */, 67FD4383206BD24B005B0C64 /* EqutableOptionalArray.swift in Sources */, 671463811EB3396E00EAB194 /* PaddingDrawingOperation.swift in Sources */, diff --git a/Sources/Extensions/Codable/Decodable+Extensions.swift b/Sources/Extensions/Codable/Decodable+Extensions.swift new file mode 100644 index 00000000..88236c56 --- /dev/null +++ b/Sources/Extensions/Codable/Decodable+Extensions.swift @@ -0,0 +1,31 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +public extension Decodable { + + init(JSON: Any, decoder: JSONDecoder = JSONDecoder()) throws { + let data = try JSONSerialization.data(withJSONObject: JSON, options: .prettyPrinted) + self = try decoder.decode(Self.self, from: data) + } +} diff --git a/Sources/Extensions/Codable/Codable+Extensions.swift b/Sources/Extensions/Codable/Encodable+Extensions.swift similarity index 94% rename from Sources/Extensions/Codable/Codable+Extensions.swift rename to Sources/Extensions/Codable/Encodable+Extensions.swift index 616531bb..ced45817 100644 --- a/Sources/Extensions/Codable/Codable+Extensions.swift +++ b/Sources/Extensions/Codable/Encodable+Extensions.swift @@ -24,7 +24,7 @@ import Foundation public extension Encodable { - public func toJSON(with encoder: JSONEncoder = JSONEncoder()) -> [String: Any] { + func toJSON(with encoder: JSONEncoder = JSONEncoder()) -> [String: Any] { guard let data = try? encoder.encode(self) else { return [:] }