- Published on
Swift-da Class-lardan qanday foydalanish kerak
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
Hammaga xush kelibsiz! Bu videoda biz class-larni ko'rib chiqamiz. O'tgan ikki videoda struct va enum-larni o'rgandik β ular ikkalasi ham value type edi. Endi esa reference type bo'lgan class-larga o'tamiz.
Reference type-lar value type-lardan tubdan farq qiladi va shu sababli ulardan foydalanish ham biroz boshqacha. Aslida, class bilan ishlash struct'ga qaraganda biroz osonroq. Bu class-ni doim afzal ko'rish kerak degani emas β ko'p hollarda struct yaxshiroq tanlov. Lekin ayrim hollarda class ishlatish majburiy bo'ladi.
Stack vs Heap β qisqa eslatma
// Struct-lar:
// - Tezkor
// - Stack-da saqlanadi
// - Value type β nusxa ko'chiriladi va mutatsiya qilinadi
// Class-lar:
// - Struct-larga qaraganda sekinroq (lekin baribir juda tez)
// - Heap-da saqlanadi
// - Heap dasturning barcha thread-lari o'rtasida umumiy
// - Reference type β xotiradagi obyektga ishora qiladi
// va shu obyektni o'zgartiradi, yangi nusxa yaratmaydi
Class yaratilganda u xotirada (Heap-da) saqlanadi. Bizda esa shu xotiradagi obyektga pointer (ishora) bo'ladi. Biz obyektni o'zgartirmoqchi bo'lganimizda uni ko'chirmay, to'g'ridan-to'g'ri xotiradagi asl nusxasini o'zgartiramiz.
Class yaratish
Keling, oddiy view model yarataylik. ViewModel β bu MVVM (Model-View-ViewModel) arxitekturasidan kelgan tushuncha. Swift UI-da view model odatda class bo'ladi.
class ScreenViewModel {
var title: String
var showButton: Bool
init(title: String, showButton: Bool) {
self.title = title
self.showButton = showButton
}
}
Struct va class init farqi
Struct-da implicit init bor edi β biz init yozmasak ham kompilyator uni o'zi tushunardi. Class-da esa bunday imkoniyat yo'q, shuning uchun init-ni o'zimiz yozishimiz shart:
// Struct β implicit init mavjud, yozmasak ham ishlaydi
struct CarModel {
var brand: String
var model: String
}
// Class β init yozilmasa kompilyator xato beradi
class ScreenViewModel {
var title: String
var showButton: Bool
// Bu init bo'lmasa: "Class has no initializers" xatosi
init(title: String, showButton: Bool) {
self.title = title
self.showButton = showButton
}
}
Yoki xususiyatlarga default qiymat bersak, init yozmasak ham bo'ladi:
class ScreenViewModel {
var title: String = "Salom"
var showButton: Bool = true
// init kerak emas
}
Deinit β obyektni yo'q qilish
Class-ning struct-dan yana bir farqi β deinit mavjudligi:
class ScreenViewModel {
var title: String
var showButton: Bool
init(title: String, showButton: Bool) {
self.title = title
self.showButton = showButton
}
deinit {
// Bu kod obyekt xotiradan o'chirilayotganda ishlaydi
}
}
// Struct-larda deinit YO'Q
// Chunki struct-lar value type β har o'zgarishda yangi nusxa yaratiladi
// Class-larda esa bir xil obyekt tirik turadi, faqat ichidagi qiymatlar o'zgaradi
deinit kam ishlatiladi. Ko'pgina ilovalar yozilganda umuman kerak bo'lmasligi mumkin, lekin u faqat class-larga xos ekanini bilish muhim.
Instance yaratish va qiymat o'zgartirish
// Class instance yaratish
let myViewModel = ScreenViewModel(title: "Ekran 1", showButton: true)
E'tibor bering β bu yerda let ishlatildi, var emas. Struct-larda qiymatni o'zgartirish uchun var kerak edi. Class-larda esa obyektning o'zi o'zgarmaydi β ichidagi ma'lumotlar o'zgaradi:
let myViewModel = ScreenViewModel(title: "Ekran 1", showButton: true)
// Bu ishlaydi β obyektning o'zi emas, ichidagi qiymat o'zgarmoqda
myViewModel.showButton = false
// Izoh:
// myViewModel β bu xotiradagi obyektga ishora (pointer)
// Pointer o'zgarmayapti (shuning uchun let)
// Xotiradagi obyekt ichidagi qiymat o'zgarmoqda
Bu struct bilan ishlashdan tubdan farq qiladi β struct-da mutating funksiyalar yozib, yangi nusxa yaratishimiz kerak edi.
Class ichida funksiyalar yozish
Qiymatlarni class tashqarisidan o'zgartirish yaxshi amaliyot emas. Buning o'rniga o'zgartirishlarni class ichidagi funksiyalar orqali amalga oshirish kerak:
class ScreenViewModel {
private(set) var title: String
private(set) var showButton: Bool
init(title: String, showButton: Bool) {
self.title = title
self.showButton = showButton
}
func hideButton() {
showButton = false
}
func updateShowButton(newValue: Bool) {
showButton = newValue
}
deinit {
// Obyekt xotiradan o'chirilayotganda ishlaydi
}
}
private(set) nima beradi?
let myViewModel = ScreenViewModel(title: "Ekran 1", showButton: true)
// Bu ishlaydi β qiymatni olish mumkin
let currentValue = myViewModel.showButton
// Bu XATO beradi β tashqaridan qiymat o'rnatib bo'lmaydi
myViewModel.showButton = false // Xato!
// To'g'ri yo'l β class ichidagi funksiya orqali
myViewModel.hideButton()
myViewModel.updateShowButton(newValue: false)
Bu clean code β toza kod yozish amaliyoti. Ma'lumotlarni o'zgartirish mantig'i faqat class ichida bo'lishi kodni tushunarli va xavfsiz qiladi.
Struct vs Class β qisqa taqqoslash
| Xususiyat | Struct | Class |
|---|---|---|
| Xotirada joyi | Stack | Heap |
| Turi | Value type | Reference type |
| Tezlik | Tezroq | Biroz sekinroq |
| Thread xavfsizligi | Ha | Yo'q (ehtiyot kerak) |
| Implicit init | Ha | Yo'q |
| Deinit | Yo'q | Ha |
| Qiymat o'zgartirish | Mutating / yangi nusxa | Bevosita obyekt ichida |
| O'zgaruvchi turi | var kerak | let bilan ham o'zgaradi |
Xulosa
Class-lar struct-larga qaraganda ishlatish jihatidan biroz osonroq β mutating yozmasak ham bo'ladi, let bilan ham ichidagi qiymatlarni o'zgartirish mumkin. Lekin bu class-ni doim tanlash kerak degani emas. Struct-lar tezroq, thread-safe va xotiradan samaraliroq foydalanadi.
Keyingi videolarda struct, enum va class-larni haqiqiy stsenariyda qo'llaymiz. Undan oldin esa private kalit so'zini chuqurroq o'rganamiz.
Rahmat, men Nick, bu Swiftful Thinking va keyingi videoda ko'rishguncha!