Table of Contents

iOS'ta Birlikte Reaktif Programlamaya Giriş

Modern iOS uygulamaları doğal olarak bir şekilde, bu olayları gerekli delegeler, çağrı merkezleri veya bildirim merkezlerinden, genellikle karmaşık, hata-prone koduna yol açan kodlar ile birleştirmelidir. iOS 13,'ta Apple tarafından tanıtıldı, birleşik, yanlış bir şekilde, uyumlu bir şekilde işlem yapan bir programlamayı mümkün kılar.Bu etkinlikler ve veri akışlarını kullanarak, yayıncıları, aboneleri ve bildirim merkezleri kullanarak, aboneleri ve bildirim merkezleri kullanarak, şifreler ve şifreler kullanarak, basitleştirilmiş bir şekilde birleştirebilirsiniz.Bu, doğrulayıcı bir şekilde doğrulayıcı bir şekilde programlamayı sağlar.

Eklem Çerçeve Nedir?

Bir araya gelme, zaman içinde işleme değerleri için bir dekümatif API sağlar.Bu değerlerin bir parçasıdır ve SwiftUI, Foundation ve UIKit.Comple üç temel soyutlama üzerine inşa edilir: 0:0.D[Döneticiler|Kategoriler) Uygulamanızı nasıl akarlar)

RxSwift gibi önceki kalıpların aksine, Apple'ın platformları ile ilk parti ve derinden entegre edilmiştir, özellikle de birçok veriye dayalı özellik birleştirmektedir.

Core Concepts of Together

Koda girmeden önce, her bir bütün boru hattını oluşturan dört temel bileşeni anlamak önemlidir:

  • [FONT:0)Publisher[[Dönetici: 1) Bir yayıncı, zaman içinde bir dizi değer yayabilir veya başarısız olabilir.
  • [FONT:0)Subr[[[Dönetici: 1 ) - Bir yayıncıdan gelen değer alan bir tür. 3 yöntemi tanımlar: [[Dönetici: [[Dönetici: [[Yeni bir değer ele almak için, ve [[Döneticileri işlemek için) ve [[başlangıçta veya başarısızlık.
  • [FONT:0)Operator[DÜDÜT:1) - Bir yayınevinden gelen bir yayıncı, doğrulayıcıdan gelen değerleri dönüştürmüş ve bu zincirleme, boru hatları güçlü hale getiren şeydir.
  • [[Döntücü[[Döncü:0)|Döntilmiş (Döncü)|Döntilmiş veya manuel olarak iptal edilen değerlerden vazgeçilebilecek abonelikleri kontrol eder. Abonelikler, talep akışını kontrol eder (geri yükleme) Abonelikler, değer almayı durdurmayı durdurmayı iptal edebilir, bu da otomatik olarak ele alınır.

Ek olarak, bir sette (ve) erişilebilirlik (ve somut tip OLFLT:13) bir abonelikin yaşam döngüsünü yönetmek için (örneğin, 0:0)Yeterli (ve) aboneliklerin otomatik olarak kapandığını garanti eder.

Yayıncılar Yaratmak

Bir araya, ortak asenkron görevleri kapsayan birçok yerleşik yayıncı sunar. Ayrıca, özel yayıncıları da ESFLT:15'i uygulamak veya rahatlık ilkizerleri kullanmakla birlikte oluşturabilirsiniz.

Timer Publisher

Mevcut tarihi normal aralıklarla yaymak için aşağıdakiler kullanın. Hemen zamanlayıcıya başlamak için, callETHFLT:17.

let timerPublisher = Timer.publish(every: 1.0, on: .main, in: .common).autoconnect()

Yayıncı, ana run döngüsünde her saniye değer taşır.

URLSession Data Task Publisher

Ağ isteklerini yerine getiren bir yayıncı ile birlikte genişletilmişFLT:20'i bir araya getirin:

guard let url = URL(string: "https://api.example.com/data") else { return }
let publisher = URLSession.shared.dataTaskPublisher(for: url)

Bu yayıncı, tamamlanmak için bir tupleyuFLT:22 veya başarısızlık üzerine kuruludur.

Bildirim Merkezi Publisher

Herhangi bir bildirimi bir yayıncıya dönüştürün:

let notificationPublisher = NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)

Sistem olayları manuel olarak gözlemciler eklemeden tepki vermek için kullanışlı.

Sadece ve Geleceği

[[Dint:) Tek bir değer yayıyor ve sonra hemen tamamlandı. Bir yayıncıya sürekli test etmek veya sarmak için mükemmel:

let justPublisher = Just("Hello, Combine!")

[[Dörtücük olarak, daha sonra aboneler için sonucu tam olarak yerine getiren bir yayıncıdır:

let futurePublisher = Future<String, Error> { promise in
 // Perform async work, then call promise(.success(value)) or promise(.failure(error))
}

PassthroughSubject and CurrentValueSubject

Konular hem bir yayıncı hem de bir abone olarak hareket eder, size bir akışa değer katabilmenize izin verir.ETHFLT:29) mevcut değeri saklı tutmadan abonelere değer verir; 03.03.2012

let subject = PassthroughSubject<Int, Never>()
subject.send(1)
subject.send(2)

let currentValueSubject = CurrentValueSubject<String, Never>("initial")
currentValueSubject.send("updated")
print(currentValueSubject.value) // "updated"

Bir Yayıncıya Açıklama

Bir boru hattını aktifleştirmek için, en yaygın kullanılan a aboneye ihtiyacınız var.) ve [[DüzgÜye|35|

Lavabo Aboneliği

[[DÜŞÜNÜŞÜNÜŞÜŞÜŞÜŞÜŞÜŞÜŞÜŞÜNÜŞÜŞÜŞÜŞÜNÜŞÜNÜŞÜŞÜŞÜNÜŞÜNÜŞÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜ, alınan değerler ve tamamlanma olayları için kapalı alan bir eleme sunar:

let subscription = timerPublisher.sink { time in
 print("Timer fired at \(time)")
}

Ayrıca, aurFLT:36'u sağlayarak hataları da halledebilirsiniz:

publisher
 .sink(receiveCompletion: { completion in
 switch completion {
 case .finished:
 print("Stream finished")
 case .failure(let error):
 print("Error: \(error)")
 }
 }, receiveValue: { value in
 print("Received: \(value)")
 })

Assign Aboner

[[Dind|38||||Dint|s|d|x|x|x|s|x|s|t|s x|s x x|s x x x x x x |=)) veya ss.

class ViewModel {
 @Published var text: String = ""
}

let viewModel = ViewModel()
let publisher = Just("Hello")
let cancellable = publisher.assign(to: \.text, on: viewModel)
print(viewModel.text) // "Hello"

Özel Aboneler

Gelişmiş kullanım koşulları için, doğrudan protokol uygulayabilirsiniz. ancak bu nadiren gereklidir; [[Dönemli ve [[Dönemli) ve [[Dönemli|Dönemli) çoğu senaryoyu kaplar.

Data'yı Operatörlerle Dönüştürmek

Operatörler, basit bina bloklarından karmaşık boru hatları oluşturmanıza izin veren bir karışımdır. İşte en temel olanlardır:

Harita Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map Map

Bir kapanış kullanarak her yayılan değeri döndürür:

publisher
 .map { $0 * 2 }
 .sink { print($0) }

Filtre Filtre

Önli bir kanıt sağlayan değerler aracılığıyla geçiş yapın:

publisher
 .filter { $0.isMultiple(of: 2) }
 .sink { print("Even: \($0)") }

FlatMap

Düzenler çoklu iç yayıncılar tek bir akışa. Yaygın olarak her değer yeni bir asynchronous operasyonu tetikler:

let searchPublisher = searchTextPublisher
 .debounce(for: .milliseconds(300), scheduler: RunLoop.main)
 .removeDuplicates()
 .flatMap { text in
 return api.searchPublisher(for: text)
 }

Conleele

İki veya daha fazla yayıncıdan gelen son değerleri bir parçaya birleştirir. Yayıncıların herhangi biri yayıldığında yeni bir değer çıkarır:

Publishers.CombineLatest(usernamePublisher, passwordPublisher)
 .map { username, password in
 return username.count > 0 && password.count > 0
 }
 .assign(to: \.isEnabled, on: loginButton)

Zip

Birden çok yayıncıdan gelen Pairs değerleri, tüm yayıncıların çiftliği olmayan bir sonraki değeri yaymasını bekliyor:

Publishers.Zip(emailsPublisher, namesPublisher)
 .sink { email, name in
 print("\(name): \(email)")
 }

Merge

Aynı türün birden çok yayıncısından gelen Interears values from multiple Publisher of the same type into a single stream:

Publishers.Merge(leftPublisher, rightPublisher)
 .sink { print($0) }

Topla Topla Topla Topla

Buffers değerleri dizilere, bir kez buffer doldurmaları veya akış tamamlandığını belirtir:

publisher
 .collect(3) // emit arrays of 3 values
 .sink { print($0) }

Tartışma ve Throttle

[[DÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞ

textField.textPublisher
 .debounce(for: .seconds(0.3), scheduler: RunLoop.main)
 .sink { text in
 // Perform search after user stops typing
 }

Eklemme

Bir yayıncının ne kadar hata yayabileceğini açıklayan bir yayıncı türü başarısız olduğunda, abonelik sona erer. Hata-handling operatörlerinin hataları kurtarma veya dönüştürme hataları kullanması için kullanması gerekir.

Map deneyin veFilter'i deneyin

Dönüşüm kapatmanız atabilirse, [[DörtÜcretsiz veya İLDİZİYLEŞİ KAYNAKLARI:) Boru hattının atıldığı bir hata varsa başarısız olur:

publisher
 .tryMap { value in
 guard value > 0 else { throw InputError.invalid }
 return value * 2
 }

Catch Catch Catch

Alternatif bir yayıncı ile bir başarısızlık değiştirin. geri dönüş değerleri sağlamak için kullanışlı:

publisher
 .catch { error in
 return Just(0) // fallback value
 }

Yeniden Yeniden Yeniden Yeniden Yeniden Yeniden Yeniden Yeniden Yeniden

Otomatik olarak üst düzey yayıncıya, başarısız olursa belirtilen sayıda kez tekrar girişler:

publisher
 .retry(3)
 .sink(receiveCompletion: { ... }, receiveValue: { ... })

Error'un yerini veEmpty'yi değiştir

[[Din:60| Belirli bir değerle bir başarısızlık yerine getirir.]Ücretçinin herhangi bir şey yapmadan tam bir değer sunar.

Memory Management ve Cancellation

Her abonelik kaynakları tüketiyor ve hafıza sızıntılarından kaçınmak için uygun şekilde iptal edilmelidir.Eks:62) Bir tür optimize edilmiş bir kanal referans.

Mağaza bir koleksiyonda kullanılabilir, genellikle birFL:63), kendi nesne (örneğin, bir görüş kontrol cihazı) tamamen silinir. Örneğin:

private var cancellables = Set<AnyCancellable>()

func setupBindings() {
 publisher
 .sink { [weak self] value in
 self?.updateUI(value)
 }
 .store(in: &cancellables)
}

Ayrıca, abonelikleri sona erdirmek ve kaynakları salıveren bir cancellable üzerinde manuel olarak çağrılabilirsiniz.

Tamam Pratik Örnek: UI Updates ile Network Request

Gerçek dünya senaryosu yapalım: bir API'den kullanıcı verilerini getir, onu korkutmak ve SwiftUI görüşünü güncelle. Bu örnek hata işleme, operatörler ve thread yönetimi gösterir.

import SwiftUI
import Combine

struct User: Decodable, Identifiable {
 let id: Int
 let name: String
 let email: String
}

class UserViewModel: ObservableObject {
 @Published var users: [User] = []
 @Published var isLoading = false
 @Published var errorMessage: String? = nil

 private var cancellables = Set<AnyCancellable>()

 func fetchUsers() {
 isLoading = true
 errorMessage = nil

 guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else {
 errorMessage = "Invalid URL"
 isLoading = false
 return
 }

 URLSession.shared.dataTaskPublisher(for: url)
 .map { $0.data }
 .decode(type: [User].self, decoder: JSONDecoder())
 .receive(on: DispatchQueue.main)
 .sink(receiveCompletion: { [weak self] completion in
 self?.isLoading = false
 switch completion {
 case .finished:
 break
 case .failure(let error):
 self?.errorMessage = error.localizedDescription
 }
 }, receiveValue: { [weak self] users in
 self?.users = users
 })
 .store(in: &cancellables)
 }
}

Anahtar noktaları:

  • [[Din:67) yanıtın çiğ verilerini geri döndürür.
  • [[Din:68) Kombine JSON'u bölmek için bir işletim operatörü kullanır.Eğer dekoding başarısız olursa, boru hattı bir hatayla sona erer.
  • [[BİLM:69) UI güncelleştirmelerinin ana konu üzerinde gerçekleşmesini sağlar.
  • Aboneliği [[70-70|kullanıcının, yaşam döngüsünün görüntü modeline bağlar.
  • Hata, SwiftUI'de bir uyarıya bağlı olabilecek malum mülkiyet aracılığıyla yüzeylenmiştir.

Birleşin ve SwiftUI: Doğal Bir Ortaklık

SwiftUI'nin reaktif mimarisi, bir metin alanının girişine izin vermeden önce, arama sonuçlarını ve UI'yi otomatik olarak değiştirdikleri zaman SwiftUI'yi bilgilendiren yayıncılar oluşturmak için, görüşe ulaşmadan önce bir dizinleme işlemine izin verirsiniz. Örneğin, bir metin alanını iptal edebilirsiniz, sonra arama sonuçlarını ve UI'yi bir araya getirin.

SwiftUI ile birlikte bir araya gelmek, daha öngörülebilir ve test edilebilir koda yol açan manuel KVO veya delege kalıpları için ihtiyaçtır.

Diğer Reaktif Çerçeveler

Bir araya gelmeden önce, iOS geliştiricileri genellikle birkaç avantaja sahiptir: ilk parti entegrasyon, SwiftUI ve Foundation ile sorunsuz bir şekilde çalışabilirlik ve güçlü tip güvenlik. Ancak RxSwift daha büyük operatörlerin ve daha olgun bir ekosisteme sahiptir. iOS 13+'yı birleştiren yeni bir proje başlatırsanız, ilk parti entegrasyonu, önerilen bir sistemdir.

Birlikte Birlikte En İyi Uygulamalar

  • [FONT:0) Basit boru hatları tut[[Dönetici: 1) Kompleks zincirler onları daha küçük, gerekirse yayıncılar olarak parçalayabilirler.
  • [FONT=0]Manage abonelikleri dikkatle - Her zaman mağaza kullanılabilir ve kullanım döngüsüni kullanarak tutabilirsiniz.(75) Bu yakalamayı başaran kapanışlarda.
  • [FONT:0) Uygun programlayıcıları kullanın - UI güncelleştirmeleri için ana kuyruka geçmek için [[77| ve [[Dönderler:78) arka kuyruklarda ağır iş yapmak için.
  • [FONT:0)PreferENGT:79 Basit mülk bağlayıcıları için[[DÜT:1) - Patter kodu azaltır.
  • [[Düzücüler:0) Boru hatlarınızı test edin[Dönetici:0) - Kombinasyon testi mükemmeldir, çünkü yayıncıları [[FONTT:80| veya [[END:81) ile oluşturabilir ve beklentileri kullanarak doğrulayın.
  • [FONT=0) Geri basınçtan haberdar olun[[Dönetici:0)[Dönetici:0))))))))[Döneticileri, akışları kontrol etmelerini sağlar. Operatörler [[Döneticiler:82) veya [[Döneticiler:83|işmanlık işlemine geldiğinde yardımcı olabilir.

Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç

iOS geliştiricilerinin aminkron olayları ve veri akışlarını nasıl işlediği devrime yol açabilir. Yayıncılar, aboneler ve operatörler, koncise, reaktif boru hatları oluşturmak ve SwiftUI ile ilgili basit örneklerle başlamak, o zaman yavaş yavaş yavaş yavaş yavaş kullanıcı etkileşimleri ve dış veri kaynaklarına yanıt veren uygulamaları oluşturmak için size yardımcı olacaktır.

For further reading, consult the official Apple Combine documentation, Hacking with Swift’s Combine introduction, or Ray Wenderlich’s Combine book for deeper dives.