🧚. RxSwift + Moya + HandyJSON + Plugins.👒👒👒
English |Simplified Chinese
Build responsive data binding network API architecture based on RxSwift + Moya
MoyaNetwork
The module is based on the network API architecture encapsulated by Moya
- It is mainly divided into the following 8 parts:
- NetworkConfig : set the configuration information at the beginning of the program, which is universal
- addDebugging: whether to enable adding debugging plug-ins by default
- baseURL: root path address
- baseParameters: default basic parameters, such as userID, token, etc
- baseMethod: default request type
- updateBaseParametersWithValue: updates the default basic parameter data
- RxMoyaProvider : add a response to the network request and return the Observable sequence
- NetworkUtil : network correlation function
- defaultPlugin: add a default plug-in
- Transformapiobeservablejson: convert to an observable sequence JSON object
- handyConfigurationPlugin: handle configuration plug-ins
- PluginSubType : inherit and replace Moya plug-in protocol to facilitate subsequent extension
- Configuration: after setting the network configuration information and before preparing the request, this method can be used to throw data directly when the local cache exists without executing subsequent network requests
- lastNever: the return time of the last network response. This method can be used in scenarios such as key failure, re obtaining the key, and then automatically re requesting the network
- NetworkAPI : add protocol attributes and encapsulate basic network requests on the basis of TargetType
- ip: root path address
- Parameters: request parameters
- Plugins: array of plugins
- Stub behavior: whether to use test data
- retry: the number of retries when the request failed
- Request: a network request method that returns an observable sequence JSON object
- NetworkAPI+Ext : default implementation scheme of NetworkAPI protocol
- NetworkAPIOO : object oriented converter, protocol oriented mode to object-oriented, convenient for small partners accustomed to OC thinking
- cdy_ip: root path address
- cdy_path: request path
- cdy_parameters: request parameters
- cdy_plugins: plug-ins
- cdy_testJSON: test data
- cdy_testTime: return time of test data, half a second by default
- cdy_retry: the number of retries when the request failed
- cdy_HTTPRequest: network request method
- NetworkX : extension function method, etc
- toJSON: object to JSON string
- toDictionary: JSON string to dictionary
- +=: Dictionary splicing
- NetworkConfig : set the configuration information at the beginning of the program, which is universal
🎷 - Object oriented usage example 1:
class OOViewModel: NSObject { let disposeBag = DisposeBag() let data = PublishRelay<String>() func loadData() { var api = NetworkAPIOO.init() api.cdy_ip = "https://www.httpbin.org" api.cdy_path = "/ip" api.cdy_method = .get api.cdy_plugins = [NetworkLoadingPlugin.init()] api.cdy_retry = 3 api.cdy_HTTPRequest() .asObservable() .compactMap{ (($0 as! NSDictionary)["origin"] as? String) } .catchAndReturn("") .bind(to: data) .disposed(by: disposeBag) } }
🎷 - MVP usage example 2:
enum LoadingAPI { case test2(String) } extension LoadingAPI: NetworkAPI { var ip: APIHost { return NetworkConfig.baseURL } var path: String { return "/post" } var parameters: APIParameters? { switch self { case .test2(let string): return ["key": string] } } } class LoadingViewModel: NSObject { let disposeBag = DisposeBag() let data = PublishRelay<NSDictionary>() ///Configure and load animation plug-ins let APIProvider: MoyaProvider<MultiTarget> = { let configuration = URLSessionConfiguration.default configuration.headers = .default configuration.timeoutIntervalForRequest = 30 let session = Moya.Session(configuration: configuration, startRequestsImmediately: false) let loading = NetworkLoadingPlugin.init() return MoyaProvider<MultiTarget>(session: session, plugins: [loading]) }() func loadData() { APIProvider.rx.request(api: LoadingAPI.test2("666")) .asObservable() .subscribe { [weak self] (event) in if let dict = event.element as? NSDictionary { self?.data.accept(dict) } }.disposed(by: disposeBag) } }
🎷 - MVVM usage example 3:
class CacheViewModel: NSObject { let disposeBag = DisposeBag() struct Input { let count: Int } struct Output { let items: Driver<[CacheModel]> } func transform(input: Input) -> Output { let elements = BehaviorRelay<[CacheModel]>(value: []) let output = Output(items: elements.asDriver()) request(input.count) .asObservable() .bind(to: elements) .disposed(by: disposeBag) return output } } extension CacheViewModel { func request(_ count: Int) -> Driver<[CacheModel]> { CacheAPI.cache(count).request() .asObservable() .mapHandyJSON(HandyDataModel<[CacheModel]>.self) .compactMap { $0.data } .observe(on: MainScheduler.instance) // The result is returned in the main thread .delay(.seconds(1), scheduler: MainScheduler.instance) // Return after 1 second delay .asDriver(onErrorJustReturn: []) // Return null at wrong time } }
🎷 - Example 4 of chained request usage:
class ChainViewModel: NSObject { let disposeBag = DisposeBag() let data = PublishRelay<NSDictionary>() func chainLoad() { requestIP() .flatMapLatest(requestData) .subscribe(onNext: { [weak self] data in self?.data.accept(data) }, onError: { print("Network Failed: \($0)") }).disposed(by: disposeBag) } } extension ChainViewModel { func requestIP() -> Observable<String> { return ChainAPI.test.request() .asObservable() .map { ($0 as! NSDictionary)["origin"] as! String } .catchAndReturn("") // Exception throw } func requestData(_ ip: String) -> Observable<NSDictionary> { return ChainAPI.test2(ip).request() .asObservable() .map { ($0 as! NSDictionary) } .catchAndReturn(["data": "nil"]) } }
🎷 - Batch request usage example 5:
class BatchViewModel: NSObject { let disposeBag = DisposeBag() let data = PublishRelay<NSDictionary>() ///Configure and load animation plug-ins let APIProvider: MoyaProvider<MultiTarget> = { let configuration = URLSessionConfiguration.default configuration.headers = .default configuration.timeoutIntervalForRequest = 30 let session = Moya.Session(configuration: configuration, startRequestsImmediately: false) let loading = NetworkLoadingPlugin.init() return MoyaProvider<MultiTarget>(session: session, plugins: [loading]) }() func batchLoad() { Observable.zip( APIProvider.rx.request(api: BatchAPI.test).asObservable(), APIProvider.rx.request(api: BatchAPI.test2("666")).asObservable(), APIProvider.rx.request(api: BatchAPI.test3).asObservable() ).subscribe(onNext: { [weak self] in guard var data1 = $0 as? Dictionary<String, Any>, let data2 = $1 as? Dictionary<String, Any>, let data3 = $2 as? Dictionary<String, Any> else { return } data1 += data2 data1 += data3 self?.data.accept(data1) }, onError: { print("Network Failed: \($0)") }).disposed(by: disposeBag) } }
MoyaPlugins
This module mainly encapsulates network related plug-ins based on moya
- Six plug-ins have been packaged for your use:
🏠 - Simple to use, implement the protocol method in the API protocol, and then add the plug-in to it:
var plugins: APIPlugins { let cache = NetworkCachePlugin(cacheType: .networkElseCache) let loading = NetworkLoadingPlugin.init(delayHideHUD: 0.5) loading.changeHudCallback = { (hud) in hud.detailsLabel.textColor = UIColor.yellow } return [loading, cache] }
HandyJSON
This module encapsulates network data analysis based on HandyJSON
- It is roughly divided into the following three parts:
- HandyDataModel : network outer data model
- HandyJSONError : parsing error related
- RxHandyJSON : HandyJSON data parsing. At present, two parsing schemes are provided
- Scheme 1 - analyze the data in combination with the HandyDataModel model
- Scheme 2 - parse the data of the specified key according to the keyPath. The precondition is that the data source must be in dictionary form
🎷 - Use examples in combination with network parts:
func request(_ count: Int) -> Driver<[CacheModel]> { CacheAPI.cache(count).request() .asObservable() .mapHandyJSON(HandyDataModel<[CacheModel]>.self) .compactMap { $0.data } .observe(on: MainScheduler.instance) // The result is returned in the main thread .delay(.seconds(1), scheduler: MainScheduler.instance) // Return after 1 second delay .asDriver(onErrorJustReturn: []) // Return null at wrong time }
CocoaPods Install
Ex: Import network architecture API - pod 'RxNetworks/MoyaNetwork' Ex: Import data parsing - pod 'RxNetworks/HandyJSON' Ex: Import and load animation plug-ins - pod 'RxNetworks/MoyaPlugins/Loading'
Demo
The general process is almost like this. The Demo is also written in detail. You can go and have a look by yourself 🎷
Tip: if you feel helpful, please point a star ⭐…
thank you. 🎇
- There are relevant plug-ins in the following sequence, which will be added slowly
✌️