Swift 4以éãæ°ããCodableãããã³ã«ã«ã¢ã¯ã»ã¹ã§ããããã«ãªããã¢ãã«ã®ãšã³ã³ãŒã/ãã³ãŒãã容æã«ãªããŸããã ç§ã®ãããžã§ã¯ãã«ã¯APIåŒã³åºãçšã®ã³ãŒãããããããããŸãããéå»1幎éãç¹°ãè¿ãã³ãŒããåé€ãããã«ãããŒããªã¯ãšã¹ããURLã¯ãšãªãã©ã¡ãŒã¿ãŒã«å¯ŸããŠãCodableã䜿çšããããšã§ããã®èšå€§ãªã³ãŒããéåžžã«è»œéã§ç°¡æœã§ã·ã³ãã«ãªãã®ã«æé©åããããã«å€ãã®äœæ¥ãè¡ã£ãŠããŸããã ç§ã®æèŠã§ã¯ããµãŒããŒãããªã¯ãšã¹ããéä¿¡ããã¬ã¹ãã³ã¹ã解æããããã®ããã€ãã®åªããã¯ã©ã¹ã§ããããšãå€æããŸããã ãŸãã䟿å©ãªãã¡ã€ã«æ§é ããããŸããããã¯ããªã¯ãšã¹ãã®åã°ã«ãŒãã®ã³ã³ãããŒã©ãŒã§ãããããã¯ãšã³ãã§Vapor 3ã䜿çšãããšãã«æ £ããŸããã æ°æ¥åãç§ã¯ãã¹ãŠã®éçºãå¥ã®ã©ã€ãã©ãªã§éžæããCodyFireãšããååãä»ããŸããã ãã®èšäºã§åœŒå¥³ã«ã€ããŠã話ãããããšæããŸãã
å 責äºé
CodyFireã¯Alamofireã«åºã¥ããŠããŸãããAlamofireã®åãªãã©ãããŒã§ã¯ãªããiOSã®REST APIãæäœããããã®ã·ã¹ãã å šäœã®ã¢ãããŒãã§ãã ã ãããAlamofireãCodableãµããŒãããã5çªç®ã®ããŒãžã§ã³ãèŠãŠããã®ã§ã¯ãªãããšå¿é ããŸããã ç§ã®åµé ç©ã殺ãããšã¯ãããŸããã
åæå
é ãããå°ãå§ããŸããããã€ãŸãã3å°ã®ãµãŒããŒãããããšãå€ããšããäºå®ã§ãã
dev-éçºçšãXcodeããå§ãããã®
ã¹ããŒãž -ãªãªãŒã¹åã®ãã¹ãçšãéåžžã¯TestFlightãŸãã¯InHouseã§
prod-çç£ãAppStoreåã
ãã¡ãããå€ãã®iOSéçºè ã¯ã ç°å¢å€æ°ã®ååšãšXcodeã®ã¹ã¿ãŒãã¢ããã¹ããŒã ã«ã€ããŠç¥ã£ãŠããŸãããç§ã®ïŒ8幎以äžã®ïŒãã©ã¯ãã£ã¹ã§ã¯ãéçºè ã®90ïŒ ããã¹ãäžãŸãã¯ãã«ãåã«é©åãªãµãŒããŒãäžå®ã®æéã§èšè¿°ããŠããŸããç§ã¯ãããæ£ããè¡ãæ¹æ³ã®è¯ãäŸã瀺ãããšã«ãã£ãŠä¿®æ£ããããã®ã
CodyFireã¯ããã©ã«ãã§ãã¢ããªã±ãŒã·ã§ã³ãçŸåšã©ã®ç°å¢ã§å®è¡ãããŠããããèªåçã«å€æããéåžžã«åçŽã«ããŸãã
#if DEBUG //DEV environment #else if Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt" { //TESTFLIGHT environment } else { //APPSTORE environment } #endif
ããã¯ãã¡ããå éšã§ãããAppDelegateã®ãããžã§ã¯ãã§ã¯3ã€ã®URLãç»é²ããã ãã§æžã¿ãŸãã
import CodyFire @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { let dev = CodyFireEnvironment(baseURL: "http://localhost:8080") let testFlight = CodyFireEnvironment(baseURL: "https://stage.myapi.com") let appStore = CodyFireEnvironment(baseURL: "https://api.myapi.com") CodyFire.shared.configureEnvironments(dev: dev, testFlight: testFlight, appStore: appStore) return true } }
ãããŠããããåãã§ãä»ã«äœãããããšã¯ã§ããŸããã
ããããå®éã«ã¯ãXcodeã§devãstageãprodãµãŒããŒããã¹ãããå¿ èŠãããå Žåãå€ããããã¹ã¿ãŒãã¢ããã¹ããŒã ã䜿çšããããšããå§ãããŸãã
ãã³ãïŒ [ã¹ããŒã ã®ç®¡ç]ã»ã¯ã·ã§ã³ã§ããããžã§ã¯ãã®ãã¹ãŠã®éçºè ã䜿çšã§ããããã«ãåã¹ããŒã ã®[å ±æ]ãã§ãã¯ããã¯ã¹ããªã³ã«ããããšãå¿ããªãã§ãã ããã
åã¹ããŒã ã§ã¯ãdevãtestFlightãappStoreã®3ã€ã®å€ãåãããšãã§ããç°å¢å€æ°ãenvããèšè¿°ããå¿ èŠããããŸãã
ãŸãããããã®ã¹ããŒã ãCodyFireã§äœ¿çšããã«ã¯ã CodyFireãåæåããåŸã«AppDelegate.didFinishLaunchingWithOptionsã«æ¬¡ã®ã³ãŒããè¿œå ããå¿ èŠããããŸã
CodyFire.shared.setupEnvByProjectScheme()
ããã«ãå€ãã®å Žåããããžã§ã¯ãã®ãã¹ãŸãã¯ãã¹ã¿ãŒãLoginScreenã®ã©ããã§ãµãŒããŒããªã³ã¶ãã©ã€ã§åãæ¿ããããã«èŠæ±ããå ŽåããããŸãã CodyFireã䜿çšãããšãç°å¢ãå€æŽããŠãµãŒããŒã1è¡ã§åãæ¿ããããšã§ããããç°¡åã«å®è£ ã§ããŸãã
CodyFire.shared.environmentMode = .appStore
ããã¯ãã¢ããªã±ãŒã·ã§ã³ãåèµ·åããããŸã§æ©èœããŸããèµ·ååŸã«ä¿åããå Žåã¯ãå€ãUserDefaultsã«ä¿åãã AppDelegateã§ã¢ããªã±ãŒã·ã§ã³ãèµ·åãããšãã«ãã§ãã¯ãè¡ããå¿ èŠãªç°å¢ã«åãæ¿ããŸãããã®éèŠãªç¹ã話ããŸãããç°å¢ã®åãæ¿ããçŸããè¡ããããããžã§ã¯ããããã«å¢ããããšãé¡ã£ãŠããŸãã åæã«ãã©ã€ãã©ãªã¯ãã§ã«åæåãããŠããŸãã
ãã¡ã€ã«æ§é ãšã³ã³ãããŒã©ãŒ
ããã§ããã¹ãŠã®APIåŒã³åºãã®ãã¡ã€ã«æ§é ã«å¯Ÿããç§ã®ããžã§ã³ã«ã€ããŠè©±ãããšãã§ããŸããããã¯CodyFireã®ã€ããªãã®ãŒãšåŒã°ããŸãã
ãããžã§ã¯ãã§æçµçã«ã©ã®ããã«èŠãããèŠãŠã¿ãŸããã
ãã¡ã€ã«ã®ãªã¹ããèŠãŠã¿ãŸãããã API.swiftããå§ããŸãããã
class API { typealias auth = AuthController typealias post = PostController }
ãã¹ãŠã®ã³ã³ãããŒã©ãŒãžã®ãªã³ã¯ã¯ããã«ãªã¹ããããŠããããã `API.controller.method`ãä»ããŠç°¡åã«åŒã³åºãããšãã§ããŸãã
class AuthController {}
API + Login.swift
extension AuthController { struct LoginResponse: Codable { var token: String } static func login(email: String, password: String) -> APIRequest<LoginResponse> { return APIRequest("login").method(.post) .basicAuth(email: email, password: password) .addCustomError(.notFound, "User not found") } }
ãã®ãã³ã¬ãŒã¿ã§ã¯ãAPIãåŒã³åºãé¢æ°ã宣èšããŸãã
-ãšã³ããã€ã³ããæå®
-HTTP POSTã¡ãœãã
-åºæ¬èªèšŒã«ã©ãããŒã䜿çš
-ãµãŒããŒããã®ç¹å®ã®å¿çã«å¿ èŠãªããã¹ãã宣èšããŸãïŒããã¯äŸ¿å©ã§ãïŒ
-ãããŠãããŒã¿ããã³ãŒããããã¢ãã«ã瀺ããŸã
äœãé ããããŸãŸã§ããïŒ
-å®å šãªãµãŒããŒURLãæå®ããå¿ èŠã¯ãããŸããã ãã§ã«ã°ããŒãã«ã«èšå®ãããŠããŸã
-ãã¹ãŠãæ£åžžã§ããã°ã 200 OKãåãåãããšã瀺ãå¿ èŠã¯ãããŸããã§ãã
200 OKã¯ããã¹ãŠã®ãªã¯ãšã¹ãã«å¯ŸããŠCodyFireãæåŸ ããããã©ã«ãã®ã¹ããŒã¿ã¹ã³ãŒãã§ãããã®å ŽåãããŒã¿ããã³ãŒããããã³ãŒã«ããã¯ãåŒã³åºãããŸããããã«ã LoginScreenã®ã³ãŒãã®ã©ããã§ãåã«åŒã³åºãããšãã§ããŸã
API.auth.login(email: "test@mail.com", password: "qwerty").onError { error in switch error.code { case .notFound: print(error.description) //: User not found default: print(error.description) } }.onSuccess { token in //TODO: auth token print("Received auth token: "+ token) }
onErrorãšonSuccessã¯ãAPIRequestãè¿ãããšãã§ããã³ãŒã«ããã¯ã®ã»ãã®äžéšã«éããŸããããããã«ã€ããŠã¯åŸã§èª¬æããŸãã
å ¥åäŸã§ã¯ãè¿ãããããŒã¿ãèªåçã«ãã³ãŒããããå Žåã®ãªãã·ã§ã³ã®ã¿ãèæ ®ããŸããããèªåã§ãããå®è£ ã§ãããšèšãããšãã§ããããªãã¯æ£ããã§ãããã ãã®ãããäŸãšããŠç»é²ãã©ãŒã ã䜿çšããŠã¢ãã«ã§ããŒã¿ãéä¿¡ããå¯èœæ§ãèããŠã¿ãŸãããã
API + Signup.swift
extension AuthController { struct SignupRequest: JSONPayload { let email, password: String let firstName, lastName, mobileNumber: String init(email: String, password: String, firstName: String, lastName: String, mobileNumber: String) { self.email = email self.password = password self.firstName = firstName self.lastName = lastName self.mobileNumber = mobileNumber } } struct SignupResponse: Codable { let token: String } static func signup(_ request: SignupRequest) -> APIRequest<SignupResponse> { return APIRequest("signup", payload: request).method(.post) .addError(.conflict, "Account already exists") } }
ãã°ã€ã³ãšã¯ç°ãªããç»é²äžã«å€§éã®ããŒã¿ãéä¿¡ããŸãã
ãã®äŸã§ã¯ã JSONPayloadãããã³ã«ã«æºæ ããSignupRequestã¢ãã«ããããŸãïŒãããã£ãŠãCodyFireã¯ãã€ããŒãã¿ã€ããç解ããŸãïŒããã®ããããªã¯ãšã¹ãã®æ¬æã¯JSONã®åœ¢åŒã«ãªããŸãã x-www-form-urlencodedãå¿ èŠãªå Žåã¯ã FormURLEncodedPayloadã䜿çšããŸã ã
ãã®çµæããã€ããŒãã¢ãã«ãåãå ¥ããåçŽãªé¢æ°ãåŸãããŸã
API.auth.signup(request)
æåãããšãç¹å®ã®å¿çã¢ãã«ãè¿ãããŸãã
ã¯ãŒã«ã ãšæããŸãããïŒ
ãããããã«ãããŒãã®å Žåã¯ã©ãã§ããããïŒ
Postãäœæã§ããäŸãèŠãŠã¿ãŸãããã
æçš¿+ Create.swift
extension PostController { struct CreateRequest: MultipartPayload { var text: String var tags: [String] var images: [Attachment] var video: Data init (text: String, tags: [String], images: [Attachment], video: Data) { self.text = text self.tags = tags self.images = images self.video = video } } struct Post: Codable { let text: String let tags: [String] let linksToImages: [String] let linkToVideo: String } static func create(_ request: CreateRequest) -> APIRequest<CreateRequest> { return APIRequest("post", payload: request).method(.post) } }
ãã®ã³ãŒãã¯ãç»åãã¡ã€ã«ã®é åãš1ã€ã®ãããªãå«ããã«ãããŒããã©ãŒã ãéä¿¡ã§ããŸãã
ãã£ã¹ããããåŒã³åºãæ¹æ³ãèŠãŠã¿ãŸãããã Attachmentã«ã€ããŠã®æãèå³æ·±ãç¬éã§ãã
let videoData = FileManager.default.contents(atPath: "/path/to/video.mp4")! let imageAttachment = Attachment(data: UIImage(named: "cat")!.jpeg(.high)!, fileName: "cat.jpg", mimeType: .jpg) let payload = PostController.CreateRequest(text: "CodyFire is awesome", tags: ["codyfire", "awesome"], images: [imageAttachment], video: videoData) API.post.create(payload).onProgress { progress in print(" : \(progress)") }.onError { error in print(error.description) }.onSuccess { createdPost in print(" : \(createdPost)") }
æ·»ä»ãã¡ã€ã«ã¯ã ããŒã¿ã«å ããŠããã¡ã€ã«åãšãã®MimeTypeãéä¿¡ãããã¢ãã«ã§ãã
AlamofireãŸãã¯ããåºãã®URLRequestã䜿çšããŠSwiftãããã«ãããŒããã©ãŒã ãéä¿¡ããããšãããå Žåã¯ã CodyFireã®ã·ã³ãã«ããé«ãè©äŸ¡ããã§ãããã
ããã§ãGETåŒã³åºãã®ããã·ã³ãã«ã§ã¯ãŒã«ãªäŸãã§ããŸããã
æçš¿+ Get.swift
extension PostController { struct ListQuery: Codable { let offset, limit: Int init (offset: Int, limit: Int) { self.offset = offset self.limit = limit } } static func get(_ query: ListQuery? = nil) -> APIRequest<[Post]> { return APIRequest("post").query(query) } static func get(id: UUID) -> APIRequest<Post> { return APIRequest("post/" + id.uuidString) } }
æãç°¡åãªäŸã¯
API.post.get(id:)
onSuccessã§ã¯ ã Postã¢ãã«ãè¿ãããŸãã
ããèå³æ·±ãäŸã次ã«ç€ºããŸãã
API.post.get(PostController.ListQuery(offset: 0, limit: 100))
ListQueryã¢ãã«ãå ¥åãšããŠåãåãã
ã©ã®APIRequestãæçµçã«ãã©ãŒã ã®URLãã¹ã«å€æãããã
post?limit=0&offset=100
[Post]é åãonSuccessã«è¿ããŸãã
ãã¡ãããå€ãæ¹æ³ã§URLãã¹ãèšè¿°ã§ããŸãããä»ã§ã¯å®å šã«ã³ãŒãåã§ããããšãããã£ãŠããŸãã
æåŸã®ãªã¯ãšã¹ãäŸã¯DELETEã«ãªããŸã
æçš¿+ Delete.swift
extension PostController { static func delete(id: UUID) -> APIRequest<Nothing> { return APIRequest("post/" + id.uuidString) .method(.delete) .desiredStatusCode(.noContent) } }
2ã€ã®èå³æ·±ãç¹ããããŸãã
-æ»ãå€ã®åã¯APIRequestã§ããã空ã®Codableã¢ãã«ã§ãããžã§ããªãã¯åNothingãæå®ããŸãã
-204 NO CONTENTãåãåãããšãæ瀺çã«ç€ºãããã®å Žåã¯CodyFireã¯onSuccessã®ã¿ãåŒã³åºããŸãã
ViewControllerãããã®ãšã³ããã€ã³ããåŒã³åºãæ¹æ³ã¯ãã§ã«ç¥ã£ãŠããŸãã
ãã ãã2ã€ã®ãªãã·ã§ã³ããããŸãã1ã€ç®ã¯onSuccessã§ã2ã€ç®ã¯ãªãã§ãã 圌ãèŠãŸã
API.post.delete(id:).execute()
ã€ãŸãããªã¯ãšã¹ããæºããããŠãããã©ãããéèŠã§ãªãå Žåã¯ãããã«å¯ŸããŠ.executeïŒïŒãåŒã³åºãã ãã§ããããã§ãªãå Žåã¯ããã³ãã©ãŒã®onSuccess宣èšã®åŸã«éå§ãããŸãã
å©çšå¯èœãªæ©èœ
åãªã¯ãšã¹ãã®æ¿èª
http-headersã§åãªã¯ãšã¹ãAPIã«çœ²åããã«ã¯ãã°ããŒãã«ãã³ãã©ãŒã䜿çšãããŸããããã¯AppDelegateã®ã©ããã«èšå®ã§ããŸãã ããã«ãã¯ã©ã·ãã¯[StringïŒString]ãŸãã¯Codableã¢ãã«ã䜿çšããŠéžæã§ããŸãã
èªèšŒãã¢ã©ãŒã®äŸã
1.ã³ãŒãã£ã³ã°å¯èœïŒæšå¥šïŒ
CodyFire.shared.fillCodableHeaders = { struct Headers: Codable { //NOTE: nil, headers var Authorization: String? var anythingElse: String } return Headers(Authorization: nil, anythingElse: "hello") }
2.ã¯ã©ã·ãã¯[æååïŒæåå]
CodyFire.shared.fillHeaders = { guard let apiToken = LocalAuthStorage.savedToken else { return [:] } return ["Authorization": "Bearer \(apiToken)"] }
ãªã¯ãšã¹ãã«ããã€ãã®http-headerãéžæçã«è¿œå ããŸã
ããã¯ãAPIRequestã®äœææã«å®è¡ã§ããŸããããšãã°ã次ã®ãšããã§ãã
APIRequest("some/endpoint").headers(["someKey": "someValue"])
äžæ£ãªãªã¯ãšã¹ãã®åŠç
AppDelegateãªã©ã§ã°ããŒãã«ã«åŠçã§ããŸã
CodyFire.shared.unauthorizedHandler = { // WelcomeScreen }
ãŸãã¯åãªã¯ãšã¹ãã§ããŒã«ã«ã«
API.post.create(request).onNotAuthorized { // }
ãããã¯ãŒã¯ãå©çšã§ããªãå Žå
API.post.create(request). onNetworkUnavailable { // , , }
ãã以å€ã®å Žåã onErrorã§ãšã©ãŒ._notConnectedToInternetãçºçããŸã
ãªã¯ãšã¹ããå§ãŸãåã«äœããå§ãã
.onRequestStartedãèšå®ããŠãããŒããŒãªã©ã®è¡šç€ºãéå§ã§ããŸãã
ããã¯äŸ¿å©ãªå Žæã§ããã€ã³ã¿ãŒãããããªãå Žåã¯åŒã³åºããããããšãã°ããŒããŒã衚瀺ããããã«ç¡é§ã«è¡šç€ºãããå¿ èŠããªãããã§ãã
ãã°åºåãã°ããŒãã«ã«ç¡å¹/æå¹ã«ããæ¹æ³
CodyFire.shared.logLevel = .debug CodyFire.shared.logLevel = .error CodyFire.shared.logLevel = .info CodyFire.shared.logLevel = .off
åäžã®ãªã¯ãšã¹ãã®ãã°åºåãç¡å¹ã«ããæ¹æ³
.avoidLogError()
ç¬èªã®æ¹æ³ã§ãã°ãåŠçãã
CodyFire.shared.logHandler = { level, text in print(" CodyFire: " + text) }
ãµãŒããŒã®æåŸ ãããhttpå¿çã³ãŒããèšå®ããæ¹æ³
äžèšã§è¿°ã¹ãããã«ãããã©ã«ãã§ã¯ãCodyFireã¯200 OKãåä¿¡ããããšãæ³å®ããŠãããåä¿¡ããå ŽåãããŒã¿ã®è§£æãéå§ããŠonSuccessãåŒã³åºããŸã ã
ããããäºæ³ãããã³ãŒãã¯ãããšãã°201 CREATEDã®ããã«ã䟿å©ãªåæã®åœ¢åŒã§èšå®ã§ããŸãã
.desiredStatusCode(.created)
ãŸãã¯ãã«ã¹ã¿ã ã®äºæ³ã³ãŒããèšå®ããããšãã§ããŸã
.desiredStatusCode(.custom(777))
ãªã¯ãšã¹ãããã£ã³ã»ã«
.cancel()
.onCancellationãã³ãã©ãŒã宣èšããããšã§ããªã¯ãšã¹ãããã£ã³ã»ã«ãããŠããããšãããããŸã
.onCancellation { // }
ããã§ãªãå Žåã onErrorãçºçããŸã
ãªã¯ãšã¹ãã®ã¿ã€ã ã¢ãŠããèšå®ãã
.responseTimeout(30) // 30
ãã³ãã©ãŒã¯ã¿ã€ã ã¢ãŠãã€ãã³ãã§ãã³ã°ããããšããããŸã
. onTimeout { // }
ããã§ãªãå Žåã onErrorãçºçããŸã
ã€ã³ã¿ã©ã¯ãã£ããªè¿œå ã¿ã€ã ã¢ãŠãã®èšå®
ããã¯ç§ã®ãæ°ã«å ¥ãã®æ©èœã§ãã ç±³åœã®ãã顧客ã圌女ã«ã€ããŠå°ããŠããŸããã 圌ã¯ããã°ã€ã³ãã©ãŒã ãããŸãã«ãæ©ãæ©èœããããšã奜ãŸãªãã£ãã圌ã®æèŠã§ã¯ãããã¯èªèšŒã§ã¯ãªãåœç©ã§ãããã®ããã«èªç¶ã«èŠããªãã£ãã
ã¢ã€ãã¢ã¯ã圌ãé»åã¡ãŒã«/ãã¹ã¯ãŒãã®ãã§ãã¯ã2ç§ä»¥äžç¶ããããšã§ãã ãããŠã0.5ç§ããç¶ããªãå Žåã¯ãããã«1.5ç§ã¹ããŒããŠããonSuccessãåŒã³åºãå¿ èŠããããŸãã æ£ç¢ºã«2ç§ãŸãã¯2.5ç§ãããå Žåã¯ãããã«onSuccessãåŒã³åºããŸãã
.additionalTimeout(2) // 2
ã«ã¹ã¿ã æ¥ä»ãšã³ã³ãŒããŒ/ãã³ãŒããŒ
CodyFireã«ã¯ç¬èªã®DateCodingStrategyåæåãããã3ã€ã®å€ããããŸã
-secondsSince1970
-ããªç§
-ãã©ãŒãããæžã¿ïŒ_ customDateFormatterïŒDateFormatterïŒ
DateCodingStrategyã¯ããã³ãŒããšãšã³ã³ãŒãã®ããã«3ã€ã®æ¹æ³ã§å¥ã ã«èšå®ã§ããŸãã
-AppDelegateã§ã°ããŒãã«ã«
CodyFire.shared.dateEncodingStrategy = .secondsSince1970 let customDateFormatter = DateFormatter() CodyFire.shared.dateDecodingStrategy = .formatted(customDateFormatter)
-1ã€ã®ãªã¯ãšã¹ã
APIRequest("some/endpoint") .dateDecodingStrategy(.millisecondsSince1970) .dateEncodingStrategy(.secondsSince1970)
-ãŸãã¯ãã¢ãã«ããšã«åå¥ã«ãã¢ãã«ãCustomDateEncodingStrategyããã³/ãŸãã¯CustomDateDecodingStrategyãšäžèŽããå¿ èŠããããŸãã
struct SomePayload: JSONPayload, CustomDateEncodingStrategy, CustomDateDecodingStrategy { var dateEncodingStrategy: DateCodingStrategy var dateDecodingStrategy: DateCodingStrategy }
ãããžã§ã¯ãã«è¿œå ããæ¹æ³
ã©ã€ãã©ãªã¯ãMITã©ã€ã»ã³ã¹ã®äžã§GitHubã§å ¥æã§ããŸãã
çŸåšãã€ã³ã¹ããŒã«ã¯CocoaPodsããã®ã¿å©çšå¯èœã§ã
pod 'CodyFire'
CodyFireãä»ã®iOSéçºè ã«ãšã£ãŠæçšã§ãããéçºãç°¡çŽ åããäžè¬çã«äžçãå°ãè¯ããã人ã ãããããããããšãé¡ã£ãŠããŸãã
ãæéãããã ãããããšãããããŸãã
UPDïŒReactiveCocoaããã³RxSwiftãµããŒããè¿œå ãããŸãã
pod 'ReactiveCodyFire' # ReactiveCocoa pod 'RxCodyFire' # RxSwift # 'CodyFire',
ReactiveCocaã®APIRequestã«ã¯.signalProducerããããRxSwiftã®å Žåã¯.observableããããŸã
UPD2ïŒè€æ°ã®ãªã¯ãšã¹ããå®è¡ã§ããããã«ãªããŸãã
åã¯ãšãªã®çµæãååŸããããšãéèŠãªå Žåã¯ã .andïŒïŒã䜿çšããŸã
ãã®ã¢ãŒãã§ã¯ãå¯èœãªéãæ倧10åã®ãªã¯ãšã¹ããå®è¡ã§ãããããã¯å³å¯ã«æ¬¡ã ã«å®è¡ãããŸãã
API.employee.all() .and(API.office.all()) .and(API.car.all()) .and(API.event.all()) .and(API.post.all()) .onError { error in print(error.description) }.onSuccess { employees, offices, cars, events, posts in // !!! }
onRequestStartedãonNetworkUnavailableãonCancellationãonNotAuthorizedãonTimeoutã䜿çšã§ããŸãã
onProgress-ãŸã éçºäž
ã¯ãšãªã®çµæãæ°ã«ããªãå Žåã¯ã .flattenïŒïŒã䜿çšã§ããŸã
[API.employee.all(), API.office.all(), API.car.all()].flatten().onError { print(error.description) }.onSuccess { print("flatten finished!") }
ããããåæã«å®è¡ããã«ã¯ã .concurrentãè¿œå ããã ãã§ïŒbyïŒ3ïŒãããã«ãã3ã€ã®èŠæ±ãåæã«å®è¡ã§ããŸããä»»æã®æ°ãæå®ã§ããŸãã
倱æãããªã¯ãšã¹ããšã©ãŒãã¹ãããããã«ã¯ã .avoidCancelOnErrorïŒïŒãè¿œå ããŸã
é²æã確èªããã«ã¯ã .onProgressãè¿œå ããŸã
UPD3ïŒãªã¯ãšã¹ãããšã«åå¥ã®ãµãŒããŒãèšå®ã§ããããã«ãªããŸãã
å¿ èŠãªãµãŒããŒã¢ãã¬ã¹ãã©ããã«äœæããå¿ èŠããããŸããäŸãã°ããã®ãããª
let server1 = ServerURL(base: "https://server1.com", path: "v1") let server2 = ServerURL(base: "https://server2.com", path: "v1") let server3 = ServerURL(base: "https://server3.com")
ãããŠããšã³ããã€ã³ããæå®ããåã«ããªã¯ãšã¹ãã®åæåã§ããããçŽæ¥äœ¿çšã§ããŸã
APIRequest(server1, "endpoint", payload: payloadObject) APIRequest(server2, "endpoint", payload: payloadObject) APIRequest(server3, "endpoint", payload: payloadObject)
ãŸãã¯ããªã¯ãšã¹ããåæåããåŸã«ãµãŒããŒãæå®ã§ããŸã
APIRequest("endpoint", payload: payloadObject).serverURL(server1)