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
「寝てても仕事が進む」Claude Codeで組む第二の脳
tomoyafujita2016
0
340
自動化したのに回らないテスト運用の壁ーAI時代の品質責任と生産性
mfunaki
1
140
いまどきの Codex で開発する visionOS アプリの開発スタイルについて
karad
0
150
ソフトウェアエンジニアにとっての生成AI - 特性を知って使い倒す / generative ai for software enginner
kishida
5
1.8k
AWS DevOps AgentのAzure接続機能を検証して見えた活用法/Use Cases Verified for the AWS DevOps Agent's Azure Connectivity Feature
masakiokuda
1
240
AI Engineeringは、AIプロダクトだけのものか? 〜AIがソフトウェアを作る時代の新しい当たり前〜 / No AI in your product. AI Engineering in your development.
rkaga
4
450
「人を評価する AI」の設計と実装
ryoyanara
0
210
Flow は今どうなっているか
mizdra
PRO
0
590
実装をデザインガイドラインに追従させるための取り組み / 260731-dip-mosh-design-system
dachi023
0
640
数百円から始めるRuby電子工作
tarosay
0
160
そこに3びきプロダクトがいるじゃろう——生成AI時代における“価値が届かない理由”の構造
kosuket
0
500
VibeCodingからAgenticWorkflowへ
starfish719
0
550
Featured
See All Featured
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
123
22k
Speed Design
sergeychernyshev
33
2k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
2
3.8k
Exploring anti-patterns in Rails
aemeredith
3
460
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
370
[RailsConf 2023] Rails as a piece of cake
palkan
59
6.9k
Side Projects
sachag
455
43k
Discover your Explorer Soul
emna__ayadi
2
1.3k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
490
Agile that works and the tools we love
rasmusluckow
331
22k
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.5k
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ͷΞϓϦΛ࡞Γ্͛Δ͜ͱ͕Ͱ͖ͳ ͔ͬͨͷͰ͜͜Ͱൃද͍ͯ͠Δ
͓͠·͍