Swift, Objective-C'nin gücünü modern dillerin güvenliğiyle birleştiren Apple'ın programlama dilidir. Diğer birçok dilden farklı olarak Swift, benzersiz yapılar sunar: otomatik kopyalama ile değer türleri, derleyici düzeyinde izolasyon ile Actors, özellik mantığını yeniden kullanmak için Property Wrappers ve klasik kalıtıma alternatif olarak Protokol Odaklı Programlama.Apple Swift Dokümantasyonu'na göre, bu özellikler kodu daha güvenli ve verimli hale getirir.
Önemli Noktalar
Swift'te struct bir değer türüdür, class ise bir referans türüdür. Bu temel fark, atama, fonksiyonlara geçirme ve bellek yönetimi sırasındaki davranışı belirler. Struct her atamada tamamen kopyalanır, class referansla iletilir — yalnızca heap'teki nesneye işaretçi kopyalanır.
Struct otomatik olarak değer semantiğini uygular — her örnek bağımsızdır. Bir struct özelliğinin değiştirilmesi yalnızca var ile mümkündür ve özellikleri değiştiren metotlar mutating olarak işaretlenmelidir. Struct kalıtımı desteklemez ancak protokollere uyum sağlayabilir. Swift'in standart kütüphanesi String, Array, Dictionary, Int, Bool için struct kullanır — tüm temel türler değer türleridir.
struct User {
let id: Int
var name: String
mutating func updateName(_ newName: String) {
name = newName
}
}
var user1 = User(id: 1, name: "Alice")
var user2 = user1
user2.updateName("Bob")
// user1.name === "Alice", user2.name === "Bob"
// Tam kopya — bağımsız örnekler
Class heap'te depolanır ve referans eşitliğini destekler. Birden çok değişken aynı nesneye referans verebilir, bir referans üzerinden yapılan değişiklikler diğer tüm referanslardan görülebilir. Class kalıtımı destekler, metot geçersiz kılmaya (override) izin verir, kaynak temizliği için deinit'e sahiptir. Swift'te struct'tan daha az kullanılır — Apple, struct ile başlamayı ve yalnızca kalıtım veya referans semantiği gerektiğinde class'a geçmeyi önerir.
class Car {
let model: String
var speed: Int
init(model: String, speed: Int) {
self.model = model
self.speed = speed
}
func accelerate(_ amount: Int) {
speed += amount
}
}
let car1 = Car(model: "Tesla", speed: 0)
let car2 = car1
car2.accelerate(50)
// car1.speed === 50, car2.speed === 50
// Aynı referans — değişiklikler her yerde görünür
struct ve class arasındaki seçim veri semantiğine bağlıdır. Yapılandırmalar, veri modelleri ve durumlar için struct kullanın — kopyalama daha güvenli ve öngörülebilirdir. Kimliği olan nesneler (kullanıcı oturumu, veritabanı bağlantısı) ve kalıtım gerektiğinde class kullanın.
Actor, değiştirilebilir durumunu eşzamanlı erişime karşı koruyan bir referans türüdür. Swift derleyicisi, actor değişkenlerine yalnızca aynı actor bağlamından erişilebileceğini garanti eder — herhangi bir dış erişim derleme hatasına neden olur. Bu, manuel kilitler olmadan dil düzeyinde veri yarışlarını önler.
Tüm actor özellikleri ve metotları varsayılan olarak izole edilmiştir. Dışarıdan bir actor metodunu çağırmak await gerektirir — Swift yürütmeyi actor'e geçirir ve geri döndürür. Actor erişimi sıralı olarak senkronize eder: farklı görevlerden gelen istekler sıraya alınır. Bu, actor içinde tutarlı durum sağlar. İzole olmayan metotlar (nonisolated) await olmadan çağrılabilir ancak değiştirilebilir özelliklere erişemez.
actor BankAccount {
private var balance: Double
init(initialBalance: Double) {
balance = initialBalance
}
func deposit(amount: Double) {
balance += amount
}
func withdraw(amount: Double) throws {
guard balance >= amount else {
throw BankError.insufficientFunds
}
balance -= amount
}
nonisolated func accountInfo() -> String {
return "Banka Hesabı"
}
}
let account = BankAccount(initialBalance: 1000)
await account.deposit(amount: 500)
// balance = 1500 — atomik, yarış durumu yok
Actor, birden çok görevin eşzamanlı olarak veri okuyup yazdığı durum yöneticileri, önbellekler ve ağ hizmetleri için kullanışlıdır. NSLock veya DispatchQueue ile manuel senkronizasyonun aksine, actor derleme zamanında kontrol edilir — hata yapmak imkansızdır. İzolasyon hataları çalışma zamanında değil, derleme zamanında ortaya çıkar.
Property Wrapper, bir özelliğin bildirimini değiştirmeden ona davranış ekleyen bir ek açıklamadır. SwiftUI ve Combine, görünüm durumunu yönetmek için yerleşik sarmalayıcılar sağlar. Derleyici, özellik erişimini sarmalayan, gözlem, senkronizasyon veya dönüştürme mantığı ekleyen kod üretir.
@Published, ObservableObject'e uyum sağlayan sınıflarda değişiklikleri otomatik olarak yayınlamak için kullanılır. Combine aboneleri her güncellemede bildirim alır. @State, SwiftUI görünümünün yerel durumudur. @State değiştiğinde SwiftUI görünümü otomatik olarak yeniden çizer. @Binding, verilere sahip olmadan üst ve alt görünüm arasında çift yönlü bağlantı oluşturur.
import SwiftUI
import Combine
@main
struct CounterApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class CounterViewModel: ObservableObject {
@Published var count: Int = 0
func increment() {
count += 1
}
}
struct ContentView: View {
@State private var greeting: String = "Merhaba"
@StateObject private var viewModel = CounterViewModel()
var body: some View {
VStack {
CounterDisplay(count: $viewModel.count)
Text(greeting)
Button("Arttır", action: viewModel.increment)
}
}
}
struct CounterDisplay: View {
@Binding var count: Int
var body: some View {
Text("Sayı: \(count)")
}
}
Özel Property Wrapper'lar @propertyWrapper ve wrappedValue alanına sahip bir yapı kullanılarak oluşturulur. Bu, doğrulama, normalleştirme, UserDefaults depolama gibi mantığın yeniden kullanılmasını sağlar. Property Wrapper'lar tekrar eden kodu önemli ölçüde azaltır ve ek açıklama yoluyla geliştiricinin niyetini açık hale getirir.
@propertyWrapper
struct Clamped<T: Comparable> {
private var value: T
let range: ClosedRange<T>
init(wrappedValue: T, range: ClosedRange<T>) {
self.range = range
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
}
var wrappedValue: T {
get { value }
set { value = min(max(newValue, range.lowerBound), range.upperBound) }
}
}
struct Settings {
@Clamped(range: 0...100) var volume: Int = 50
}
var s = Settings()
s.volume = 150
// s.volume === 100 — değer otomatik olarak sınırlandı
Generics, tür güvenliğini kaybetmeden esnek kod yazmak için Swift'in güçlü bir mekanizmasıdır. Genel işlevler ve türler, kısıtlamaları karşılayan herhangi bir türle çalışır. Protokol Odaklı Programlama (POP), protocol + extension'ın klasik sınıf kalıtımının yerini aldığı ve davranış kompozisyonu sağlayan bir Swift paradigmasıdır.
Swift, protokollerle (where cümleleri) genel parametreleri kısıtlamaya izin verir. İlişkili türe sahip protokol, protokoller için genel eşdeğerdir: somut tür, uyum anında belirlenir. Bu, tür güvenli koleksiyonlar ve algoritmaların temelidir. Swift'in standart kütüphanesi Generics'i aktif olarak kullanır: Array, Dictionary, Optional — hepsi genel türlerdir.
protocol Cacheable {
associatedtype Key: Hashable
associatedtype Value
func get(_ key: Key) -> Value?
mutating func set(_ value: Value, for key: Key)
}
struct MemoryCache<K: Hashable, V>: Cacheable {
private var storage: [K: V] = [:]
typealias Key = K
typealias Value = V
func get(_ key: K) -> V? {
return storage[key]
}
mutating func set(_ value: V, for key: K) {
storage[key] = value
}
}
func firstMatch<T: Equatable>(in array: [T], target: T) -> Int? {
for (index, item) in array.enumerated() {
if item == target {
return index
}
}
return nil
}
let numbers = [10, 20, 30, 40]
let index = firstMatch(in: numbers, target: 30)
// index === 2 — tüm Equatable türleri için tek bir genel metot
Protokol extension'ı POP'un ana mekanizmasıdır. Bir extension'da protokol metotlarının varsayılan uygulaması sağlanabilir. Protokole uyum sağlayan türler bu uygulamayı ücretsiz alır ve gerektiğinde geçersiz kılabilir. Bu, sınıf kalıtımı olmadan davranış hiyerarşileri oluşturmayı sağlar — Swift'te bulunmayan çoklu kalıtıma bir alternatif.
protocol Drivable {
var speed: Double { get set }
func drive()
}
extension Drivable {
func drive() {
if speed > 0 {
print("\(speed) km/s hızla sürüş")
}
}
}
struct Bicycle: Drivable {
var speed: Double = 15
}
struct Plane: Drivable {
var speed: Double = 900
func drive() {
print("\(speed) km/s hızla uçuş")
}
}
let bike = Bicycle()
bike.drive() // "15.0 km/s hızla sürüş" — varsayılan
let plane = Plane()
plane.drive() // "900.0 km/s hızla uçuş" — geçersiz kılındı
Extension ile POP, birden çok protokol aracılığıyla kompozisyon sağlar — bir tür birden çok protokole uyum sağlayabilir ve uygulamalarını alabilir. Bu, tüm hiyerarşinin sabit olduğu tek sınıf kalıtımından daha esnektir. Swift'in standart kütüphanesi POP üzerine inşa edilmiştir: CustomStringConvertible, Equatable, Hashable, Codable — hepsi extension'a sahip protokollerdir.
Enum Swift'te diğer dillere göre önemli ölçüde daha güçlü bir yapıdır. Her durum ilişkili değerlere sahip olabilir — herhangi bir türden rastgele veri kümesi. Extension ve pattern matching ile birleştiğinde enum, durumları, işlem sonuçlarını ve sonlu durum makinelerini modellemenin temeli haline gelir.
İlişkili değerler, her durumun benzersiz veriler depolamasına izin verir. Örneğin, loading durumu veri içermez, success sonucu içerir, failure bir hata içerir. Switch ile pattern matching, ilişkili değerleri çıkarır ve her durumu işler. Derleyici kapsamlılığı kontrol eder (exhaustive switch) — bu unutulan durumları ortadan kaldırır.
enum NetworkResult<T> {
case loading
case success(T)
case failure(Error)
}
enum MediaFile {
case image(url: URL, width: Int, height: Int)
case video(url: URL, duration: Double)
case audio(url: URL, bitrate: Int)
}
func handle(_ result: NetworkResult<String>) {
switch result {
case .loading:
print("Yükleniyor...")
case .success(let data):
print("Alındı: \(data)")
case .failure(let error):
print("Hata: \(error.localizedDescription)")
}
}
let file = MediaFile.video(url: URL(string: "https://example.com/video.mp4")!, duration: 120)
if case .video(let url, let duration) = file {
print("Video \(url) süre \(duration)s")
}
Swift, enum için extension aracılığıyla metot, hesaplanmış özellik ve protokol uyumu eklemeye izin verir. Bu, orijinal bildirimi değiştirmeyi gerektirmez — kod temiz ve modüler kalır. Extension'daki metotlar ilişkili değerlerle çalışabilir, türetilmiş verileri hesaplayabilir ve iş mantığını uygulayabilir.
extension MediaFile {
var fileName: String {
switch self {
case .image(let url, _, _),
.video(let url, _),
.audio(let url, _):
return url.lastPathComponent
}
}
var description: String {
switch self {
case .image(_, let w, let h):
return "Resim \(w)x\(h)"
case .video(_, let d):
return "Video \(d)s"
case .audio(_, let b):
return "Ses \(b) kbps"
}
}
}
extension MediaFile: Equatable {
static func == (lhs: MediaFile, rhs: MediaFile) -> Bool {
return lhs.fileName == rhs.fileName
}
}
let files: [MediaFile] = [file]
files.forEach { print($0.description) }
// "Video 120.0s"
İlişkili değerler + Extension ile Enum, Kotlin'deki sealed sınıfların veya diğer dillerdeki ayrımcı birleşimlerin yerine geçer. Swift bu kombinasyonu Result (standart kütüphanede standart bir tür), Optional (Optional, .none ve .some ile bir enum'dur) ve SwiftUI'de durum yönetimi için kullanır. Pattern matching, tüm durumların işlenmesini garanti eder — çalışma zamanı hataları imkansızdır.
Sıkça Sorulan Sorular
Struct — değer türü, atamada kopyalanır, kalıtımı desteklemez. Class — referans türü, referansla iletilir, kalıtım, deinit ve kimlik kontrolünü (===) destekler. Apple, struct ile başlamayı ve yalnızca referans semantiği gerektiğinde class'a geçmeyi önerir.
Actor — thread güvenli referans türü. Derleyici, farklı bağlamlardan değiştirilebilir duruma eşzamanlı erişimi engeller. Birden çok görev tarafından erişilen durum yöneticileri, önbellekler ve hizmetler için Actor kullanın. Actor metotlarını çağırmak await gerektirir.
Başlıcaları: @State — yerel görünüm durumu; @Binding — sahiplik olmadan veri bağlantısı; @Published — ObservableObject'te değişiklik yayını; @StateObject — ObservableObject sahipliği; @EnvironmentObject — ortamdan bağımlılık. Özel sarmalayıcılar @propertyWrapper ile oluşturulur.
POP — sınıf kalıtımı yerine protocol + extension'ın davranışı tanımladığı bir paradigmadır. Bir tür birden çok protokole uyum sağlar ve uygulamalarını ücretsiz alır. Bu, kalıtım yerine kompozisyondur — daha esnek ve güvenlidir. Swift'in standart kütüphanesi (Equatable, Codable) POP üzerine inşa edilmiştir.
Swift'te enum ilişkili değerleri destekler — her durum farklı türlerde rastgele veri depolayabilir. Pattern matching (switch) ile birleştiğinde, durumlar, hatalar ve Domain-Driven Design için güçlü bir model sağlar. Optional ve Result, ilişkili değerlere sahip standart Swift enum'larıdır.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.