Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
iosdc_2018.pdf
Search
Kyohei Ito
August 31, 2018
3.2k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
iosdc_2018.pdf
Kyohei Ito
August 31, 2018
More Decks by Kyohei Ito
See All by Kyohei Ito
flutter_kaigi_2025.pdf
kyoheig3
2
1.1k
layerx_20241129.pdf
kyoheig3
2
530
flutterkaigi_2024.pdf
kyoheig3
0
1.9k
flutter_kaigi_2021.pdf
kyoheig3
0
1.2k
flutter_kmm_1.pdf
kyoheig3
1
1.2k
ca.swift_10.pdf
kyoheig3
0
720
orecon_vol1.pdf
kyoheig3
4
1.8k
iosdc_2017.pdf
kyoheig3
4
940
ca.swift_2.pdf
kyoheig3
9
1.4k
Featured
See All Featured
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
500
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
1
610
Measuring & Analyzing Core Web Vitals
bluesmoon
9
1k
Skip the Path - Find Your Career Trail
mkilby
1
230
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.6k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
4
1.2k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.4k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.8k
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
2
280
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.6k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
730
Transcript
grpc-swiftΛͬͯ iOSΞϓϦͰշదͳ gRPC௨৴Λߦ͏ɹɹ 2018/08/31 iOSDC
About Me ҏ౻ɹګฏ Github : KyoheiG3 Twitter : @KyoheiG3
About Me ΩϡϨʔγϣϯ Ameba OWND AbemaTV SUPERCHOICE ࠓ·ͨ৽ن
gPRC
gRPCͬͯԿʁ • Google͕࡞ͬͨRPCΛ࣮ݱ͢ΔͨΊͷϑϨʔϜϫʔΫ • ͚ࣾͷStubbyΛɺ2015ʹΦʔϓϯԽͨ͠ͷ • HTTP2
RPCͬͯԿʁ • ϦϞʔτϓϩγʔδϟίʔϧͷུ • ϓϩάϥϜ͔ΒผͷΞυϨεۭؒʹ͋Δαϒϧʔνϯखଓ ͖Λ࣮ߦ͢Δ͜ͱΛՄೳʹ͢Δٕज़
HTTP2 • SPDYΛج൫ʹ࡞Γग़͞Εͨ • SPDYGoogle
Մೳͳ௨৴ํࣜ
Unaryʢ୯ൃͷ௨৴ʣ • 1ͭͷϦΫΤετʹର͠ɺϨεϙϯεΛ1ͭฦ͢ • HTTP1ܥͱಉ͡Α͏ͳεςʔτϨεͳ௨৴ํࣜ
Server StreamingʢαʔόετϦʔϛϯάʣ • 1ͭͷϦΫΤετʹର͠ɺϨεϙϯεΛෳฦ͢ • αʔόpush ϙʔϦϯάʹஔ͖ΘΔ
Client StreamingʢΫϥΠΞϯτετϦʔϛϯάʣ • ෳͷϦΫΤετʹର͠ɺϨεϙϯεΛ1ͭฦ͢ • ϑΝΠϧΞοϓϩʔυͳͲ
Bi-Directional StreamingʢํετϦʔϛϯάʣ • ෳͷϦΫΤετʹର͠ɺϨεϙϯεΛෳฦ͢ • νϟοτͳͲ
Αࣖ͘ʹ͢ΔProtocol Buffersͱͷҧ͍ͬͯʁ • Protocol Buffers௨৴͢Δσʔλͷܗࣜʢjson, xml...ʣ • gRPC௨৴ͷखஈ
͢͜͠Protocol Buffersͷ͓͞Β͍
protobuf • protobufͱུ͞ΕΔ͜ͱ͕ଟ͍ • όΠφϦϕʔε • .protoϑΝΠϧͰσʔλܗࣜΛఆٛ
echo.proto syntax = "proto3"; package echo; message EchoRequest { string
text = 1; } message EchoResponse { string text = 1; }
protobuf • .protoϑΝΠϧ͔ΒɺswiftgoϑΝΠϧΛ࡞Մೳ
protobuf $ protoc echo.proto --plugin=./protoc-gen-swift --swift_out=.
echo.pb.swift struct Echo_EchoRequest { var text: String = String() var
unknownFields = SwiftProtobuf.UnknownStorage() init() {} } struct Echo_EchoResponse { var text: String = String() var unknownFields = SwiftProtobuf.UnknownStorage() init() {} }
protobuf • swiftͰApple͕ެࣜʹαϙʔτ1 • όΠφϦͷγϦΞϥΠζɾσγϦΞϥΠζͷϥΠϒϥ Ϧʹґଘ • ܰͯ͘ܕ҆શ 1 https://github.com/apple/swift-protobuf
protobuf σϝϦοτ • ௨৴σʔλͷՄಡੑ͕͗͢Δʢͱ͍͏͔ಡΊͳ͍ʣ • ಋೖʹҰखؒඞཁ
protobuf ϝϦοτ ׂѪ͠·͢ɻ ϝϦοτͨ͘͞Μ͋ΔͷͰɺσʔλܗࣜͷબࢶͷҰͭʹೖ ΕΔͷ͋Γͩͱࢥ͍·͢ɻ
gRPC × protobuf • gRPC͕ར༻͢ΔσϑΥϧτͷσʔλܗ͕ࣜprotobuf • gRPC͋͘·Ͱ௨৴ͷखஈͳͷͰɺσʔλܗࣜҰԠjsonͱ ͔Մೳ • ͚ͲɺprotobufͱgRPCζϒζϒͳͷͰҰॹʹ͏લఏ
SwiftGRPC
SwiftGRPC • objective-cͰc++Ͱ࣮͞ΕͨgrpcΛར༻2 • swiftͰར༻͢Δʹগʑ໘ 2 https://github.com/grpc/grpc
SwiftGRPC • grpcͷΠϯλʔϑΣʔεΛswiftͰϥοϓ
Officially Supported Platforms3 C/C++, C#, Dart *, Go, Java, Node.js,
PHP *, Python, Ruby * ·ͩbeta SwiftΞϯΦϑΟγϟϧͰ͔͢?! 3 https://grpc.io/about/#osp
ಋೖ
ಋೖ • ͱʹ͔͘protobufલఏ • SwiftGRPCͷprotocϓϥάΠϯΛ࡞ • .protoϑΝΠϧ͔Β.swiftϑΝΠϧΛ࡞
protobufΛΠϯετʔϧ $ brew install protobuf
SwiftGRPCͷprotocϓϥάΠϯΛ࡞ • grpc-swiftΛcloneͯ͠build $ git clone https://github.com/grpc/grpc-swift.git $ cd grpc-swift
$ make all > .protoc-gen-swift .protoc-gen-swiftgrpc
ඞཁʹԠͯ͡pathΛ௨͢ • ࣮ߦ࣌ʹϓϥάΠϯͷpathΛࢦఆͰ͖ΔͷͰඞਢͰͳ͍ $ mkdir ~/.protoc $ cp ./protoc-gen-swift ./protoc-gen-swiftgrpc
~/.protoc $ echo 'export PATH=$PATH:$HOME/.protoc' >> ~/.bash_profile $ source ~/.bash_profile
protoc-gen-swiftgrpc • SwiftGRPCͷprotocϓϥάΠϯ • protobufͱಉ༷ʹ.proto͔Β.swiftΛ࡞
echo.protoʢbeforeʣ syntax = "proto3"; package echo; message EchoRequest { string
text = 1; } message EchoResponse { string text = 1; }
echo.protoʢserviceʣ • serviceͷதʹɺrpcϑΟʔϧυΛఆٛ͢Δ service Echo { rpc }
echo.protoʢserviceʣ • rpcϑΟʔϧυʹҙͷϝιουΛఆٛ͢Δ service Echo { rpc Get }
echo.protoʢserviceʣ • ϦΫΤετͷΦϒδΣΫτΛఆٛ͢Δ service Echo { rpc Get(EchoRequest) }
echo.protoʢserviceʣ • ϨεϙϯεͷΦϒδΣΫτΛఆٛ͢Δ service Echo { rpc Get(EchoRequest) returns(EchoResponse) {}
}
echo.protoʢserviceʣ • streamෳճͷॲཧΛՄೳʹ͢Δఆٛ service Echo { rpc Get(EchoRequest) returns (EchoResponse)
{} rpc Expand(EchoRequest) returns (stream EchoResponse) {} rpc Collect(stream EchoRequest) returns (EchoResponse) {} rpc Update(stream EchoRequest) returns (stream EchoResponse) {} }
echo.protoʢafterʣ syntax = "proto3"; package echo; message EchoRequest { string
text = 1; } message EchoResponse { string text = 1; } service Echo { rpc Get(EchoRequest) returns (EchoResponse) {} rpc Expand(EchoRequest) returns (stream EchoResponse) {} rpc Collect(stream EchoRequest) returns (EchoResponse) {} rpc Update(stream EchoRequest) returns (stream EchoResponse) {} }
protoc-gen-swiftgrpc $ protoc echo.proto --plugin=./protoc-gen-swiftgrpc --swiftgrpc_out=.
echo.grpc.swift protocol Echo_EchoProvider: ServiceProvider { func get(request: Echo_EchoRequest, session: Echo_EchoGetSession)
throws -> Echo_EchoResponse func expand(request: Echo_EchoRequest, session: Echo_EchoExpandSession) throws -> ServerStatus? func collect(session: Echo_EchoCollectSession) throws -> Echo_EchoResponse? func update(session: Echo_EchoUpdateSession) throws -> ServerStatus? } protocol Echo_EchoService: ServiceClient { func get(_ request: Echo_EchoRequest) throws -> Echo_EchoResponse func get(_ request: Echo_EchoRequest, completion: @escaping (Echo_EchoResponse?, CallResult) -> Void) throws -> Echo_EchoGetCall func expand(_ request: Echo_EchoRequest, completion: ((CallResult) -> Void)?) throws -> Echo_EchoExpandCall func collect(completion: ((CallResult) -> Void)?) throws -> Echo_EchoCollectCall func update(completion: ((CallResult) -> Void)?) throws -> Echo_EchoUpdateCall }
EchoʢαϯϓϧʣͰίʔυղઆ
Echoͷಈ͔͠ํ • SwiftGRPC.xcodeprojΛ࡞͢Δ $ make project
Echoͷಈ͔͠ํ • ./third_party/swift-protobuf͕ඞཁ • ࠷ۙऔಘεΫϦϓτ͕আ͞Εͨ4 $ mkdir third_party $ cd
third_party $ git clone https://github.com/apple/swift-protobuf.git 4 https://github.com/grpc/grpc-swift/pull/296
Echoͷಈ͔͠ํ • ./Examples/EchoXcode/Echo.xcodeprojΛ։͘
Echoͷಈ͔͠ํ • ./SwiftGRPC.xcodeprojΛϓϩδΣΫτʹՃ͢Δ
Echoͷಈ͔͠ํ • Target DependenciesʹSwiftGRPC.frameworkΛՃ͢Δ
Echo for Client
Echo_EchoServiceClient • ΫϥΠΞϯτ͔ΒαʔόͷଓΛཧ • ෦ͰChannelΦϒδΣΫτΛอ࣋ • Echo_EchoServiceʹ४ڌ • get, expand,
collect, updateϝιουΛ࣮ߦͯ͠ɺετ ϦʔϛϯάΛߦ͏ͨΊͷCallΦϒδΣΫτΛ࡞
Echo_EchoServiceClient let service = Echo_EchoServiceClient(address: "YOUR_ADDRESS", secure: false)
Echo_EchoExpandCallʢServerStreamingʣ • expand()ϝιουͰऔಘ • αʔόετϦʔϛϯά͕Մೳ • receive()ϝιουΛ࣮ߦՄೳ
Echo_EchoExpandCallʢServerStreamingʣ var requestMessage = Echo_EchoRequest() requestMessage.text = "message" let expandCall
= try service.expand(requestMessage) { _ in } try expandCall.receive { response in // ϨεϙϯεΛड͚औΔ }
Echo_EchoCollectCallʢClientStreamingʣ • collect()ϝιουͰऔಘ • ΫϥΠΞϯτετϦʔϛϯά͕Մೳ • send(), closeAndReceive()ϝιουΛ࣮ߦՄೳ
Echo_EchoCollectCallʢClientStreamingʣ let collectCall = try service.collect { _ in }
var requestMessage = Echo_EchoRequest() requestMessage.text = "message" try collectCall.send(requestMessage) { error in // ΤϥʔΛड͚औΔ } try collectCall.closeAndReceive { response in // close࣌ʹ1͚ͩσʔλΛड͚औΕΔ }
Echo_EchoUpdateCallʢBidirectionalStreamingʣ • update()ϝιουͰऔಘ • ํετϦʔϛϯά͕Մೳ • send(), receive(), closeSend()ϝιουΛ࣮ߦՄೳ
Echo_EchoUpdateCallʢBidirectionalStreamingʣ let updateCall = try service.update { _ in }
try updateCall.receive { response in // ϨεϙϯεΛड͚औΔ } var requestMessage = Echo_EchoRequest() requestMessage.text = "message" try updateCall.send(requestMessage) { error in // ΤϥʔΛड͚औΔ } try updateCall.closeSend {}
ΫϥΠΞϯτ࣮ͷجຊతͳྲྀΕ • Service͔ΒCallΦϒδΣΫτΛ࡞͢Δ • ࡞ͨ͠CallΦϒδΣΫτʹ༻ҙ͞Ε͍ͯΔstreamingͷϝ ιουΛݺͼग़͢ • CallΦϒδΣΫτstreaming͕ऴྃ͢Δ·Ͱอ͓࣋ͯ͘͠ ※ Unaryྫ֎
Echo_EchoGetCallʢUnaryʣ • get()ϝιουͰऔಘ • streaming༻ͷϝιου༻ҙ͞Ε͍ͯͳ͍
Echo_EchoGetCallʢUnaryʣ var requestMessage = Echo_EchoRequest() requestMessage.text = "message" let getCall
= try service.get(requestMessage) { response, callResult in }
ΫϥΠΞϯτ࣮ͷಛ • CallΦϒδΣΫτΛ࡞͔ͬͨ࣌ΒtimeoutΧϯτμϯ • σϑΥϧτ600ඵͰɺϦΫΤετݸผʹઃఆෆՄ • ClientStreamingͷsend()ʹҾͰͤΔtimeoutɺಉظ ௨৴͢Δࡍͷsemaphoreͷػ࣌ؒ
ΫϥΠΞϯτ࣮ͷಛ • receive()ɺ1ͰσʔλΛड͚औΔͱͦΕҎ࣮߱ߦ͞ Εͳ͍ͷͰɺ࠶receive()ΛݺͿඞཁ͕͋Δ • ͳʹ͔͠ΒͷΤϥʔ͕ग़ͨΒͦΕҎ߱ૹड৴Ͱ͖ͳ͍ͷͰɺ CallΦϒδΣΫτ͔Β࠶࡞͢Δඞཁ͕͋Δ • throws͕ͨΒଟ͍
ΫϥΠΞϯτͷstubʹ͍ͭͯ • ServerΛϩʔΧϧʹ࣮ͯ͠stubԽ
Echo for Server
ServiceServer • αʔόͷΫϥΠΞϯτ͔ΒͷଓΛཧ • ෦ͰServerΦϒδΣΫτΛอ࣋ • Echo_EchoProviderʹ४ڌͨ͠ΦϒδΣΫτΛड͚औΔ • startϝιουͰɺଓͷड৴Λ։࢝
ServiceServer class EchoProvider: Echo_EchoProvider { func get() {} func expand()
{} func collect() {} func update() {} } let provider = EchoProvider() let server = ServiceServer(address: "YOUR_ADDRESS", serviceProviders: [provider]) server.start()
Echo_EchoProvider • get, expand, collect, updateϝιουͰɺΫϥΠΞϯ τͷϨεϙϯεΛߦ͏ • ҾͰ͞ΕΔSessionΦϒδΣΫτͰৼΔ͍Λ࣮
Echo_EchoProviderʢget == Unaryʣ • Echo_EchoRequestΦϒδΣΫτΛऔಘ • Echo_EchoResponseΛฦͨ͠Βऴྃ
Echo_EchoProviderʢget == Unaryʣ func get(request: Echo_EchoRequest, session _: Echo_EchoGetSession) throws
-> Echo_EchoResponse { var response = Echo_EchoResponse() response.text = request.text + " response" return response }
Echo_EchoProviderʢexpand == ServerStreamingʣ • Echo_EchoRequestΦϒδΣΫτΛऔಘ • ඞཁʹԠͯ͡sessionͷsend()Λ࣮ߦ • ServerStatusΛฦ͠ɺ͔ͭsend()͕ྃͨ͠Βऴྃ
Echo_EchoProviderʢexpand == ServerStreamingʣ func expand(request: Echo_EchoRequest, session: Echo_EchoExpandSession) throws ->
ServerStatus? { var response = Echo_EchoResponse() response.text = request.text + " response" try! session.send(response) { // ΤϥʔΛड͚औΔ } return .ok }
Echo_EchoProviderʢcollect == ClientStreamingʣ • ϦΫΤετsessionͷreceive()Ͱऔಘ • Echo_EchoResponseΛฦͨ͠Βऴྃ
Echo_EchoProviderʢcollect == ClientStreamingʣ func collect(session: Echo_EchoCollectSession) throws -> Echo_EchoResponse? {
var response = Echo_EchoResponse() let request = try! session.receive() response.text = request.text + " response" return response }
Echo_EchoProviderʢupdate == BidiStreamingʣ • ϦΫΤετsessionͷreceive()Ͱऔಘ • ඞཁʹԠͯ͡sessionͷsend()Λ࣮ߦ • ServerStatusΛฦ͠ɺ͔ͭsend()͕ྃͨ͠Βऴྃ
Echo_EchoProviderʢupdate == BidiStreamingʣ func update(session: Echo_EchoUpdateSession) throws -> ServerStatus? {
let request = try! session.receive() var response = Echo_EchoResponse() response.text = request.text + " response" try! session.send(response) { // ΤϥʔΛड͚औΔ } return .ok }
αʔό࣮ͷجຊతͳྲྀΕ • Echo_EchoProviderʹ४ڌͨ͠ΦϒδΣΫτΛ࡞͢Δ • ProviderͷϝιουͰಉظతʹॲཧ͠ɺΛฦͯ͠ऴྃ
SwiftGRPCClient
None
SwiftGRPCClient > https://github.com/cats-oss/grpc-swift-client • ΫϥΠΞϯτઐ༻ͷgRPCϥΠϒϥϦ • SwiftGRPCʹґଘ • timeoutΛϦΫΤετ୯ҐͰܾΊͨΓ •
ϦΫΤετͷ్தͰॲཧΛΠϯλʔηϓτͨ͠Γ • receive()ΛࣗಈͰϦτϥΠͯ͘͠ΕͨΓ
protoc-gen-swiftgrpc-client $ protoc echo.proto --plugin=./protoc-gen-swiftgrpc-client --swiftgrpc-client_out=.
protoc-gen-swiftgrpc-client enum Echo_EchoMethod: String, CallMethod { case get = "Get"
static let service = "echo.Echo" } protocol _Echo_EchoGetRequest { typealias InputType = Echo_EchoRequest typealias OutputType = Echo_EchoResponse } protocol Echo_EchoGetRequest: _Echo_EchoGetRequest, UnaryStreamingRequest {} extension Echo_EchoGetRequest { var method: CallMethod { return Echo_EchoMethod.get } }
SwiftGRPCʢClientStreamingʣ let collectCall = try service.collect { _ in }
var requestMessage = Echo_EchoRequest() requestMessage.text = "message" try collectCall.send(requestMessage) { error in // ΤϥʔΛड͚औΔ } try collectCall.closeAndReceive { response in // close࣌ʹ1͚ͩσʔλΛड͚औΕΔ }
SwiftGRPCClientʢClientStreamingʣ let stream = Session.shared.stream(with: EchoClientRequest()) stream .send("message") { response
in // ૹ৴݁ՌΛड͚औΔ } stream .closeAndReceive { response in // close࣌ʹ1͚ͩσʔλΛड͚औΕΔ }
SwiftGRPCʢServerStreamingʣ var requestMessage = Echo_EchoRequest() requestMessage.text = "message" let expandCall
= try service.expand(requestMessage) { _ in } try expandCall.receive { response in // ϨεϙϯεΛड͚औΔ }
SwiftGRPCClientʢServerStreamingʣ let stream = Session.shared.stream(with: EchoServerRequest(text: "message")) .receive { response
in // ϨεϙϯεΛड͚औΔ }
SwiftGPRCClientʢRxʣ extension Reactive where Base: Streaming, Base.Request: UnaryRequest { func
data() -> Observable<Base.Request.OutputType> { return .create { observer in self.base.data { result in switch result { case .success(let data): observer.onNext(data) observer.onCompleted() case .failure(let error): observer.onError(error) } } return Disposables.create { self.base.cancel() } } } }
SwiftGPRCClientʢRxʣ Session.shared.stream(with: EchoUnaryRequest()).rx.data() .subscribe(onNext: { response in // ϨεϙϯεΛड͚औΔ },
onError: { error in // ΤϥʔΛड͚औΔ }) .disposed(by: disposeBag)
SwiftGPRCClient • ΫϥΠΞϯτʹSwiftGPRCClientΛར༻ͯ͠ɺstubͱͯ͠ SwiftGRPCͷαʔό࣮Λར༻͢Δ
ॴײͱࠓޙ
ॴײ • ࠷ॳcallͷcancel͢Βແ͔ͬͨ • ಋೖ͕ਏ͔ͬͨ • Τϥʔ࣌ͷࡉ͔͍ڍಈ͕௫ΈͮΒ͍
Swift Summit
ࠓޙ • ࠷ۙυΠπਓͷΤϯδχΞ͕ฃಆͯ͠ϝϯςφϯε • Network.frameworkͷಋೖͷݕ౼ͳͲ͕͞Ε͍ͯΔ • ͱΓ͋͑ͣਖ਼ࣜʹgrpcҰʹೖͬͯཉ͍͠
grpc-swiftΛͬͯiOSΞϓϦͰշదͳgRPC௨৴Λߦ͏ɹɹ https://github.com/cats-oss/grpc-swift-client Github : KyoheiG3 Twitter : @KyoheiG3
Thanks!