Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
iOSの通信処理を簡潔に書く
Search
PKPK-Carnage
December 25, 2018
Programming
320
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
iOSの通信処理を簡潔に書く
PKPK-Carnage
December 25, 2018
More Decks by PKPK-Carnage
See All by PKPK-Carnage
iOSアプリを堅牢にデザインするために知っておくべきたった1つのこと
pkpkcarnage
0
520
アプリへの導線の増やし方.pdf
pkpkcarnage
0
750
「シェア機能」について考えてみた
pkpkcarnage
0
120
リリースビルドでのみ起こる謎のバグに見舞われた話
pkpkcarnage
0
230
Any型をprotocolにキャストする時に 気をつけた方がいい話
pkpkcarnage
0
310
今日から使える! Optionalをいい感じに扱うtips
pkpkcarnage
0
1.3k
もっと早く教えて欲しかった画面遷移
pkpkcarnage
0
370
Other Decks in Programming
See All in Programming
act1-costs.pdf
sumedhbala
0
230
ローカルLLMでどこまでコードが書けるか -縮小版 / How much code can be written on a local LLM Shortened
kishida
2
190
1B+ /day規模のログを管理する技術
broadleaf
0
140
琵琶湖の水は止められてもNet--HTTPのリトライは止められない / You might be able to stop the water flow of Lake Biwa but you can't stop Net::HTTP retries
luccafort
PRO
0
330
【やさしく解説 設計編・中級 #6】良いアーキテクチャとは ~ 一本の登り道の、行き先 ~
panda728
PRO
0
160
これからAgentCoreを触る方へトレンドはGatewayです
har1101
6
490
ローカルLLMでどこまでコードが書けるか -拡張版 / How much code can be written on a local LLM Extended
kishida
12
4.8k
yield再入門 #phpcon
o0h
PRO
0
200
初めてのKubernetes 本番運用でハマった話
oku053
0
120
AIを活用したE2Eテスト実装効率化のあゆみ / ebisu-mobile-14-kotetu
kotetuco
0
170
関数型プログラミングのメリットって何だろう?
wanko_it
0
170
광주소프트웨어마이스터고등학교 DevFest 특강 - 바이브 코딩 시대에서 주니어 개발자로 살아남는 방법
utilforever
1
120
Featured
See All Featured
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
Darren the Foodie - Storyboard
khoart
PRO
3
3.4k
How STYLIGHT went responsive
nonsquared
100
6.2k
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
610
The Limits of Empathy - UXLibs8
cassininazir
1
480
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
340
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.7k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
570
My Coaching Mixtape
mlcsv
0
170
Technical Leadership for Architectural Decision Making
baasie
3
440
The Spectacular Lies of Maps
axbom
PRO
1
860
Deep Space Network (abreviated)
tonyrice
0
230
Transcript
iOSͰ௨৴ॲཧΛ؆ܿʹॻ͘ 2018/12/25 ΫϦϘονΛٹ͏ձɻ PKPK-Carnage
About me • iOSྺ2ͪΐͬͱ • খֶੜ͔ΒͣͬͱΞϝίϛ͕͖ • Qiita → @PKPK-Carnage
• Github → PKPK-Carnage • Twitter → @PKPK-Carnage
౦ژίϛίϯʹߦ͖ͬͯ·ͨ͠
౦ژίϛίϯʹߦ͖ͬͯ·ͨ͠
͜Ε͚ͩΞϝίϛ͕ਓؾʹͳͬͨͷʹɺ Ͳ͏ͯࣗ͠ҰਓͰίϛίϯʹ͍ΔΜͩɾɾɾ
None
Marvel APIͰΞϓϦΛ࡞Εɺ ΅ͬͪΛճආͰ͖ΔͷͰʂʁ
Marvel APIͬͯͳΜͩʁ • MarvelͷίϛοΫʹؔ͢ΔใΛऔಘͰ͖ΔWebAPI • ৄ͘͠Qiitaʹهࣄॻ͖·ͨ͠(એ)
௨৴ॲཧΛ࡞Δ • Swift4.2Λ༻ • ϑϨʔϜϫʔΫ(Alamofire)Λ༻ • CodableͰjsonΛύʔε͢Δ
௨৴ॲཧΛ࡞Δ • Swift4.2Λ༻ • ϑϨʔϜϫʔΫ(Alamofire)Λ༻ • CodableͰjsonΛύʔε͢Δ • ग़དྷΔ͚ͩ؆ܿʹॻ͘ʂ
ͱΓ͋͑ͣॻ͍ͯΈΔɻ import Alamofire class APIManager { static func request(urlString: String,
parameter: [String: Any], success: @escaping (Data) -> Void, failure: @escaping (Error) -> Void) { // ڞ௨URLΛ݁߹ let url = "https://gateway.marvel.com/v1/public/\(urlString)" // ௨৴Λߦ͏ Alamofire.request(url, parameters: parameter).responseData { response in switch response.result { case .success(let data): success(data) case .failure(let error): failure(error) } } } }
ͱΓ͋͑ͣॻ͍ͯΈΔɻ extension APIManager { // ΩϟϥΫλʔͷҰཡΛऔಘ͢ΔAPI static func characterList(parameter: CharacterListRequest,
success: @escaping (CharacterListResponse) -> Void, failure: @escaping (Error) -> Void) { self.request(urlString: "characters", parameter: parameter.dict, success: { data in do { let data = try JSONDecoder().decode(CharacterListResponse.self, from: data) success(data) } catch { failure(error) } }, failure: failure) } }
ͱΓ͋͑ͣॻ͍ͯΈΔɻ
ͱΓ͋͑ͣॻ͍ͯΈΔɻ extension APIManager { // ΩϟϥΫλʔͷҰཡΛऔಘ͢ΔAPI static func characterList(parameter: CharacterListRequest,
success: @escaping (CharacterListResponse) -> Void, failure: @escaping (Error) -> Void) { self.request(urlString: “characters", parameter: parameter.dict, success: { data in do { let data = try JSONDecoder().decode(CharacterListResponse.self, from: data) success(data) } catch { failure(error) } }, failure: failure) } }
ͱΓ͋͑ͣॻ͍ͯΈΔɻ 15 extension APIManager { // ίϛοΫͷҰཡΛऔಘ͢ΔAPI static func comicList(parameter:
ComicListRequest, success: @escaping (ComicListResponse) -> Void, failure: @escaping (Error) -> Void) { self.request(urlString: "comics", parameter: parameter.dict, success: { data in do { let data = try JSONDecoder().decode(ComicListResponse.self, from: data) success(data) } catch { failure(error) } }, failure: failure) } } extension APIManager { // ΠϕϯτͷҰཡΛऔಘ͢ΔAPI static func eventList(parameter: EventListRequest, success: @escaping (EventListResponse) -> Void, failure: @escaping (Error) -> Void) { extension APIManager { // ΩϟϥΫλʔͷҰཡΛऔಘ͢ΔAPI static func characterList(parameter: CharacterListRequest, success: @escaping (CharacterListResponse) -> Void, failure: @escaping (Error) -> Void) { self.request(urlString: “characters", parameter: parameter.dict, success: { data in do { let data = try JSONDecoder().decode(CharacterListResponse.self, from: data) success(data) } catch { failure(error) } }, failure: failure) } }
શવ؆ܿʹॻ͚ͯͳ͍
֤API͝ͱʹϝιουΛॻ͔ͣʹɺڞ௨Խ͠Α͏
enumͱprotocolΛ׆༻͢Δ
ProtocolΛ࡞͢Δ protocol APIType { var url: String { get }
var parameter: [String: Any] { get } } ֤API͝ͱʹඞཁͳϦΫΤετใΛऔಘ͢ΔͨΊͷProtocolΛ࡞͢Δ
ҎԼͷೋͭͷAPIͰenumΛ࡞ͬͯΈΔ
enumΛ࡞͢Δ struct APITypes { private static let baseURL = "http://gateway.marvel.com/v1/public/"
enum Character { case list(CharacterListRequest) case comics(CharacterComicListRequest) } }
enumΛ࡞͢Δ struct APITypes { private static let baseURL = "http://gateway.marvel.com/v1/public/"
enum Character: APIType { case list(CharacterListRequest) case comics(CharacterComicListRequest) var url: String { let characterURL = "characters" switch self { case .list: return APITypes.baseURL + characterURL case .comics(let request): return APITypes.baseURL + “\(characterURL)/\(request.id)/comics” } } var parameter: [String : Any] { switch self { case .list(let request): return request.dict case .comics(let request): return request.dict } } } }
࠷ॳ͜͏ͩͬͨڞ௨ϦΫΤετͷॲཧ͕ɾɾɾ import Alamofire class APIManager { static func request(urlString: String,
parameter: [String: Any], success: @escaping (Data) -> Void, failure: @escaping (Error) -> Void) { // ڞ௨URLΛ݁߹ let url = "https://gateway.marvel.com/v1/public/\(urlString)" // ௨৴Λߦ͏ Alamofire.request(url, parameters: parameter).responseData { response in switch response.result { case .success(let data): success(data) case .failure(let error): failure(error) } } } }
͜͏ͳΔ import Alamofire class APIManager { static func request(type: APIType,
success: @escaping (Data) -> Void, failure: @escaping (Error) -> Void) { // ௨৴Λߦ͏ Alamofire.request(type.url, parameters: type.parameter).responseData { response in switch response.result { case .success(let data): success(data) case .failure(let error): failure(error) } } } }
֤API͝ͱͷϝιου͕ɾɾɾ 25 extension APIManager { // ίϛοΫͷҰཡΛऔಘ͢ΔAPI static func comicList(parameter:
ComicListRequest, success: @escaping (ComicListResponse) -> Void, failure: @escaping (Error) -> Void) { self.request(urlString: "comics", parameter: parameter.dict, success: { data in do { let data = try JSONDecoder().decode(ComicListResponse.self, from: data) success(data) } catch { failure(error) } }, failure: failure) } } extension APIManager { // ΠϕϯτͷҰཡΛऔಘ͢ΔAPI static func eventList(parameter: EventListRequest, success: @escaping (EventListResponse) -> Void, extension APIManager { // ΩϟϥΫλʔͷҰཡΛऔಘ͢ΔAPI static func characterList(parameter: CharacterListRequest, success: @escaping (CharacterListResponse) -> Void, failure: @escaping (Error) -> Void) { self.request(urlString: “characters", parameter: parameter.dict, success: { data in do { let data = try JSONDecoder().decode(CharacterListResponse.self, from: data) success(data) } catch { failure(error) } }, failure: failure) } }
ඞཁແ͘ͳΔʂ
࣮ࡍʹAPIΛୟ͘ͱ͜Μͳײ͡ // ΩϟϥΫλʔͷҰཡΛऔಘ͢Δ func fetchCharacterListData(parameters: CharacterListRequest) { APIManager.request(type: APITypes.Character.list(parameters), success:
{ data in do { let response = try JSONDecoder().decode(CharacterListResponse.self, from: data) // ௨৴&σίʔυޭ࣌ͷॲཧ } catch { // σίʔυΤϥʔ࣌ͷॲཧ } }, failure: { error in // ௨৴Τϥʔ࣌ͷॲཧ }) } // ΩϟϥΫλʔ͝ͱͷίϛοΫҰཡΛऔಘ͢Δ func fetchCharacterComicListData(_ parameters: CharacterComicListRequest) { APIManager.request(type: APITypes.Character.comics(parameters), success: { data in do { let response = try JSONDecoder().decode(CharacterComicListResponse.self, from: data) // ௨৴&σίʔυޭ࣌ͷॲཧ } catch { // σίʔυΤϥʔ࣌ͷॲཧ } }, failure: { error in // ௨৴Τϥʔ࣌ͷॲཧ }) }
͋Εɾɾɾʁ // ΩϟϥΫλʔͷҰཡΛऔಘ͢Δ func fetchCharacterListData(parameters: CharacterListRequest) { APIManager.request(type: APITypes.Character.list(parameters), success:
{ data in do { let response = try JSONDecoder().decode(CharacterListResponse.self, from: data) // ௨৴&σίʔυޭ࣌ͷॲཧ } catch { // σίʔυΤϥʔ࣌ͷॲཧ } }, failure: { error in // ௨৴Τϥʔ࣌ͷॲཧ }) } // ΩϟϥΫλʔ͝ͱͷίϛοΫҰཡΛऔಘ͢Δ func fetchCharacterComicListData(_ parameters: CharacterComicListRequest) { APIManager.request(type: APITypes.Character.comics(parameters), success: { data in do { let response = try JSONDecoder().decode(CharacterComicListResponse.self, from: data) // ௨৴&σίʔυޭ࣌ͷॲཧ } catch { // σίʔυΤϥʔ࣌ͷॲཧ } }, failure: { error in // ௨৴Τϥʔ࣌ͷॲཧ }) }
ϨεϙϯεͷσίʔυॲཧΛ ຖճॻ͔͞ΕͯΔ
֤Ϩεϙϯε͝ͱʹσίʔυॲཧΛॻ͔ͣʹɺڞ௨Խ͠Α͏
GenericsΛ׆༻͢Δ
GenericsΛద༻͢Δ import Alamofire class APIManager { static func request(type: APIType,
success: @escaping (Data) -> Void, failure: @escaping (Error) -> Void) { // ௨৴Λߦ͏ Alamofire.request(type.url, parameters: type.parameter).responseData { response in switch response.result { case .success(let data): success(data) case .failure(let error): failure(error) } } } }
GenericsΛద༻͢Δ import Alamofire class APIManager<T: Decodable> { static func request(type:
APIType, success: @escaping (T) -> Void, failure: @escaping (Error) -> Void) { // ௨৴Λߦ͏ Alamofire.request(type.url, parameters: type.parameter).responseData { response in switch response.result { case .success(let data): do { let decodedData = try JSONDecoder().decode(T.self, from: data) success(decodedData) } catch { failure(error) } case .failure(let error): failure(error) } } } }
σίʔυ͕ڞ௨Խ͞ΕΔͱɾɾɾ // ΩϟϥΫλʔͷҰཡΛऔಘ͢Δ func fetchCharacterListData(parameters: CharacterListRequest) { APIManager.request(type: APITypes.Character.list(parameters), success:
{ data in do { let response = try JSONDecoder().decode(CharacterListResponse.self, from: data) // ௨৴&σίʔυޭ࣌ͷॲཧ } catch { // σίʔυΤϥʔ࣌ͷॲཧ } }, failure: { error in // ௨৴Τϥʔ࣌ͷॲཧ }) } // ΩϟϥΫλʔ͝ͱͷίϛοΫҰཡΛऔಘ͢Δ func fetchCharacterComicListData(_ parameters: CharacterComicListRequest) { APIManager.request(type: APITypes.Character.comics(parameters), success: { data in do { let response = try JSONDecoder().decode(CharacterComicListResponse.self, from: data) // ௨৴&σίʔυޭ࣌ͷॲཧ } catch { // σίʔυΤϥʔ࣌ͷॲཧ } }, failure: { error in // ௨৴Τϥʔ࣌ͷॲཧ }) }
͜͏ͳΔ // ΩϟϥΫλʔͷҰཡΛऔಘ͢Δ func fetchCharacterListData(parameters: CharacterListRequest) { APIManager<CharacterListResponse>.request(type: APITypes.Character.list(parameters), success:
{ data in // ޭ࣌ͷॲཧ(data = CharacterListResponse) }, failure: { error in // ௨৴ΤϥʔσίʔυΤϥʔ࣌ͷॲཧ }) } // ΩϟϥΫλʔ͝ͱͷίϛοΫҰཡΛऔಘ͢Δ func fetchCharacterComicListData(_ parameters: CharacterComicListRequest) { APIManager<CharacterComicListResponse>.request(type: APITypes.Character.comics(parameters), success: { data in // ޭ࣌ͷॲཧ(data = CharacterComicListResponse) }, failure: { error in // ௨৴ΤϥʔσίʔυΤϥʔ࣌ͷॲཧ }) }
☺
·ͱΊ • ϦΫΤετͷΓ͚enumͱprotocolͰཧͰ͖Δ • ϨεϙϯεͷσίʔυGenericsͰڞ௨Խग़དྷΔ • ΫϦεϚε·ͰʹMarvelͷΞϓϦΛ࡞Γ্͛Δ͜ͱ͕Ͱ͖ͳ ͔ͬͨͷͰ͜͜Ͱൃද͍ͯ͠Δ
͓͠·͍