๐ง. RxSwift + Moya + HandyJSON + Plugins.๐๐๐
English | ็ฎไฝไธญๆ
This is a set of infrastructure based on RxSwift + Moya
This module is based on the Moya encapsulated network API architecture.
- Mainly divided into 3 parts:
- NetworkConfig: Set the configuration information at the beginning of the program.
- baseURL: Root path address to base URL.
- baseParameters: Default basic parameters, like: userID, token, etc.
- baseMethod: Default request method type.
- updateBaseParametersWithValue: Update default base parameter value.
- RxMoyaProvider: Add responsiveness to network requests, returning
Single
sequence. - NetworkUtil: Network related functions
- defaultPlugin: Add default plugin.
- transformAPISingleJSON: Transforms a
Single
sequence object. - handyConfigurationPlugin: Handles configuration plugins.
- PluginSubType: Inherit and replace the Moya plug-in protocol to facilitate subsequent expansion.
- configuration: After setting the network configuration information, before starting to prepare the request, this method can be used in scenarios such as key invalidation, re-acquiring the key and then automatically re-requesting the network.
- lastNever: When the last network response is returned, this method can be used in scenarios such as key failure to re-obtain the key and then automatically re-request the network.
- NetworkAPI: Add protocol attributes and encapsulate basic network requests based on TargetType.
- ip: Root path address to base URL.
- parameters: Request parameters.
- plugins: Set network plugins.
- stubBehavior: Whether to take the test data.
- request: Network request method and return a Single sequence object.
- NetworkAPIOO: OOP converter, MVP to OOP, convenient for friends who are used to OC thinking
- cdy_ip: Root path address to base URL.
- cdy_path: Request path.
- cdy_parameters: Request parameters.
- cdy_plugins: Set network plugins.
- cdy_testJSON: Network testing json string.
- cdy_testTime: Network test data return time, the default is half a second.
- cdy_HTTPRequest: Network request method and return a Single sequence object.
- NetworkX: extension function methods etc.
- toJSON: to JSON string.
- toDictionary: JSON string to dictionary.
- +=: Dictionary concatenation.
- NetworkConfig: Set the configuration information at the beginning of the program.
๐ท - OO Example 1:
class OOViewModel: NSObject {
let disposeBag = DisposeBag()
let data = PublishRelay<String>()
func loadData() {
var api = NetworkAPIOO.init()
api.cdy_ip = NetworkConfig.baseURL
api.cdy_path = "/ip"
api.cdy_method = .get
api.cdy_plugins = [NetworkLoadingPlugin.init()]
api.cdy_HTTPRequest()
.asObservable()
.compactMap{ (($0 as! NSDictionary)["origin"] as? String) }
.bind(to: data)
.disposed(by: disposeBag)
}
}
๐ท - MVP 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 the loading animation plugin
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 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)
.delay(.seconds(1), scheduler: MainScheduler.instance)
.asDriver(onErrorJustReturn: [])
}
}
๐ท - Chain Example 4:
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 thrown
}
func requestData(_ ip: String) -> Observable<NSDictionary> {
return ChainAPI.test2(ip).request()
.asObservable()
.map { ($0 as! NSDictionary) }
.catchAndReturn(["data": "nil"])
}
}
๐ท - Batch Example 5:
class BatchViewModel: NSObject {
let disposeBag = DisposeBag()
let data = PublishRelay<NSDictionary>()
/// Configure loading animation plugin
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] (data1, data2, data3) in
guard var data1 = data1 as? Dictionary<String, Any>,
let data2 = data2 as? Dictionary<String, Any>,
let data3 = data3 as? Dictionary<String, Any> else {
return
}
data1 += data2
data1 += data3
self?.data.accept(data1)
}, onError: {
print("Network Failed: \($0)")
}).disposed(by: disposeBag)
}
}
This module is mainly based on moya package network related plug-ins
- At present, 4 plug-ins have been packaged for you to use:
๐ - Simple to use, implement the protocol method in the API protocol, and then add the plugin to it:
var plugins: APIPlugins {
let cache = NetworkCachePlugin(cacheType: .networkElseCache)
let loading = NetworkLoadingPlugin.init(delayHideHUD: 0.5)
return [loading, cache]
}
This module is based on HandyJSON
package network data parsing
- Roughly divided into the following 3 parts:
- HandyDataModel: Network outer data model
- HandyJSONError: Parse error related
- RxHandyJSON: HandyJSON data parsing, currently provides two parsing solutions
- Option 1: Combine
HandyDataModel
model to parse out data. - Option 2: Parse the data of the specified key according to
keyPath
, the precondition is that the json data source must be in the form of a dictionary.
- Option 1: Combine
๐ท - Example of use in conjunction with the network part:
func request(_ count: Int) -> Driver<[CacheModel]> {
CacheAPI.cache(count).request()
.asObservable()
.mapHandyJSON(HandyDataModel<[CacheModel]>.self)
.compactMap { $0.data }
.observe(on: MainScheduler.instance)
.delay(.seconds(1), scheduler: MainScheduler.instance)
.asDriver(onErrorJustReturn: [])
}
Ex: Import Network Architecture API
- pod 'RxNetworks/MoyaNetwork'
Ex: Import Model Anslysis
- pod 'RxNetworks/HandyJSON'
Ex: Import loading animation plugin
- pod 'RxNetworks/MoyaPlugins/Loading'
The general process is almost like this, the Demo is also written in great detail, you can check it out for yourself.๐ท
Tip: If you find it helpful, please help me with a star. If you have any questions or needs, you can also issue.
Thanks.๐
- ๐ท E-mail address: [email protected] ๐ท
- ๐ธ GitHub address: yangKJ ๐ธ
RxNetworks is available under the MIT license. See the LICENSE file for more info.