SwiftUI vs UIKit
Apple'ın modern deklaratif framework'ü SwiftUI ile battle-tested UIKit arasındaki kapsamlı karşılaştırma. 2025'te hangi framework'ü seçmelisiniz?
Reaktif programlama paradigması — stream'ler, operator'lar, subscriber'lar
Swift 5.5 native eşzamanlılık — okunabilir, güvenli, modern
// Combine - Canlı arama ile form validasyonu
import Combine
import Foundation
class SearchViewModel: ObservableObject {
@Published var searchText = ""
@Published var results: [String] = []
@Published var isLoading = false
@Published var errorMessage: String?
private var cancellables = Set<AnyCancellable>()
private let searchService: SearchService
init(searchService: SearchService) {
self.searchService = searchService
setupSearch()
}
private func setupSearch() {
$searchText
.debounce(for: .milliseconds(300), scheduler: RunLoop.main)
.removeDuplicates()
.filter { $0.count >= 2 }
.handleEvents(receiveOutput: { [weak self] _ in
self?.isLoading = true
self?.errorMessage = nil
})
.flatMap { [weak self] query -> AnyPublisher<[String], Never> in
guard let self else { return Just([]).eraseToAnyPublisher() }
return self.searchService.search(query: query)
.catch { [weak self] error -> Just<[String]> in
self?.errorMessage = error.localizedDescription
return Just([])
}
.eraseToAnyPublisher()
}
.receive(on: DispatchQueue.main)
.sink { [weak self] results in
self?.isLoading = false
self?.results = results
}
.store(in: &cancellables)
}
}// Async/Await - Paralel API çağrısı ve hata yönetimi
import Foundation
// Actor ile thread-safe cache
actor NetworkCache {
private var cache: [URL: Data] = [:]
func get(_ url: URL) -> Data? { cache[url] }
func set(_ url: URL, data: Data) { cache[url] = data }
}
struct UserDashboard {
let user: User
let posts: [Post]
let notifications: [Notification]
}
@MainActor
class DashboardViewModel: ObservableObject {
@Published var dashboard: UserDashboard?
@Published var isLoading = false
@Published var error: Error?
private let cache = NetworkCache()
func loadDashboard(userId: String) async {
isLoading = true
error = nil
do {
// async let ile paralel yükleme
async let user = fetchUser(id: userId)
async let posts = fetchPosts(userId: userId)
async let notifications = fetchNotifications(userId: userId)
// Hepsi aynı anda başladı, hepsini bekliyoruz
dashboard = UserDashboard(
user: try await user,
posts: try await posts,
notifications: try await notifications
)
} catch {
self.error = error
}
isLoading = false
}
private func fetchUser(id: String) async throws -> User {
let url = URL(string: "https://api.example.com/users/\(id)")!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(User.self, from: data)
}
private func fetchPosts(userId: String) async throws -> [Post] {
let url = URL(string: "https://api.example.com/users/\(userId)/posts")!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode([Post].self, from: data)
}
private func fetchNotifications(userId: String) async throws -> [Notification] {
let url = URL(string: "https://api.example.com/users/\(userId)/notifications")!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode([Notification].self, from: data)
}
}2025'te yeni projeler için Async/Await tercih edin — daha okunabilir, daha az hata eğilimli ve Apple'ın aktif olarak geliştirdiği yön bu. Combine'ı kompleks reaktif akışlar (canlı arama, form validasyon pipeline'ları) için kullanmaya devam edin. İkisi birlikte mükemmel çalışır.
Kademeli geçiş önerilir. Yeni özellikler async/await ile yazılabilir; mevcut Combine kodu çalışmaya devam eder. AsyncPublisher ile Combine stream'lerini async sequence'e dönüştürmek mümkün.