Ana içeriğe geç

Başlarken

Connect-Swift, uygulamanızın sunucularıyla iletişim kurmak için üretilmiş, tip güvenli ve Swift özelliklerini kullanan API'leri destekleyen küçük bir kütüphanedir ( Add Packages... seçeneğine tıklayarak Connect-Swift paketine bağımlılık ekleyin:

Add Packages

Açılan pencerede, sağ üstteki Search or Enter Package URL metin alanına tıklayın ve Connect-Swift GitHub URL'sini yapıştırın:

https://github.com/connectrpc/connect-swift

Connect kütüphanesinin seçildiğinden emin olun, sonra paketi eklemek için Add Package butonuna tıklayın. Bu, gerekli SwiftProtobuf paketini de otomatik olarak ekleyecektir:

Add Connect Library

not

GRPC'yi taşıma protokolü olarak kullanmak isterseniz, Connect-Swift paketinden ConnectNIO kütüphanesini de eklemelisiniz; bu kütüphane, SwiftNIO kullanarak gRPC desteği sağlar. Bu bağımlılık, Connect veya gRPC-Web protokolü kullanılırken gerekli değildir.

Alternatif: CocoaPods kullanımı

CocoaPods, Swift Paket Yöneticisi'ne alternatif olarak desteklenmektedir. Connect-Swift'i CocoaPods ile kullanmak için, sadece Podfile'ınıza şu satırı ekleyin:

pod 'Connect-Swift'
pod 'SwiftProtobuf'
not

Connect-Swift, CocoaPods ile hem Connect hem de gRPC-Web protokollerini desteklese de, yalnızca Swift Paket Yöneticisi kullanılırken gRPC desteği mevcuttur; çünkü SwiftNIO, CocoaPods'u desteklememektedir.

Uygulamaya Entegre Edin

Öncelikle, önceki adımlardan üretilen .swift dosyalarını projenize ekleyin:

  • Generated dizinini Xcode'a sürükleyip ContentView.swift dosyasının yanına bırakın.
  • Sorulduğunda, Xcode'da Add to targets: altında Eliza'nın seçili olduğundan emin olun. Bu, üretilmiş kaynakların uygulama hedefinize derlenmesini sağlayacaktır.
  • Xcode istemcisinde Finish butonuna tıklayın.

Bu noktada, uygulamanızın başarılı bir şekilde derlenmesi gerekir.

Sohbet görünümünü oluşturmak için, ContentView.swift dosyasının içeriğini aşağıdaki kod ile değiştirin:

Üzerine tıklayın ContentView.swift genişletmek için
import Combine
import SwiftUI

struct Message: Identifiable {
enum Author {
case eliza
case user
}

typealias ID = UUID // Gerekli 'Identifiable' için

let id = UUID()
let message: String
let author: Author
}

final class MessagingViewModel: ObservableObject {
private let elizaClient: Connectrpc_Eliza_V1_ElizaServiceClientInterface

@MainActor @Published private(set) var messages = [Message]()

init(elizaClient: Connectrpc_Eliza_V1_ElizaServiceClientInterface) {
self.elizaClient = elizaClient
}

func send(_ sentence: String) async {
let request = Connectrpc_Eliza_V1_SayRequest.with { $0.sentence = sentence }
await self.addMessage(Message(message: sentence, author: .user))

let response = await self.elizaClient.say(request: request, headers: [:])
await self.addMessage(Message(
message: response.message?.sentence ?? "Yanıt yok", author: .eliza
))
}

@MainActor
private func addMessage(_ message: Message) {
self.messages.append(message)
}
}

struct ContentView: View {
@State private var currentMessage = ""
@ObservedObject private var viewModel: MessagingViewModel

init(viewModel: MessagingViewModel) {
self.viewModel = viewModel
}

var body: some View {
VStack {
ScrollViewReader { listView in
// ScrollViewReader, iOS 16 ile ListView'de çöküyor:
// https://developer.apple.com/forums/thread/712510
// Bir alternatif olarak ScrollView + ForEach kullanıyoruz.
ScrollView {
ForEach(self.viewModel.messages) { message in
VStack {
switch message.author {
case .user:
HStack {
Spacer()
Text("Siz")
.foregroundColor(.gray)
.fontWeight(.semibold)
}
HStack {
Spacer()
Text(message.message)
.multilineTextAlignment(.trailing)
}
case .eliza:
HStack {
Text("Eliza")
.foregroundColor(.blue)
.fontWeight(.semibold)
Spacer()
}
HStack {
Text(message.message)
.multilineTextAlignment(.leading)
Spacer()
}
}
}
.id(message.id)
}
}
.onChange(of: self.viewModel.messages.count) { messageCount in
listView.scrollTo(self.viewModel.messages[messageCount - 1].id)
}
}

HStack {
TextField("Mesajınızı yazın...", text: self.$currentMessage)
.onSubmit { self.sendMessage() }
.submitLabel(.send)
Button("Gönder", action: { self.sendMessage() })
.foregroundColor(.blue)
}
}
.padding()
}

private func sendMessage() {
let messageToSend = self.currentMessage
if messageToSend.isEmpty {
return
}

Task { await self.viewModel.send(messageToSend) }
self.currentMessage = ""
}
}

Son olarak, ElizaApp.swift dosyasının içeriğini aşağıdaki kod ile değiştirin:

Üzerine tıklayın ElizaApp.swift genişletmek için

import Connect
import SwiftUI

@main
struct ElizaApp: App {
@State private var client = ProtocolClient(
httpClient: URLSessionHTTPClient(),
config: ProtocolClientConfig(
host: "https://demo.connectrpc.com",
networkProtocol: .connect, // Ya da .grpcWeb
codec: ProtoCodec() // Ya da JSONCodec()
)
)

var body: some Scene {
WindowGroup {
ContentView(viewModel: MessagingViewModel(
elizaClient: Connectrpc_Eliza_V1_ElizaServiceClient(client: self.client)
))
}
}
}

Uygulamayı derleyip çalıştırdığınızda, Eliza ile sohbet edebilmelisiniz! 🎉

Chat with Eliza!

Kısaca

Yukarıdaki kodların neler yaptığını, özellikle Connect kütüphanesiyle etkileşimi hakkında detaylara göz atalım.

Bir ProtocolClient oluşturma

Öncelikle, ElizaApp bir ProtocolClient örneği oluşturur ve saklar. Bu tür, hangi HTTP istemcisinin kullanılacağını (varsayılan olarak URLSession), verilerin nasıl kodlanacağı/çözümleneceği (yani JSON veya Protobuf ikili format) ve hangi protokolün kullanılacağının belirtildiği çeşitli seçeneklerle yapılandırılır (bu durumda, Connect protokolü).

Eğer Protobuf yerine JSON kullanmak ve istekleri gziplemek isteseydik, sadece iki satırlık basit bir değişiklik yapmamız yeterli olurdu:

private var client = ProtocolClient(
httpClient: URLSessionHTTPClient(),
config: ProtocolClientConfig(
host: "https://demo.connectrpc.com",
networkProtocol: .connect,
codec: JSONCodec(),
requestCompression: .init(minBytes: 50_000, pool: GzipCompressionPool())
)
)

HTTP istemcisinin davranışı, URLSessionHTTPClient'in alt sınıfını oluşturarak, ConnectNIO kütüphanesindeki NIOHTTPClient'i kullanarak veya HTTPClientInterface protokolüne uyan yeni bir tür tanımlayarak ve bunu httpClient olarak geçirerek özelleştirilebilir. Daha fazla özelleştirme seçeneği için istemci kullanımı belgelerine göz atın.

gRPC kullanımı

Yukarıdaki örnekte gRPC'yi taşıma protokolü olarak kullanmak isterseniz, aşağıdaki satırları değiştirerek bunu yapabilirsiniz; ayrıca, ConnectNIO kütüphanesi bağımlılığını eklediğinizden emin olun:

Üzerine tıklayın

import ConnectNIO

...

private var client = ProtocolClient(
httpClient: NIOHTTPClient(host: "https://demo.connectrpc.com"),
config: ProtocolClientConfig(
host: "https://demo.connectrpc.com",
networkProtocol: .grpc,
codec: JSONCodec(),
requestCompression: .init(minBytes: 50_000, pool: GzipCompressionPool())
)
)

Üretilmiş kodu kullanma

Yukarıda MessagingViewModel sınıfına bir göz atın. Bu sınıf, Connectrpc_Eliza_V1_ElizaServiceClientInterface türünde bir örnek ile başlatılır - bu, ElizaService Protobuf servis tanımından üretilen Swift protokolüdür. Etkileşimli bir protokolü kabul etmek, üretilmiş Connectrpc_Eliza_V1_ElizaServiceClient somut türünü değil de protokole uyan türleri kullanmamıza olanak tanıyarak, testler için sahte sınıfların enjekte edilmesine olanak sağlar. Mocklar ve testler hakkında detaylara girmeyeceğiz, ancak daha fazla bilgi ve örnekler için test belgelerine bakabilirsiniz.

SwiftUI görünümünden send(...) fonksiyonu çağrıldığında, görünüm modelinin bir Connectrpc_Eliza_V1_SayRequest oluşturup bunu sunucudan bir yanıt almak için üretilmiş istemcideki say(...) fonksiyonuna ilettiğini göreceksiniz. Tüm bunlar, daha önce yazdığımız Protobuf dosyasından üretilmiş, tip güvenli API'ler kullanılarak yapılır.

Bu örnek Swift'in async/await API'lerini kullansa da, Connect-Swift, geleneksel kapalı fonksiyonlar/geri çağrılar için de üretim yapabilir ve üretilmiş .connect.swift dosyasını açtığınızda her iki arayüzü de göreceksiniz. Bu davranış, üretici seçenekleriyle özelleştirilebilir.

Daha fazla örnek

İnceleyebileceğiniz daha fazla detaylı örnek bulunmaktadır; bunlar Connect-Swift deposunda yer almaktadır. Bu örnekler:

gRPC veya gRPC-Web kullanımı

Connect-Swift, Connect, gRPC ve gRPC-Web protokollerini destekler. Aralarındaki geçişleri sağlamak için talimatlar burada bulunabilir.

Bir dizi nedenden dolayı, gRPC protokolünü kullanıyorsanız bile, Connect-Swift'i gRPC-Swift üzerinde kullanmanızı öneririz:

  • İdiomatik, tipli API'ler. Artık REST/JSON uç noktalarını ve Codable uyumlarını elle yazmak yok. Connect-Swift, en son Swift özelliklerini kullanan ve serileştirme endişelerinizi ortadan kaldıran idiyomatik API'ler üretiyor.
  • Birinci sınıf test desteği. Connect-Swift, aynı protokol arayüzlerine uyan hem üretim hem de sahte uygulamalar üreterek, test edilebilirliği sağlıyor ve minimum el yazımı boilerplate ile kolaylık sağlıyor.
  • Kullanımı kolay araçlar. Connect-Swift, uzak kod üretimi yapmak için Buf CLI ile entegre olup, yerel bağımlılıkları yüklemeye ve yapılandırmaya gerek kalmadan kullanılabilir.
  • Esneklik. Connect-Swift, URLSession'ı kullanıyor. Kütüphane, bunun değiştirilmesini ve özel sıkıştırma algoritmalarını ve interceptor'leri kaydetme seçeneğini sunuyor.
  • İkili boyut. Connect-Swift kütüphanesi çok küçüktür (<200KB) ve Connect ve gRPC-Web protokolleriyle kullanıldığında herhangi bir üçüncü taraf ağ bağımlılığı gerektirmez. gRPC ile kullanıldığında ise, SwiftNIO bağımlılığı nedeniyle ikili boyut biraz daha büyük (~2.4MB) olacaktır; bu, HTTP trailer'larını desteklemek içindir.

Eğer arka uç hizmetleriniz halihazırda gRPC kullanıyorsa, Envoy, requests için Connect ve gRPC-Web protokollerini gRPC'ye dönüştüren destek sağlar; böylelikle SwiftNIO bağımlılığı olmadan Connect-Swift kullanabilirsiniz.