diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b631f95..ebfcdcbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +### 0.8.0 +- **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` + ### 0.7.19 - **Fix**: `PaginationWrapper` retry button showing. 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 diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index 93b737c0..db4b61eb 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -60,14 +60,14 @@ 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 */; }; - 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 */; }; + 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 /* 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 */; }; @@ -360,10 +360,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,6 +548,27 @@ 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 /* 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 */; }; + 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 */; }; + 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 */; }; @@ -562,22 +579,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 */; }; @@ -642,8 +643,8 @@ 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 = ""; }; - 671461DD1EB3396E00EAB194 /* AlamofireRequest+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AlamofireRequest+Extensions.swift"; sourceTree = ""; }; + 671461DC1EB3396E00EAB194 /* SessionManager+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SessionManager+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 = ""; }; @@ -732,7 +733,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 /* PaginationWrapperUIDelegate+DefaultImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PaginationWrapperUIDelegate+DefaultImplementation.swift"; sourceTree = ""; }; @@ -809,6 +809,12 @@ 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 = ""; }; + 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 /* 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 = ""; }; @@ -818,10 +824,6 @@ D93221ED20A44896003799D5 /* Double+RoundingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+RoundingTests.swift"; 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 */ @@ -932,6 +934,7 @@ isa = PBXGroup; children = ( 671461D31EB3396E00EAB194 /* NetworkService.swift */, + B84CB06C20B8325D0090DB91 /* SessionManager.swift */, ); path = Services; sourceTree = ""; @@ -969,6 +972,7 @@ EFBE57CE1EC35ED90040E00A /* Array */, 67A1FF921EBCA64A00D6C89F /* CABasicAnimation */, 671461E01EB3396E00EAB194 /* CGFloat */, + B85B768520B1CF4C00F837C4 /* Codable */, A6D10EA91F8A9269003E69DD /* Comparable */, 67745284206259C20024EEEF /* DataLoading */, 6771DFE81EEA7C8F002DCDAE /* DateFormattingService */, @@ -987,7 +991,6 @@ 671462021EB3396E00EAB194 /* TimeInterval */, 671462081EB3396E00EAB194 /* UIColor */, 672947E0206EA36B00AC6B6B /* UIKit */, - EFA4C6682086508B008C4DD8 /* UniversalMappable */, 6727476C206CCD3100725163 /* Views */, ); path = Extensions; @@ -996,8 +999,8 @@ 671461DB1EB3396E00EAB194 /* Alamofire */ = { isa = PBXGroup; children = ( - 671461DC1EB3396E00EAB194 /* AlamofireManager+Extensions.swift */, - 671461DD1EB3396E00EAB194 /* AlamofireRequest+Extensions.swift */, + 671461DC1EB3396E00EAB194 /* SessionManager+Extensions.swift */, + 671461DD1EB3396E00EAB194 /* DataRequest+Extensions.swift */, ); path = Alamofire; sourceTree = ""; @@ -1184,7 +1187,6 @@ 67955D51206D216B0021ECD2 /* Singleton.swift */, 6714622E1EB3396E00EAB194 /* StaticViewHeightProtocol.swift */, 671462311EB3396E00EAB194 /* SupportProtocol.swift */, - EFA4C66320864F9C008C4DD8 /* UniversalMappable.swift */, 671462321EB3396E00EAB194 /* ViewHeightProtocol.swift */, 678D269C20692BFF00B05B93 /* Views */, 671462341EB3396E00EAB194 /* XibNameProtocol.swift */, @@ -1256,6 +1258,8 @@ 671463B21EB34B1E00EAB194 /* Models */ = { isa = PBXGroup; children = ( + B85B766620AC4EA300F837C4 /* Album.swift */, + B85B766B20AC51BE00F837C4 /* AlbumsContainer.swift */, 671463B31EB34B1E00EAB194 /* Post.swift */, ); path = Models; @@ -1308,6 +1312,7 @@ 67186C1A1EB24B7800CFAFFB /* Info-iOS.plist */, 6782BBB91EB31DD90086E0B8 /* Info-tvOS.plist */, 671463B01EB34B1E00EAB194 /* LoadFromNibTests.swift */, + B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */, ); path = Tests; sourceTree = ""; @@ -1479,7 +1484,6 @@ 6771DFE81EEA7C8F002DCDAE /* DateFormattingService */ = { isa = PBXGroup; children = ( - 6771DFE91EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift */, 67386A8B206CF3F6004EDA6C /* DateFormattingService+DefaultImplementation.swift */, ); path = DateFormattingService; @@ -1789,6 +1793,15 @@ path = Extensions; sourceTree = ""; }; + B85B768520B1CF4C00F837C4 /* Codable */ = { + isa = PBXGroup; + children = ( + B84CB07720B872AD0090DB91 /* Decodable+Extensions.swift */, + B85B768620B1CF6700F837C4 /* Encodable+Extensions.swift */, + ); + path = Codable; + sourceTree = ""; + }; C90516DF61394D92FF071C0C /* Frameworks */ = { isa = PBXGroup; children = ( @@ -1838,16 +1851,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 = ( @@ -2493,7 +2496,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", @@ -2504,7 +2506,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", @@ -2558,7 +2559,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", @@ -2567,7 +2567,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", @@ -2586,7 +2585,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", @@ -2595,7 +2593,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", @@ -2625,7 +2622,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 */, @@ -2644,7 +2641,6 @@ 674AF55C1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.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 */, @@ -2663,7 +2659,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 */, @@ -2673,12 +2668,11 @@ 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 */, 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 */, @@ -2689,10 +2683,11 @@ 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 */, + B84CB07820B872AD0090DB91 /* Decodable+Extensions.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 */, @@ -2703,13 +2698,13 @@ 67EB7FEB2061667900BDD9FB /* DefaultTotalCountCursorListingResult.swift in Sources */, 671AD26C206A3E8500EAF887 /* Array+TotalCountCursorListingResult.swift in Sources */, 673CF4382063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.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 */, 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 */, @@ -2781,11 +2776,14 @@ D93221EE20A44896003799D5 /* Double+RoundingTests.swift in Sources */, 671463CA1EB34B1E00EAB194 /* TestView.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 */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2797,20 +2795,18 @@ 6714634A1EB3396E00EAB194 /* ResettableType.swift in Sources */, 6713C23E20AF0D5900875921 /* NetworkOperationModel.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 */, 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 */, 6713C23920AF0C4D00875921 /* NetworkOperationState.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 */, @@ -2833,15 +2829,14 @@ 6714638A1EB3396E00EAB194 /* RoundDrawingOperation.swift in Sources */, 67153E3C207DFADA0049D8C0 /* RotateDrawingOperation.swift in Sources */, 6774529C20625E5B0024EEEF /* PaginationDataLoadingState.swift in Sources */, + B84CB06A20B702240090DB91 /* Encodable+Extensions.swift in Sources */, 67ED2BE020B44DEB00508B3E /* InitializableView.swift in Sources */, 671463821EB3396E00EAB194 /* PaddingDrawingOperation.swift in Sources */, 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 */, + 6714627E1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */, 677452AB206263360024EEEF /* CursorType+RxDataSourceDefaultImplementation.swift in Sources */, 673564F32068C2AD00F0CBED /* NumberFormattingService+DefaultImplementation.swift in Sources */, 67EB7FD620615D1700BDD9FB /* ResettableCursorType.swift in Sources */, @@ -2861,6 +2856,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 */, @@ -2888,13 +2884,13 @@ 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 */, 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; }; @@ -2907,7 +2903,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 */, @@ -2945,7 +2941,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 */, @@ -2953,25 +2948,24 @@ 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 */, 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 */, 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 */, 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 */, @@ -2985,7 +2979,6 @@ 6714630B1EB3396E00EAB194 /* UIView+Rotation.swift in Sources */, 6713C23F20AF0D5900875921 /* NetworkOperationModel.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 */, @@ -2994,12 +2987,12 @@ 67153E3D207DFADA0049D8C0 /* RotateDrawingOperation.swift in Sources */, 67274782206CD3BD00725163 /* ViewText+Extensions.swift in Sources */, 673CF42E2063DE5900C329F6 /* TextPlaceholderView.swift in Sources */, + B84CB06B20B702260090DB91 /* Encodable+Extensions.swift in Sources */, 671462731EB3396E00EAB194 /* CursorError.swift in Sources */, 6727478D206CD83600725163 /* DateFormat.swift in Sources */, 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 */, @@ -3042,6 +3035,7 @@ 671462531EB3396E00EAB194 /* StaticCursor.swift in Sources */, 6714629F1EB3396E00EAB194 /* CursorType+Slice.swift in Sources */, 6714636B1EB3396E00EAB194 /* ConfigurableView.swift in Sources */, + B84CB07020B8325D0090DB91 /* SessionManager.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3049,9 +3043,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 */, + B85B766A20AC4EC700F837C4 /* Album.swift in Sources */, A6F32C121F6EBE9800AC08EE /* StringExtensionTests.swift in Sources */, D93221F020A44896003799D5 /* Double+RoundingTests.swift in Sources */, 671463C01EB34B1E00EAB194 /* LoadFromNibTests.swift in Sources */, @@ -3065,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 */, @@ -3076,9 +3074,8 @@ 677452B720627FE00024EEEF /* PaginationWrappable.swift in Sources */, 6713C23D20AF0D5900875921 /* NetworkOperationModel.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 */, + 671462811EB3396E00EAB194 /* DataRequest+Extensions.swift in Sources */, 67E6C2361EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */, 671463551EB3396E00EAB194 /* StaticViewHeightProtocol.swift in Sources */, 671463611EB3396E00EAB194 /* SupportProtocol.swift in Sources */, @@ -3090,7 +3087,6 @@ 671462F11EB3396E00EAB194 /* UIImage+SupportExtensions.swift in Sources */, 671462691EB3396E00EAB194 /* NetworkService.swift in Sources */, 671463111EB3396E00EAB194 /* UIViewController+DefaultXibName.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 */, @@ -3113,6 +3109,7 @@ 67EB7FD520615D1700BDD9FB /* ResettableCursorType.swift in Sources */, 671463251EB3396E00EAB194 /* Any+TypeName.swift in Sources */, 671463891EB3396E00EAB194 /* RoundDrawingOperation.swift in Sources */, + B84CB06920B702240090DB91 /* Encodable+Extensions.swift in Sources */, 675C1FB61F97CA33007D5249 /* AppearanceConfigurable.swift in Sources */, 67FD4383206BD24B005B0C64 /* EqutableOptionalArray.swift in Sources */, 671463811EB3396E00EAB194 /* PaddingDrawingOperation.swift in Sources */, @@ -3122,7 +3119,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 */, @@ -3171,11 +3168,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 */, @@ -3185,6 +3179,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 */, @@ -3211,12 +3206,15 @@ 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 */, + B85B766E20AC51C600F837C4 /* AlbumsContainer.swift in Sources */, D93221EF20A44896003799D5 /* Double+RoundingTests.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/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 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 { return requestCountRelay.asDriver() @@ -58,24 +57,27 @@ 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) - -> 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, - acceptableStatusCodes: configuration.acceptableStatusCodes) + decoder: decoder) .counterTracking(for: self) } /// 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) + public func rxRequest(with parameters: ApiRequestParameters, decoder: JSONDecoder = JSONDecoder()) -> Observable<(response: HTTPURLResponse, model: T)> { return sessionManager.rx.responseModel(requestParameters: parameters, - 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..47ce6307 --- /dev/null +++ b/Sources/Classes/Services/SessionManager.swift @@ -0,0 +1,56 @@ +// +// 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 + +/// 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, + serverTrustPolicyManager: ServerTrustPolicyManager, + acceptableStatusCodes: Set, + mappingQueue: DispatchQueue) { + + self.acceptableStatusCodes = acceptableStatusCodes + self.mappingQueue = mappingQueue + + 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) + } +} 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) } diff --git a/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift b/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift deleted file mode 100644 index 351323df..00000000 --- a/Sources/Extensions/Alamofire/AlamofireManager+Extensions.swift +++ /dev/null @@ -1,123 +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 Alamofire -import RxSwift -import RxAlamofire -import ObjectMapper - -public extension Alamofire.SessionManager { - - /// The default acceptable range 200...299 - static let defaultAcceptableStatusCodes = Set(200..<300) - -} - -public extension Reactive where Base: Alamofire.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) - -> Observable { - - return request(requestParameters.method, - requestParameters.url, - parameters: requestParameters.parameters, - encoding: requestParameters.encoding, - headers: requestParameters.headers) - .map { $0.validate(statusCode: acceptableStatusCodes) } - } - - /// Method that executes request and serializes response into target object - /// - /// - 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 responseModel(requestParameters: ApiRequestParameters, - 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) } - } - - /// Method that executes request and serializes response into target object - /// - /// - 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 responseObservableModel(requestParameters: ApiRequestParameters, - 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) } - } - - /// 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/DataRequest+Extensions.swift similarity index 50% rename from Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift rename to Sources/Extensions/Alamofire/DataRequest+Extensions.swift index 01d2d61b..47eef191 100644 --- a/Sources/Extensions/Alamofire/AlamofireRequest+Extensions.swift +++ b/Sources/Extensions/Alamofire/DataRequest+Extensions.swift @@ -22,55 +22,23 @@ import Alamofire 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] - /// 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 response(onQueue: mappingQueue) + .tryMapResult { response, data in + (response, try decoder.decode(T.self, from: data)) } } @@ -78,43 +46,20 @@ 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()) - -> Observable<(response: HTTPURLResponse, model: T)> where T.ModelType == T { + func observableApiResponse(mappingQueue: DispatchQueue = .global(), decoder: JSONDecoder) + -> Observable<(response: HTTPURLResponse, model: 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 response(onQueue: mappingQueue) + .tryMapObservableResult { response, value in + let json = try JSONSerialization.jsonObject(with: value, options: []) + return T.create(from: json, with: decoder) + .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(response: $0.0, result: $0.1) } + private 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: @@ -152,14 +97,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) } } } diff --git a/Sources/Extensions/Alamofire/SessionManager+Extensions.swift b/Sources/Extensions/Alamofire/SessionManager+Extensions.swift new file mode 100644 index 00000000..aa9ef655 --- /dev/null +++ b/Sources/Extensions/Alamofire/SessionManager+Extensions.swift @@ -0,0 +1,70 @@ +// +// 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 Alamofire +import RxSwift +import RxAlamofire + +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) + -> Observable { + + return request(requestParameters.method, + requestParameters.url, + parameters: requestParameters.parameters, + encoding: requestParameters.encoding, + headers: requestParameters.headers) + .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 + /// - Returns: Observable with HTTP URL Response and target object + func responseModel(requestParameters: ApiRequestParameters, + decoder: JSONDecoder) + -> Observable<(response: HTTPURLResponse, model: T)> { + + return apiRequest(requestParameters: requestParameters) + .flatMap { $0.rx.apiResponse(mappingQueue: self.base.mappingQueue, decoder: decoder) } + } + + /// 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 + /// - Returns: Observable with HTTP URL Response and target object + func responseObservableModel(requestParameters: ApiRequestParameters, + decoder: JSONDecoder) + -> Observable<(response: HTTPURLResponse, model: T)> { + + return apiRequest(requestParameters: requestParameters) + .flatMap { $0.rx.observableApiResponse(mappingQueue: self.base.mappingQueue, decoder: decoder) } + } + +} diff --git a/Sources/Extensions/UniversalMappable/UniversalMappable+Extensions.swift b/Sources/Extensions/Codable/Decodable+Extensions.swift similarity index 81% rename from Sources/Extensions/UniversalMappable/UniversalMappable+Extensions.swift rename to Sources/Extensions/Codable/Decodable+Extensions.swift index 313d90d5..88236c56 100644 --- a/Sources/Extensions/UniversalMappable/UniversalMappable+Extensions.swift +++ b/Sources/Extensions/Codable/Decodable+Extensions.swift @@ -20,12 +20,12 @@ // THE SOFTWARE. // -import ObjectMapper +import Foundation -public extension UniversalMappable { +public extension Decodable { - func encode(to map: Map, key: String) { - self >>> map[key] + 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/UniversalMappable/UniversalMappable+ImmutableMappable.swift b/Sources/Extensions/Codable/Encodable+Extensions.swift similarity index 75% rename from Sources/Extensions/UniversalMappable/UniversalMappable+ImmutableMappable.swift rename to Sources/Extensions/Codable/Encodable+Extensions.swift index 4b982fa1..ced45817 100644 --- a/Sources/Extensions/UniversalMappable/UniversalMappable+ImmutableMappable.swift +++ b/Sources/Extensions/Codable/Encodable+Extensions.swift @@ -20,16 +20,19 @@ // THE SOFTWARE. // -import ObjectMapper +import Foundation -public extension UniversalMappable where Self: ImmutableMappable { +public extension Encodable { - func encode(to map: Map, key: String) { - self >>> map[key] + 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 } - - static func decode(from map: Map, key: String) throws -> ImmutableMappable { - return try map.value(key) - } - } 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/Protocols/ObservableMappable.swift b/Sources/Protocols/ObservableMappable.swift index 5d97a040..ca232fb6 100644 --- a/Sources/Protocols/ObservableMappable.swift +++ b/Sources/Protocols/ObservableMappable.swift @@ -20,14 +20,11 @@ // THE SOFTWARE. // -import ObjectMapper import RxSwift /// Protocol for concurrent model mapping -public protocol ObservableMappable { +public protocol ObservableMappable where Self: Decodable { - associatedtype ModelType - - static func createFrom(map: Map) -> Observable + static func create(from jsonObject: Any, with decoder: JSONDecoder) -> Observable } diff --git a/Sources/Structures/NetworkService/NetworkServiceConfiguration.swift b/Sources/Structures/NetworkService/NetworkServiceConfiguration.swift index bd410e6c..0424a985 100644 --- a/Sources/Structures/NetworkService/NetworkServiceConfiguration.swift +++ b/Sources/Structures/NetworkService/NetworkServiceConfiguration.swift @@ -39,21 +39,18 @@ 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 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 @@ -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. diff --git a/Sources/Extensions/UniversalMappable/UniversalMappable+SwiftStandard.swift b/Tests/Models/Album.swift similarity index 50% rename from Sources/Extensions/UniversalMappable/UniversalMappable+SwiftStandard.swift rename to Tests/Models/Album.swift index b43efc17..d772afa4 100644 --- a/Sources/Extensions/UniversalMappable/UniversalMappable+SwiftStandard.swift +++ b/Tests/Models/Album.swift @@ -20,51 +20,37 @@ // THE SOFTWARE. // -import ObjectMapper +import LeadKit +import RxSwift -extension Int: UniversalMappable {} -extension Int8: UniversalMappable {} -extension Int16: UniversalMappable {} -extension Int32: UniversalMappable {} -extension Int64: UniversalMappable {} +struct Album: Decodable { -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) + enum CodingKeys: String, CodingKey { + case userId + case albumId = "id" + case title } + let userId: Int + let albumId: Int + let title: String } -public extension BinaryFloatingPoint where Self: UniversalMappable { +extension Album: Equatable { - static func decode(from map: Map, key: String) throws -> Self { - return try map.value(key) + static func == (lhs: Album, rhs: Album) -> Bool { + return lhs.userId == rhs.userId && + lhs.albumId == rhs.albumId && + lhs.title == rhs.title } - } -extension Bool: UniversalMappable { +extension Album: ObservableMappable { - public static func decode(from map: Map, key: String) throws -> Bool { - return try map.value(key) + 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) + } } - -} - -extension String: UniversalMappable { - - public static func decode(from map: Map, key: String) throws -> String { - return try map.value(key) - } - } diff --git a/Sources/Protocols/UniversalMappable.swift b/Tests/Models/AlbumsContainer.swift similarity index 62% rename from Sources/Protocols/UniversalMappable.swift rename to Tests/Models/AlbumsContainer.swift index 3f2071ad..cc1d6879 100644 --- a/Sources/Protocols/UniversalMappable.swift +++ b/Tests/Models/AlbumsContainer.swift @@ -20,15 +20,27 @@ // THE SOFTWARE. // -import ObjectMapper +import LeadKit +import RxSwift -/// 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 +struct AlbumContainer: Decodable { + let albums: [Album] } + +extension AlbumContainer: ObservableMappable { + + static func create(from jsonObject: Any, with decoder: JSONDecoder) -> 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 ab6a170d..a277c6fe 100644 --- a/Tests/Models/Post.swift +++ b/Tests/Models/Post.swift @@ -20,36 +20,33 @@ // THE SOFTWARE. // -import ObjectMapper +import LeadKit +import RxSwift -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 - } +} - init(map: Map) throws { - userId = try map.value("userId") - postId = try map.value("id") - title = try map.value("title") - body = try map.value("body") - } +extension Post: ObservableMappable { - mutating func mapping(map: Map) { - userId >>> map["userId"] - postId >>> map["id"] - title >>> map["title"] - body >>> map["body"] + 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) + } } - } extension Post: Equatable { diff --git a/Tests/NetworkServiceTests.swift b/Tests/NetworkServiceTests.swift new file mode 100644 index 00000000..c310fffe --- /dev/null +++ b/Tests/NetworkServiceTests.swift @@ -0,0 +1,162 @@ +// +// 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 XCTest +import LeadKit +import RxSwift + +final class NetworkServiceTests: XCTestCase { + + var disposeBag: DisposeBag! + + var networkService: NetworkService! + + override func setUp() { + super.setUp() + + let configuration = NetworkServiceConfiguration(baseUrl: "https://jsonplaceholder.typicode.com", + additionalHttpHeaders: ["Content-Type": "application/json"]) + networkService = NetworkService(configuration: configuration) + disposeBag = DisposeBag() + } + + override func tearDown() { + disposeBag = nil + networkService = nil + super.tearDown() + } + + func testModelRequest() { + // given + let expectedModel = Album(userId: 1, + albumId: 1, + title: "quidem molestiae enim") + + var receivedModel: Album? + var error: Error? + let requestCompletedExpectation = expectation(description: "Request completed") + let apiRequest = ApiRequestParameters(url: networkService.configuration.baseUrl + "/albums/1") + + // when + networkService.rxRequest(with: apiRequest) + .subscribe(onNext: { (_, model: Album) 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) + } + + func testModelArrayRequest() { + // given + var response: [Album]? + var error: Error? + let requestCompletedExpectation = expectation(description: "Request completed") + let apiRequest = ApiRequestParameters(url: networkService.configuration.baseUrl + "/albums") + + //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 = Album(userId: 1, + albumId: 1, + title: "quidem molestiae enim") + + var receivedModel: Album? + var error: Error? + let requestCompletedExpectation = expectation(description: "Request completed") + let apiRequest = ApiRequestParameters(url: networkService.configuration.baseUrl + "/albums/1") + + // when + networkService.rxObservableRequest(with: apiRequest) + .subscribe(onNext: { (_, model: Album) 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) + } + + func testObservableModelArrayRequest() { + // given + var receivedModel: AlbumContainer? + var error: Error? + let requestCompletedExpectation = expectation(description: "Request completed") + let apiRequest = ApiRequestParameters(url: networkService.configuration.baseUrl + "/albums") + + // when + networkService.rxObservableRequest(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) + receivedModel?.albums.enumerated().forEach { index, element in + XCTAssertEqual(element.albumId, index + 1) + } + } +}