implement concurrent mapping
This commit is contained in:
parent
1f9036df7d
commit
c2802a42f6
|
|
@ -11,6 +11,9 @@
|
|||
78011AB31D48B53600EA16A2 /* ApiRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78011AB21D48B53600EA16A2 /* ApiRequestParameters.swift */; };
|
||||
780D23431DA412470084620D /* CGImage+Alpha.swift in Sources */ = {isa = PBXBuildFile; fileRef = 780D23421DA412470084620D /* CGImage+Alpha.swift */; };
|
||||
780D23461DA416F80084620D /* CGContext+Initializers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 780D23451DA416F80084620D /* CGContext+Initializers.swift */; };
|
||||
780F56C71E0D7608004530B6 /* ResultOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 780F56C61E0D7608004530B6 /* ResultOperation.swift */; };
|
||||
780F56CA1E0D76B8004530B6 /* Sequence+ConcurrentMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 780F56C91E0D76B8004530B6 /* Sequence+ConcurrentMap.swift */; };
|
||||
780F56CC1E0D7ACA004530B6 /* ObservableMappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 780F56CB1E0D7ACA004530B6 /* ObservableMappable.swift */; };
|
||||
7827C9341DE4ADB2009DA4E6 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7827C92E1DE4ADB2009DA4E6 /* Alamofire.framework */; };
|
||||
7827C9351DE4ADB2009DA4E6 /* CocoaLumberjack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7827C92F1DE4ADB2009DA4E6 /* CocoaLumberjack.framework */; };
|
||||
7827C9361DE4ADB2009DA4E6 /* ObjectMapper.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7827C9301DE4ADB2009DA4E6 /* ObjectMapper.framework */; };
|
||||
|
|
@ -22,6 +25,8 @@
|
|||
7845A15A1E0BCD9A00B527BB /* KeyboardNotificationValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7845A1591E0BCD9A00B527BB /* KeyboardNotificationValues.swift */; };
|
||||
786D78E81D53C378006B2CEA /* AlamofireRequest+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 786D78E71D53C378006B2CEA /* AlamofireRequest+Extensions.swift */; };
|
||||
786D78EC1D53C46E006B2CEA /* AlamofireManager+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 786D78EB1D53C46E006B2CEA /* AlamofireManager+Extensions.swift */; };
|
||||
7873D14F1E1127BC001816EB /* LeadKitError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7873D14E1E1127BC001816EB /* LeadKitError.swift */; };
|
||||
7873D1511E112B0D001816EB /* Any+Cast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7873D1501E112B0D001816EB /* Any+Cast.swift */; };
|
||||
78753E241DE58A5D006BC0FB /* CursorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78753E231DE58A5D006BC0FB /* CursorError.swift */; };
|
||||
78753E2C1DE58BF9006BC0FB /* StaticCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78753E2B1DE58BF9006BC0FB /* StaticCursor.swift */; };
|
||||
78753E2E1DE58DBA006BC0FB /* FixedPageCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78753E2D1DE58DBA006BC0FB /* FixedPageCursor.swift */; };
|
||||
|
|
@ -29,6 +34,7 @@
|
|||
787682FA1CAD40C300532AB3 /* StaticEstimatedViewHeightProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 787682F91CAD40C200532AB3 /* StaticEstimatedViewHeightProtocol.swift */; };
|
||||
787783631CA03CA0001CDC9B /* IndexPath+ImmutableIndexPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 787783621CA03CA0001CDC9B /* IndexPath+ImmutableIndexPath.swift */; };
|
||||
787783671CA04D4A001CDC9B /* String+SizeCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 787783661CA04D4A001CDC9B /* String+SizeCalculation.swift */; };
|
||||
787D874A1E10E1A400D6015C /* ImmutableMappable+ObservableMappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 787D87491E10E1A400D6015C /* ImmutableMappable+ObservableMappable.swift */; };
|
||||
7884DB9C1DC1439200E52A63 /* UserDefaults+MappableDataTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884DB9B1DC1439200E52A63 /* UserDefaults+MappableDataTypes.swift */; };
|
||||
788EC15A1CF64528009CFB6B /* UIStoryboard+InstantiateViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 788EC1591CF64528009CFB6B /* UIStoryboard+InstantiateViewController.swift */; };
|
||||
789CC6081DE5835600F789D3 /* CursorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 789CC6071DE5835600F789D3 /* CursorType.swift */; };
|
||||
|
|
@ -87,6 +93,9 @@
|
|||
78011AB21D48B53600EA16A2 /* ApiRequestParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApiRequestParameters.swift; sourceTree = "<group>"; };
|
||||
780D23421DA412470084620D /* CGImage+Alpha.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGImage+Alpha.swift"; sourceTree = "<group>"; };
|
||||
780D23451DA416F80084620D /* CGContext+Initializers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGContext+Initializers.swift"; sourceTree = "<group>"; };
|
||||
780F56C61E0D7608004530B6 /* ResultOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultOperation.swift; sourceTree = "<group>"; };
|
||||
780F56C91E0D76B8004530B6 /* Sequence+ConcurrentMap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Sequence+ConcurrentMap.swift"; sourceTree = "<group>"; };
|
||||
780F56CB1E0D7ACA004530B6 /* ObservableMappable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObservableMappable.swift; sourceTree = "<group>"; };
|
||||
7827C92E1DE4ADB2009DA4E6 /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = ../../../Carthage/Build/iOS/Alamofire.framework; sourceTree = "<group>"; };
|
||||
7827C92F1DE4ADB2009DA4E6 /* CocoaLumberjack.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CocoaLumberjack.framework; path = ../../../Carthage/Build/iOS/CocoaLumberjack.framework; sourceTree = "<group>"; };
|
||||
7827C9301DE4ADB2009DA4E6 /* ObjectMapper.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjectMapper.framework; path = ../../../Carthage/Build/iOS/ObjectMapper.framework; sourceTree = "<group>"; };
|
||||
|
|
@ -98,6 +107,8 @@
|
|||
7845A1591E0BCD9A00B527BB /* KeyboardNotificationValues.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardNotificationValues.swift; sourceTree = "<group>"; };
|
||||
786D78E71D53C378006B2CEA /* AlamofireRequest+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AlamofireRequest+Extensions.swift"; sourceTree = "<group>"; };
|
||||
786D78EB1D53C46E006B2CEA /* AlamofireManager+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AlamofireManager+Extensions.swift"; sourceTree = "<group>"; };
|
||||
7873D14E1E1127BC001816EB /* LeadKitError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LeadKitError.swift; sourceTree = "<group>"; };
|
||||
7873D1501E112B0D001816EB /* Any+Cast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Any+Cast.swift"; sourceTree = "<group>"; };
|
||||
78753E231DE58A5D006BC0FB /* CursorError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CursorError.swift; sourceTree = "<group>"; };
|
||||
78753E2B1DE58BF9006BC0FB /* StaticCursor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticCursor.swift; sourceTree = "<group>"; };
|
||||
78753E2D1DE58DBA006BC0FB /* FixedPageCursor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FixedPageCursor.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -105,6 +116,7 @@
|
|||
787682F91CAD40C200532AB3 /* StaticEstimatedViewHeightProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticEstimatedViewHeightProtocol.swift; sourceTree = "<group>"; };
|
||||
787783621CA03CA0001CDC9B /* IndexPath+ImmutableIndexPath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "IndexPath+ImmutableIndexPath.swift"; sourceTree = "<group>"; };
|
||||
787783661CA04D4A001CDC9B /* String+SizeCalculation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+SizeCalculation.swift"; sourceTree = "<group>"; };
|
||||
787D87491E10E1A400D6015C /* ImmutableMappable+ObservableMappable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ImmutableMappable+ObservableMappable.swift"; sourceTree = "<group>"; };
|
||||
7884DB9B1DC1439200E52A63 /* UserDefaults+MappableDataTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UserDefaults+MappableDataTypes.swift"; sourceTree = "<group>"; };
|
||||
788EC1591CF64528009CFB6B /* UIStoryboard+InstantiateViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStoryboard+InstantiateViewController.swift"; sourceTree = "<group>"; };
|
||||
789CC6071DE5835600F789D3 /* CursorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CursorType.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -195,6 +207,7 @@
|
|||
78753E231DE58A5D006BC0FB /* CursorError.swift */,
|
||||
789F5A131DFECD54004A3694 /* KeyboardNotificationValuesError.swift */,
|
||||
789F5A1F1DFECF9F004A3694 /* KeyboardNotification.swift */,
|
||||
7873D14E1E1127BC001816EB /* LeadKitError.swift */,
|
||||
);
|
||||
path = Enums;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -237,6 +250,22 @@
|
|||
path = CGContext;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
780F56C51E0D75F7004530B6 /* Operations */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
780F56C61E0D7608004530B6 /* ResultOperation.swift */,
|
||||
);
|
||||
path = Operations;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
780F56C81E0D76A5004530B6 /* Sequence */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
780F56C91E0D76B8004530B6 /* Sequence+ConcurrentMap.swift */,
|
||||
);
|
||||
path = Sequence;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
786D78E61D53C355006B2CEA /* Alamofire */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -273,6 +302,14 @@
|
|||
path = String;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
787D87481E10E19000D6015C /* ObjectMapper */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
787D87491E10E1A400D6015C /* ImmutableMappable+ObservableMappable.swift */,
|
||||
);
|
||||
path = ObjectMapper;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7884DB9A1DC1432B00E52A63 /* UserDefaults */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -329,6 +366,7 @@
|
|||
children = (
|
||||
78B0FC7B1C6B2BAE00358B64 /* Logging */,
|
||||
78753E2A1DE58BED006BC0FB /* Cursors */,
|
||||
780F56C51E0D75F7004530B6 /* Operations */,
|
||||
);
|
||||
path = Classes;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -423,6 +461,8 @@
|
|||
789CC6091DE584C000F789D3 /* CursorType */,
|
||||
789F5A0A1DFECB52004A3694 /* UIViewAnimationCurve */,
|
||||
789F5A1C1DFECF44004A3694 /* NotificationCenter */,
|
||||
780F56C81E0D76A5004530B6 /* Sequence */,
|
||||
787D87481E10E19000D6015C /* ObjectMapper */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -441,6 +481,7 @@
|
|||
7837F60E1CBCF5C0000D74C1 /* EstimatedViewHeightProtocol.swift */,
|
||||
783423691DB8D0E100A79643 /* StoryboardProtocol.swift */,
|
||||
789CC6071DE5835600F789D3 /* CursorType.swift */,
|
||||
780F56CB1E0D7ACA004530B6 /* ObservableMappable.swift */,
|
||||
);
|
||||
path = Protocols;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -457,6 +498,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
78D4B5491DA64EAB005B0764 /* Any+TypeName.swift */,
|
||||
7873D1501E112B0D001816EB /* Any+Cast.swift */,
|
||||
);
|
||||
path = Functions;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -668,6 +710,8 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
787D874A1E10E1A400D6015C /* ImmutableMappable+ObservableMappable.swift in Sources */,
|
||||
780F56CA1E0D76B8004530B6 /* Sequence+ConcurrentMap.swift in Sources */,
|
||||
7837F60F1CBCF5C0000D74C1 /* EstimatedViewHeightProtocol.swift in Sources */,
|
||||
78CFEE541C5C45E500F50370 /* UIView+LoadFromNib.swift in Sources */,
|
||||
78D4B5461DA64D49005B0764 /* UIViewController+DefaultStoryboardIdentifier.swift in Sources */,
|
||||
|
|
@ -683,13 +727,16 @@
|
|||
78CFEE571C5C45E500F50370 /* StaticNibNameProtocol.swift in Sources */,
|
||||
788EC15A1CF64528009CFB6B /* UIStoryboard+InstantiateViewController.swift in Sources */,
|
||||
787783671CA04D4A001CDC9B /* String+SizeCalculation.swift in Sources */,
|
||||
7873D1511E112B0D001816EB /* Any+Cast.swift in Sources */,
|
||||
78B036431DA4FEC90021D5CC /* CGImage+Transform.swift in Sources */,
|
||||
780F56C71E0D7608004530B6 /* ResultOperation.swift in Sources */,
|
||||
78011A641D47ABC500EA16A2 /* UIView+DefaultReuseIdentifier.swift in Sources */,
|
||||
786D78EC1D53C46E006B2CEA /* AlamofireManager+Extensions.swift in Sources */,
|
||||
78B0FC811C6B2CD500358B64 /* App.swift in Sources */,
|
||||
7845A15A1E0BCD9A00B527BB /* KeyboardNotificationValues.swift in Sources */,
|
||||
78B036491DA562C30021D5CC /* CGImage+Template.swift in Sources */,
|
||||
789F5A1E1DFECF5F004A3694 /* NotificationCenter+RxKeyboardExtensions.swift in Sources */,
|
||||
7873D14F1E1127BC001816EB /* LeadKitError.swift in Sources */,
|
||||
78753E301DE594B4006BC0FB /* MapCursor.swift in Sources */,
|
||||
780D23461DA416F80084620D /* CGContext+Initializers.swift in Sources */,
|
||||
95B39A861D9D51250057BD54 /* String+Localization.swift in Sources */,
|
||||
|
|
@ -705,6 +752,7 @@
|
|||
78CFEE5B1C5C45E500F50370 /* ViewModelProtocol.swift in Sources */,
|
||||
789F5A121DFECD11004A3694 /* KeyboardDidNotificationValues.swift in Sources */,
|
||||
EF5FB5691E0141610030E4BE /* UIView+Rotation.swift in Sources */,
|
||||
780F56CC1E0D7ACA004530B6 /* ObservableMappable.swift in Sources */,
|
||||
780D23431DA412470084620D /* CGImage+Alpha.swift in Sources */,
|
||||
78CFEE5A1C5C45E500F50370 /* ViewHeightProtocol.swift in Sources */,
|
||||
787682FA1CAD40C300532AB3 /* StaticEstimatedViewHeightProtocol.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// ResultOperation.swift
|
||||
// LeadKit
|
||||
//
|
||||
// Created by Ivan Smolin on 23/12/16.
|
||||
// Copyright © 2016 Touch Instinct. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Subclass of Operation which contains result of executed operation
|
||||
public class ResultOperation<T>: Operation {
|
||||
|
||||
/// Result of executed operation or nil if operation is not finished yet or throw error
|
||||
public var result: T?
|
||||
|
||||
public typealias ExecutionClosure = () throws -> T
|
||||
|
||||
private let executionClosure: ExecutionClosure
|
||||
|
||||
public init(executionClosure: @escaping ExecutionClosure) {
|
||||
self.executionClosure = executionClosure
|
||||
}
|
||||
|
||||
override public func main() {
|
||||
result = try? executionClosure()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// LeadKitError.swift
|
||||
// LeadKit
|
||||
//
|
||||
// Created by Ivan Smolin on 26/12/16.
|
||||
// Copyright © 2016 Touch Instinct. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Enum which represents common errors in LeadKit framework
|
||||
///
|
||||
/// - failedToCastValue: attampt to cast was failed
|
||||
public enum LeadKitError: Error {
|
||||
|
||||
case failedToCastValue(expectedType: Any.Type, givenType: Any.Type)
|
||||
|
||||
}
|
||||
|
|
@ -11,15 +11,12 @@ import RxSwift
|
|||
import RxAlamofire
|
||||
import ObjectMapper
|
||||
|
||||
public extension Alamofire.SessionManager {
|
||||
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
|
||||
*/
|
||||
/// 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 RxAlamofire.request(requestParameters.method,
|
||||
requestParameters.url,
|
||||
|
|
@ -28,15 +25,26 @@ public extension Alamofire.SessionManager {
|
|||
headers: requestParameters.headers)
|
||||
}
|
||||
|
||||
/**
|
||||
method which executes request and serialize response into target object
|
||||
|
||||
- parameter requestParameters: api parameters to pass Alamofire
|
||||
|
||||
- returns: Observable with HTTP URL Response and target object
|
||||
*/
|
||||
/// Method which executes request and serialize response into target object
|
||||
///
|
||||
/// - Parameter requestParameters: api parameters to pass Alamofire
|
||||
/// - Returns: Observable with HTTP URL Response and target object
|
||||
func responseModel<T: ImmutableMappable>(requestParameters: ApiRequestParameters) -> Observable<(HTTPURLResponse, T)> {
|
||||
return apiRequest(requestParameters: requestParameters).flatMap { $0.rx.apiResponse() }
|
||||
return apiRequest(requestParameters: requestParameters)
|
||||
.observeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
|
||||
.flatMap { $0.rx.apiResponse() }
|
||||
}
|
||||
|
||||
/// Method which executes request and serialize response into target object
|
||||
///
|
||||
/// - Parameter requestParameters: api parameters to pass Alamofire
|
||||
/// - Returns: Observable with HTTP URL Response and target object
|
||||
func responseObservableModel<T: ObservableMappable>(requestParameters: ApiRequestParameters) ->
|
||||
Observable<(HTTPURLResponse, T)> where T.ModelType == T {
|
||||
|
||||
return apiRequest(requestParameters: requestParameters)
|
||||
.observeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
|
||||
.flatMap { $0.rx.apiResponse() }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,28 +11,28 @@ import RxSwift
|
|||
import ObjectMapper
|
||||
import RxAlamofire
|
||||
|
||||
public enum ApiResponseMappingError: Error {
|
||||
|
||||
case incorrectValueType(message: String)
|
||||
|
||||
}
|
||||
|
||||
public extension Reactive where Base: DataRequest {
|
||||
|
||||
/**
|
||||
method which serialize response into target object
|
||||
|
||||
- returns: Observable with HTTP URL Response and target object
|
||||
*/
|
||||
/// Method which serialize response into target object
|
||||
///
|
||||
/// - Returns: Observable with HTTP URL Response and target object
|
||||
func apiResponse<T: ImmutableMappable>() -> Observable<(HTTPURLResponse, T)> {
|
||||
return responseJSON().map { resp, value in
|
||||
if let json = value as? [String: Any] {
|
||||
return (resp, try T(JSON: json))
|
||||
} else {
|
||||
let failureReason = "Value has incorrect type: \(type(of: value)), expected: [String: Any]"
|
||||
let json = try cast(value) as [String: Any]
|
||||
|
||||
throw ApiResponseMappingError.incorrectValueType(message: failureReason)
|
||||
}
|
||||
return (resp, try T(JSON: json))
|
||||
}
|
||||
}
|
||||
|
||||
/// Method which serialize response into target object
|
||||
///
|
||||
/// - Returns: Observable with HTTP URL Response and target object
|
||||
func apiResponse<T: ObservableMappable>() -> Observable<(HTTPURLResponse, T)> where T.ModelType == T {
|
||||
return responseJSON().flatMap { resp, value -> Observable<(HTTPURLResponse, T)> in
|
||||
let json = try cast(value) as [String: Any]
|
||||
|
||||
return try T.createFrom(map: Map(mappingType: .fromJSON, JSON: json))
|
||||
.map { (resp, $0) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// ImmutableMappable+ObservableMappable.swift
|
||||
// LeadKit
|
||||
//
|
||||
// Created by Ivan Smolin on 26/12/16.
|
||||
// Copyright © 2016 Touch Instinct. All rights reserved.
|
||||
//
|
||||
|
||||
import ObjectMapper
|
||||
import RxSwift
|
||||
|
||||
public extension ObservableMappable where Self: ImmutableMappable, ModelType == Self {
|
||||
|
||||
/// Default implementation of ObservableMappable protocol for ImmutableMappable protocol
|
||||
///
|
||||
/// - Parameter map: ObjectMapper.Map object
|
||||
/// - Returns: Observable with value of ModelType(map: ObjectMapper.Map)
|
||||
/// - Throws: error of ModelType(map: ObjectMapper.Map)
|
||||
static func createFrom(map: Map) throws -> Observable<Self> {
|
||||
return Observable.just(try ModelType(map: map))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// Sequence+ConcurrentMap.swift
|
||||
// LeadKit
|
||||
//
|
||||
// Created by Ivan Smolin on 23/12/16.
|
||||
// Copyright © 2016 Touch Instinct. All rights reserved.
|
||||
//
|
||||
|
||||
import RxSwift
|
||||
|
||||
public typealias CancelClosureType = () -> ()
|
||||
|
||||
public extension Sequence {
|
||||
|
||||
func concurrentMap<R>(transform: @escaping ((Iterator.Element) throws -> R),
|
||||
concurrentOperationCount: Int = ProcessInfo.processInfo.activeProcessorCount,
|
||||
completion: @escaping (([R]) -> ())) -> CancelClosureType {
|
||||
|
||||
let operationsCount = Swift.max(1, concurrentOperationCount)
|
||||
|
||||
let operationQueue = OperationQueue()
|
||||
operationQueue.maxConcurrentOperationCount = operationsCount
|
||||
|
||||
let array = Array(self)
|
||||
|
||||
let step = Int(ceil(Double(array.count) / Double(operationsCount)))
|
||||
let numberOfSlices = Int(ceil(Double(array.count) / Double(step)))
|
||||
|
||||
DispatchQueue.global().async {
|
||||
let operations: [ResultOperation<[R]>] = (0..<numberOfSlices).map {
|
||||
let start = $0 * step
|
||||
let end = Swift.min(start + step, array.count)
|
||||
|
||||
return ResultOperation { try array[start..<end].map(transform) }
|
||||
}
|
||||
|
||||
operationQueue.addOperations(operations, waitUntilFinished: true)
|
||||
|
||||
var results: [R] = [] // var is used for performance optimization
|
||||
|
||||
let operationsResults = operations.flatMap { $0.result }
|
||||
|
||||
for operationResult in operationsResults {
|
||||
results += operationResult
|
||||
}
|
||||
|
||||
completion(results)
|
||||
}
|
||||
|
||||
return {
|
||||
operationQueue.cancelAllOperations()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public extension Sequence {
|
||||
|
||||
func concurrentRxMap<R>(transform: @escaping ((Iterator.Element) throws -> R),
|
||||
concurrentOperationCount: Int = ProcessInfo.processInfo.activeProcessorCount) -> Observable<[R]> {
|
||||
|
||||
return Observable<[R]>.create { observer in
|
||||
let disposeHandler = self.concurrentMap(transform: transform,
|
||||
concurrentOperationCount: concurrentOperationCount) {
|
||||
observer.onNext($0)
|
||||
observer.onCompleted()
|
||||
}
|
||||
|
||||
return Disposables.create(with: disposeHandler)
|
||||
}
|
||||
}
|
||||
|
||||
func concurrentRxMap<R>(transform: @escaping ((Iterator.Element) throws -> R)) -> Observable<[R]> {
|
||||
|
||||
return Observable<[R]>.create { observer in
|
||||
let disposeHandler = self.concurrentMap(transform: transform) {
|
||||
observer.onNext($0)
|
||||
observer.onCompleted()
|
||||
}
|
||||
|
||||
return Disposables.create(with: disposeHandler)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -14,12 +14,10 @@ import RxSwift
|
|||
/// model or array of specified type from UserDefaults.
|
||||
///
|
||||
/// - noSuchValue: there is no such value for given key
|
||||
/// - wrongStoredValueType: the stored value type is unsuitable for performing mapping with it
|
||||
/// - unableToMap: the value cannot be mapped to given type for some reason
|
||||
public enum UserDefaultsError: Error {
|
||||
|
||||
case noSuchValue(key: String)
|
||||
case wrongStoredValueType(expected: Any.Type, received: Any.Type)
|
||||
case unableToMap(mappingError: Error)
|
||||
|
||||
}
|
||||
|
|
@ -33,11 +31,7 @@ public extension UserDefaults {
|
|||
throw UserDefaultsError.noSuchValue(key: key)
|
||||
}
|
||||
|
||||
guard let storedValue = objectForKey as? ST else {
|
||||
throw UserDefaultsError.wrongStoredValueType(expected: ST.self, received: type(of: objectForKey))
|
||||
}
|
||||
|
||||
return storedValue
|
||||
return try cast(objectForKey) as ST
|
||||
}
|
||||
|
||||
/// Returns the object with specified type associated with the first occurrence of the specified default.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// Any+Cast.swift
|
||||
// LeadKit
|
||||
//
|
||||
// Created by Ivan Smolin on 26/12/16.
|
||||
// Copyright © 2016 Touch Instinct. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Function which attempts to cast given value to specific type
|
||||
///
|
||||
/// - Parameter value: value to cast
|
||||
/// - Returns: value casted to specific type
|
||||
/// - Throws: LeadKitError.failedToCastValue cast fails
|
||||
public func cast<T>(_ value: Any?) throws -> T {
|
||||
guard let val = value as? T else {
|
||||
throw LeadKitError.failedToCastValue(expectedType: T.self, givenType: type(of: value))
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
|
@ -8,6 +8,10 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
/// Function which return string representation of type without ".Type" suffix
|
||||
///
|
||||
/// - Parameter type: a type
|
||||
/// - Returns: string representation of type without ".Type" suffix
|
||||
public func className<T>(of type: T) -> String {
|
||||
let clsName = String(describing: type(of: type))
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// ObservableMappable.swift
|
||||
// LeadKit
|
||||
//
|
||||
// Created by Ivan Smolin on 23/12/16.
|
||||
// Copyright © 2016 Touch Instinct. All rights reserved.
|
||||
//
|
||||
|
||||
import ObjectMapper
|
||||
import RxSwift
|
||||
|
||||
/// Protocol for concurrent model mapping
|
||||
public protocol ObservableMappable {
|
||||
|
||||
associatedtype ModelType
|
||||
|
||||
static func createFrom(map: Map) throws -> Observable<ModelType>
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue