Merge pull request #139 from TouchInstinct/feature/codable

Feature/codable
This commit is contained in:
Andrey Ovsyannikov 2018-05-28 14:56:55 +03:00 committed by GitHub
commit 87abcde0ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 494 additions and 448 deletions

View File

@ -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.

View File

@ -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

View File

@ -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 = "<group>"; };
671461D81EB3396E00EAB194 /* LeadKitError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LeadKitError.swift; sourceTree = "<group>"; };
671461D91EB3396E00EAB194 /* ResizeMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResizeMode.swift; sourceTree = "<group>"; };
671461DC1EB3396E00EAB194 /* AlamofireManager+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AlamofireManager+Extensions.swift"; sourceTree = "<group>"; };
671461DD1EB3396E00EAB194 /* AlamofireRequest+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AlamofireRequest+Extensions.swift"; sourceTree = "<group>"; };
671461DC1EB3396E00EAB194 /* SessionManager+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SessionManager+Extensions.swift"; sourceTree = "<group>"; };
671461DD1EB3396E00EAB194 /* DataRequest+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DataRequest+Extensions.swift"; sourceTree = "<group>"; };
671461DF1EB3396E00EAB194 /* CGContext+Initializers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGContext+Initializers.swift"; sourceTree = "<group>"; };
671461E11EB3396E00EAB194 /* CGFloat+Pixels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGFloat+Pixels.swift"; sourceTree = "<group>"; };
671461E31EB3396E00EAB194 /* CGImage+Alpha.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGImage+Alpha.swift"; sourceTree = "<group>"; };
@ -732,7 +733,6 @@
674AF55B1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIActivityIndicatorView+LoadingIndicator.swift"; sourceTree = "<group>"; };
6762131720A0BBA30034EEF1 /* TableSection+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TableSection+Extensions.swift"; sourceTree = "<group>"; };
676B22A1206A626D002E9F8A /* NSAttributedString+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+Extensions.swift"; sourceTree = "<group>"; };
6771DFE91EEA7CB8002DCDAE /* DateFormattingService+MappingTransform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DateFormattingService+MappingTransform.swift"; sourceTree = "<group>"; };
67745267206249360024EEEF /* UITableView+PaginationWrappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+PaginationWrappable.swift"; sourceTree = "<group>"; };
6774526B206249E30024EEEF /* UICollectionView+PaginationWrappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionView+PaginationWrappable.swift"; sourceTree = "<group>"; };
6774526F20624A2A0024EEEF /* PaginationWrapperUIDelegate+DefaultImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PaginationWrapperUIDelegate+DefaultImplementation.swift"; sourceTree = "<group>"; };
@ -809,6 +809,12 @@
A6F32C071F6EBDAA00AC08EE /* String+LocalizedComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+LocalizedComponent.swift"; sourceTree = "<group>"; };
A6F32C0E1F6EBE8E00AC08EE /* StringExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtensionTests.swift; sourceTree = "<group>"; };
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 = "<group>"; };
B84CB07720B872AD0090DB91 /* Decodable+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Decodable+Extensions.swift"; sourceTree = "<group>"; };
B84D64B020A70B7000DD76DA /* NetworkServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkServiceTests.swift; sourceTree = "<group>"; };
B85B766620AC4EA300F837C4 /* Album.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = "<group>"; };
B85B766B20AC51BE00F837C4 /* AlbumsContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumsContainer.swift; sourceTree = "<group>"; };
B85B768620B1CF6700F837C4 /* Encodable+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Encodable+Extensions.swift"; sourceTree = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
@ -818,10 +824,6 @@
D93221ED20A44896003799D5 /* Double+RoundingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+RoundingTests.swift"; sourceTree = "<group>"; };
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 = "<group>"; };
EFA4C66320864F9C008C4DD8 /* UniversalMappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalMappable.swift; sourceTree = "<group>"; };
EFA4C669208650B4008C4DD8 /* UniversalMappable+ImmutableMappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UniversalMappable+ImmutableMappable.swift"; sourceTree = "<group>"; };
EFA4C66E20865126008C4DD8 /* UniversalMappable+SwiftStandard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UniversalMappable+SwiftStandard.swift"; sourceTree = "<group>"; };
EFA4C6732086514A008C4DD8 /* UniversalMappable+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UniversalMappable+Extensions.swift"; sourceTree = "<group>"; };
EFBE57CF1EC35EF20040E00A /* Array+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Extensions.swift"; sourceTree = "<group>"; };
EFBE57DA1EC361620040E00A /* UIView+Layout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Layout.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -932,6 +934,7 @@
isa = PBXGroup;
children = (
671461D31EB3396E00EAB194 /* NetworkService.swift */,
B84CB06C20B8325D0090DB91 /* SessionManager.swift */,
);
path = Services;
sourceTree = "<group>";
@ -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 = "<group>";
@ -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 = "<group>";
@ -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 = "<group>";
};
B85B768520B1CF4C00F837C4 /* Codable */ = {
isa = PBXGroup;
children = (
B84CB07720B872AD0090DB91 /* Decodable+Extensions.swift */,
B85B768620B1CF6700F837C4 /* Encodable+Extensions.swift */,
);
path = Codable;
sourceTree = "<group>";
};
C90516DF61394D92FF071C0C /* Frameworks */ = {
isa = PBXGroup;
children = (
@ -1838,16 +1851,6 @@
path = NetworkService;
sourceTree = "<group>";
};
EFA4C6682086508B008C4DD8 /* UniversalMappable */ = {
isa = PBXGroup;
children = (
EFA4C6732086514A008C4DD8 /* UniversalMappable+Extensions.swift */,
EFA4C669208650B4008C4DD8 /* UniversalMappable+ImmutableMappable.swift */,
EFA4C66E20865126008C4DD8 /* UniversalMappable+SwiftStandard.swift */,
);
path = UniversalMappable;
sourceTree = "<group>";
};
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;
};

View File

@ -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'

View File

@ -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

View File

@ -210,7 +210,7 @@ final public class PaginationWrapper<Cursor: ResettableRxDataSourceCursor, Deleg
self.wrappedView.footerView = retryButton
let newContentOffset = CGPoint(x: 0, y: scrollView.contentOffset.y + retryButtonHeight)
scrollView.setContentOffset(newContentOffset, animated: true)
}
}

View File

@ -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.
@ -37,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<Int> {
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<T: ObservableMappable>(with parameters: ApiRequestParameters)
-> Observable<(response: HTTPURLResponse, model: T)> where T.ModelType == T {
public func rxObservableRequest<T: ObservableMappable>(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<T: ImmutableMappable>(with parameters: ApiRequestParameters)
public func rxRequest<T: Decodable>(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)
}

View File

@ -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<Int>
/// Dispatch Queue on which mapping is performed
public let mappingQueue: DispatchQueue
public init(configuration: URLSessionConfiguration,
serverTrustPolicyManager: ServerTrustPolicyManager,
acceptableStatusCodes: Set<Int>,
mappingQueue: DispatchQueue) {
self.acceptableStatusCodes = acceptableStatusCodes
self.mappingQueue = mappingQueue
super.init(configuration: configuration, serverTrustPolicyManager: serverTrustPolicyManager)
}
public init?(session: URLSession,
delegate: SessionDelegate,
serverTrustPolicyManager: ServerTrustPolicyManager,
acceptableStatusCodes: Set<Int>,
mappingQueue: DispatchQueue) {
self.acceptableStatusCodes = acceptableStatusCodes
self.mappingQueue = mappingQueue
super.init(session: session, delegate: delegate, serverTrustPolicyManager: serverTrustPolicyManager)
}
}

View File

@ -28,5 +28,5 @@ import Foundation
public enum LeadKitError: Error {
case failedToCastValue(expectedType: Any.Type, givenType: Any.Type)
case failedToDecode(reason: String)
}

View File

@ -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<Int> = Base.defaultAcceptableStatusCodes)
-> Observable<DataRequest> {
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<T: ImmutableMappable>(requestParameters: ApiRequestParameters,
mappingQueue: DispatchQueue = .global(),
acceptableStatusCodes: Set<Int> = 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<T: ImmutableMappable>(requestParameters: ApiRequestParameters,
mappingQueue: DispatchQueue = .global(),
acceptableStatusCodes: Set<Int> = 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<T>(requestParameters: ApiRequestParameters,
mappingQueue: DispatchQueue = .global(),
acceptableStatusCodes: Set<Int> = 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<T: ObservableMappable>(requestParameters: ApiRequestParameters,
mappingQueue: DispatchQueue = .global(),
acceptableStatusCodes: Set<Int> = 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<T: ObservableMappable>(requestParameters: ApiRequestParameters,
mappingQueue: DispatchQueue = .global(),
acceptableStatusCodes: Set<Int> = Base.defaultAcceptableStatusCodes)
-> Observable<(response: HTTPURLResponse, models: [T])> where T.ModelType == T {
return apiRequest(requestParameters: requestParameters, acceptableStatusCodes: acceptableStatusCodes)
.flatMap { $0.rx.observableApiResponse(mappingQueue: mappingQueue) }
}
}

View File

@ -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<T: ImmutableMappable>(mappingQueue: DispatchQueue = .global())
func apiResponse<T: Decodable>(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<T: ImmutableMappable>(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<T>().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<T>(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<T: ObservableMappable>(mappingQueue: DispatchQueue = .global())
-> Observable<(response: HTTPURLResponse, model: T)> where T.ModelType == T {
func observableApiResponse<T: ObservableMappable>(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<T: ObservableMappable>(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<ServerResponse> {
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<R>(_ transform: @escaping (E) throws -> Observable<R>) -> Observable<R> {
return flatMap { response -> Observable<R> in
return flatMap { response, result -> Observable<R> 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)
}
}
}

View File

@ -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<DataRequest> {
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<T: Decodable>(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<T: ObservableMappable>(requestParameters: ApiRequestParameters,
decoder: JSONDecoder)
-> Observable<(response: HTTPURLResponse, model: T)> {
return apiRequest(requestParameters: requestParameters)
.flatMap { $0.rx.observableApiResponse(mappingQueue: self.base.mappingQueue, decoder: decoder) }
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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<DateInRegion, String> {
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<DateInRegion, String> {
return shared.mappingTransform(with: format)
}
}

View File

@ -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<ModelType>
static func create(from jsonObject: Any, with decoder: JSONDecoder) -> Observable<Self>
}

View File

@ -39,21 +39,18 @@ public struct NetworkServiceConfiguration {
/// Server trust policies.
public var serverTrustPolicies: [String: ServerTrustPolicy]
/// Acceptable status codes for validation
public var acceptableStatusCodes: Set<Int> = 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.

View File

@ -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<Album> {
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)
}
}

View File

@ -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<AlbumContainer> {
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)
}
}
}

View File

@ -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<Post> {
return Observable.deferredJust {
let data = try JSONSerialization.data(withJSONObject: jsonObject, options: [])
return try decoder.decode(Post.self, from: data)
}
}
}
extension Post: Equatable {

View File

@ -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)
}
}
}