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
330
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
760
「シェア機能」について考えてみた
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
Foundry Localでエージェント開発
seosoft
0
150
書籍「プロフェッショナルAI駆動開発」紹介スライド
juntaromatsumoto
0
1k
[DroidKaigi 2026] Bring your own phones to Gradle Managed Devices
f2lk
0
110
AIと壁打ちしながら進めるコスト管理
fufuhu
2
1.9k
Go を使い始めて 2 ヶ月の学び / My first two months with Go
contour_gara
0
420
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
120
異なる設計思想のフレームワークを経験して得た学び
amekuhideki
2
1.5k
標準パッケージに uuid が追加された 背景から見る Go らしい意思決定 / go_127_uuid_decision
convto
2
2.4k
The Good Stuff, Not the Slop: Engineering High-Quality Android Apps with Modern AI Tooling
danybony
1
200
型解析で実現する Go の言語内 DSL / Conference に Go! タイムテーブルの歩き方 for Gophers
mazrean
0
130
30年振りにコンパイラの定数整数除算を改善した
herumi
9
4.5k
PHPプロジェクトの結合バランスを可視化する #php_night
kajitack
0
230
Featured
See All Featured
The Art of Programming - Codeland 2020
erikaheidi
57
14k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.5k
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
400
A Modern Web Designer's Workflow
chriscoyier
698
190k
Prompt Engineering for Job Search
mfonobong
0
440
Reality Check: Gamification 10 Years Later
codingconduct
0
2.3k
Designing for humans not robots
tammielis
254
26k
Scaling GitHub
holman
464
140k
A Soul's Torment
seathinner
7
3.6k
Build your cross-platform service in a week with App Engine
jlugia
234
19k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
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ͷΞϓϦΛ࡞Γ্͛Δ͜ͱ͕Ͱ͖ͳ ͔ͬͨͷͰ͜͜Ͱൃද͍ͯ͠Δ
͓͠·͍