paint-brush
Swift init(), bir marta va hamma uchuntomonidan@kfamyn
Yangi tarix

Swift init(), bir marta va hamma uchun

tomonidan Kiryl Famin19m2025/03/21
Read on Terminal Reader

Juda uzoq; O'qish

Ushbu maqola Swift ishga tushiruvchilari uchun zarur bo'lgan barcha narsalarni qamrab oladi: a'zolar bo'yicha, tayinlangan, qulaylik, qulaylikni bekor qilish; zarur foydalanish holatlari; parametrsiz UIView() ishga tushirgich; kompilyator yordami; muvaffaqiyatsiz init, enum init va boshqalar.
featured image - Swift init(), bir marta va hamma uchun
Kiryl Famin HackerNoon profile picture
0-item
1-item

Kirish

Salom! Mening ismim Kiril Famin va men iOS dasturchisiman.


Bugun men Swift-da initsializatorlar kabi oddiy mavzuni yaxshilab ko'rib chiqmoqchiman. Ko'rinib turgan soddaligiga qaramay, ba'zida ushbu mavzuni to'liq tushunmaslik, tafsilotlarni o'rganmasdan tezda tuzatmoqchi bo'lgan umidsizlikka olib keladigan xatolarga olib keladi.


Ushbu maqolada biz initsializatorlar bilan bog'liq barcha narsalarni ko'rib chiqamiz, jumladan:


  • Maxsus tuzilmani belgilashda strukturaning a'zolar bo'yicha ishga tushirgichini qanday saqlash kerak

  • Nima uchun sinflarda initsializator yozish har doim ham kerak emas

  • Nima uchun super.init qo'ng'iroq qilish har doim ham belgilangan ishga tushirgichda talab qilinmaydi

  • Nima uchun super.init qo'ng'iroq qilishdan oldin kichik sinfning barcha maydonlari to'ldirilishi kerak

  • Pastki sinflarda minimal bekor qilingan barcha ota-initsializatorlarga qanday kirish mumkin

  • required ishga tushirgich kerak bo'lganda

  • Nima uchun UIView.init() har doim parametrlarsiz chaqiriladi, lekin init(frame:) va init(coder:) bekor qilinadi


...va boshqalar. Ammo keling, buni bosqichma-bosqich ko'rib chiqaylik.

Mundarija

Asoslar

Tuzilmalar

  • A'zolar bo'yicha ishga tushirgich
  • Ixtiyoriy
  • var vs let
  • A'zolar bo'yicha ishga tushirgichni saqlab qolish

Sinflar

  • Belgilangan ishga tushirgich
  • Qulaylik ishga tushirgich
  • Superklassning qulaylik ishga tushirgichini saqlab qolish
  • Bekor qilish sonini minimallashtirish
  • Kompilyator yordami
  • required boshlang'ich: generics, protokollar, Self() , final
  • UIView() parametrlarsiz

Muhtaram eslatmalar

  • Muvaffaqiyatsiz ishga tushirish
  • Enums

Xulosa

Tegishli havolalar

Asoslar

Apple kompaniyasining Swift dasturlash tili (6) qo'llanmasida (aytmoqchi, initsializatorlar uchun hayratlanarli darajada batafsil) shunday deyilgan:


Initializatsiya - bu sinf, tuzilma yoki ro'yxatga olish namunasini foydalanish uchun tayyorlash jarayoni. Bu jarayon oʻsha namunadagi har bir saqlangan xususiyat uchun boshlangʻich qiymatni oʻrnatish va yangi namuna foydalanishga tayyor boʻlgunga qadar talab qilinadigan boshqa sozlash yoki ishga tushirishni oʻz ichiga oladi.


Siz ushbu ishga tushirish jarayonini ma'lum turdagi yangi namunani yaratish uchun chaqirilishi mumkin bo'lgan maxsus usullarga o'xshash initsializatorlarni belgilash orqali amalga oshirasiz. Objective-C initsializatorlaridan farqli o'laroq, Swift ishga tushirgichlari qiymat qaytarmaydi. Ularning asosiy roli yangi turdagi namunalarni birinchi marta ishlatishdan oldin to'g'ri ishga tushirishni ta'minlashdir.


Xo'sh, men bu erda hech narsa qo'shishim shart emas deb o'ylayman.

Tuzilmalar

Keling, strukturani ishga tushirishni muhokama qilishdan boshlaylik. Bu juda oddiy, chunki meros yo'q, lekin siz hali ham bilishingiz kerak bo'lgan ba'zi qoidalar mavjud.

A'zolar bo'yicha ishga tushirgich

Keling, oddiy tuzilmani yozamiz:

 struct BankAccount { let amount: Double let isBlocked: Bool } let bankAccount = BankAccount(amount: 735, isBlocked: Bool)


E'tibor bering, biz boshlang'ichni aniq e'lon qilmasdan strukturani ishga tushira oldik. Buning sababi, tuzilmalar kompilyator tomonidan yaratilgan a'zolar bo'yicha ishga tushirgichni oladi. Bu faqat tuzilmalar uchun ishlaydi.


Refactor → Generate Memberwise initializer ni tanlab, uning qanday ko'rinishini ko'rishingiz mumkin:


Xcode-da a'zolar bo'yicha ishga tushirgich yaratilmoqda


 init(amount: Double, isBlocked: Bool) { self.amount = amount self.isBlocked = isBlocked }


Imzodan hamma parametrlar uchun qiymatlarni bermaslik kompilyatsiya xatosiga olib kelishini tushunish oson:

 let bankAccount = BankAccount(amount: 735) // ❌ Missing argument for parameter 'isBlocked' in call


Biroq, agar siz talab qilinadigan argumentlar sonini kamaytirmoqchi bo'lsangiz, maxsus ishga tushirgichni belgilashingiz mumkin:

 init(amount: Double, isBlocked: Bool = false) { self.amount = amount isBlocked = isBlocked } let bankAccount = BankAccount(amount: 735) // ✅


Esda tutingki, agar isBlocked to'ldirilmagan bo'lsa, bu kompilyatsiya xatosiga olib keladi, chunki barcha struktura xususiyatlari initsializerda to'ldirilishi kerak .

Majburiy emas, var vs let

Maydonni aniq to'ldirish shart bo'lmagan yagona holat - bu ixtiyoriy ( ? ) o'zgaruvchi ( var ). Bunday hollarda maydon sukut bo'yicha nil ga aylanadi:

 struct BankAccount { let amount: Double var isBlocked: Bool? init(amount: Double) { self.amount = amount } } let bankAccount = BankAccount(amount: 735) // ✅


Ammo, agar biz bu holatda a'zolar bo'yicha ishga tushirgichdan foydalanishga harakat qilsak, biz kompilyatsiya xatosini olamiz:

 let bankAccount = BankAccount( amount: 735, isBlocked: false ) // ❌ Extra argument 'isBlocked' in call

A'zolar bo'yicha ishga tushirgichni saqlab qolish

Buning sababi, maxsus ishga tushirgichni e'lon qilish a'zolar bo'yicha ishga tushirgichni olib tashlaydi. Uni aniq belgilash hali ham mumkin, lekin u avtomatik ravishda mavjud bo'lmaydi.


Biroq, a'zolar bo'yicha ishga tushirgichni saqlab qolish uchun kichik hiyla bor: extension maxsus ishga tushirgichni e'lon qilish .

 struct BankAccount { let amount: Double var isBlocked: Bool? } extension BankAccount { init(amount: Double) { self.amount = amount } } let barclaysBankAccount = BankAccount(amount: 735) // ✅ let revolutBankAccount = BankAccount(amount: 812, isBlocked: false) // ✅ print(barclaysBankAccount.isBlocked) // nil print(barclaysBankAccount.isBlocked) // false


Tuzilmalar uchun xulosa

  • Barcha maydonlar ishga tushirgichda to'ldirilishi kerak
  • Ixtiyoriy var maydonlari sukut bo'yicha nil
  • Strukturalar a'zolar bo'yicha bepul ishga tushirgich oladi
  • Agar maxsus ishga tushirgich e'lon qilingan bo'lsa, a'zolar bo'yicha ishga tushirgich yo'qoladi
  • Strukturaning a'zolar bo'yicha ishga tushirgichini saqlab qolish uchun extension moslashtirilganni belgilang

Sinflar

Belgilangan ishga tushirgich

Sinf uchun asosiy ishga tushirgich belgilangan ishga tushirgichdir . U ikkita maqsadga xizmat qiladi:

  1. Barcha maydonlar to'ldirilganligini ta'minlaydi
  2. Agar sinf meros bo'lib qolgan bo'lsa, u superklassni ishga tushiruvchini chaqiradi
 class Animal { var name: String init(name: String) { self.name = name } } class Dog: Animal { var breed: String var name: String init(breed: String, name: String) { self.breed = breed super.init(name: name) } }


super.init ga qo'ng'iroq qilishdan oldin barcha maydonlar to'ldirilishi kerak . Buning sababi shundaki, superklassni ishga tushiruvchi subklass tomonidan bekor qilingan usullarni chaqirishi mumkin, bu esa to'ldirilmagan pastki sinf xususiyatlariga kirishi mumkin.

 class Animal { var age: Int init(age: Int) { self.age = age getInfo() } func getInfo() { print("Age: ", age) } } class Dog: Animal { var breed: String init(breed: String, age: Int) { self.breed = breed // imagine we haven't done this super.init(age: age) } override func getInfo() { print("Age: ", age, ", breed: ", breed) } }


Shunday qilib, agar self.breed = breed o'rnatmaganimizda, biz ish vaqti xatosiga duch kelgan bo'lardik, chunki Animal initsializer Dog sinfidan bekor qilingan getInfo() usulini chaqirgan bo'lar edi. Bu usul hali to'ldirilmagan breed mulkiga kirishga harakat qiladi.


Tuzilmalardan farqli o'laroq, sinflar yashirin a'zolar inisializerini olmaydilar. Agar ishga tushirilmagan xususiyatlar mavjud bo'lsa, kompilyatsiya xatosi yuzaga keladi:

 class Animal { // ❌ Class 'Animal' has no initializers var age: Int }
 class Animal { // ✅ var age: Int = 0 }
 class Animal { // ✅ var age: Int? }
 class Animal { } // ✅

Qulaylik ishga tushirgich

Sinflar, shuningdek, qulaylik yaratuvchisiga ega bo'lishi mumkin. Belgilangan initsializatorlardan farqli o'laroq, ular noldan ob'ekt yaratmaydi, balki boshqa initsializatorlarning mantig'ini qayta ishlatish orqali ishga tushirish jarayonini soddalashtiradi.

 class Rectangle { var width: Double var height: Double init(width: Double, height: Double) { self.width = width self.height = height } convenience init(side: Double) { self.init(width: side, height: side) // uses a designated initializer of self } }


Qulaylik initsializatorlari tayinlangan ishga tushirgichlarni yoki boshqa qulaylik ishga tushirgichlarini chaqirishi mumkin. Oxir-oqibat, belgilangan ishga tushiruvchi har doim chaqiriladi.

Qulaylik, belgilangan va supersinf boshlang'ichlari


Qulaylik initsializatorlari har doim gorizontal (self.init) va belgilangan ishga tushirgichlar vertikal (super.init) bo'ladi.

Superklassning qulaylik initializerini saqlab qolish

Subklass yangi xususiyatlarni e'lon qilishi bilanoq, u supersinfning barcha qulaylik ishga tushirgichlariga kirish huquqini yo'qotadi.

 class Animal { var age: Int var name: String init(age: Int, name: String) { self.age = age self.name = name } convenience init(age: Int) { self.init(age: age, name: "Default") } convenience init(name: String) { self.init(age: 0, name: name) } } class Dog: Animal { var breed: String init(age: Int, name: String, breed: String) { self.breed = breed super.init(age: age, name: name) } } let dog = Dog(age: 3) // ❌ Missing arguments for parameters 'breed', 'name' in call 


Joriy ishga tushirish ierarxiyasi, faqat bitta init aniq e'lon qilingan


Bu supersinfning barcha belgilangan initsializatorlarini bekor qilish orqali tuzatilishi mumkin.

 class Dog: Animal { // ... override init(age: Int, name: String) { self.breed = "Mixed" super.init(age: age, name: name) } } let dog = Dog(age: 3) // ✅ 


Qulaylik initsializatorlari endi tiklandi, lekin ikkita initsializator aniq e'lon qilindi


Ko'rinib turibdiki, shu tarzda keyingi kichik sinfda qulaylik ishga tushirgichdan foydalanish uchun ikkita initsializatorni bekor qilishingiz kerak.

 class GuideDog: Dog { var isTrained: Bool override init(age: Int, name: String) { self.isTrained = false super.init(age: age, name: name) } override init(age: Int, name: String, breed: String) { self.isTrained = false super.init(age: age, name: name, breed: breed) } init(age: Int, name: String, breed: String, isTrained: Bool) { self.isTrained = isTrained super.init(age: age, name: name, breed: breed) } } let dog = GuideDog(age: 3) // ✅ 


Qulaylik initsializatorlari tiklandi, ammo GuideDog uchta ishga tushirgichni aniq belgilaydi


Bekor qilish sonini minimallashtirish

Biroq, buning oldini olish uchun qulaylikni bekor qilish ishga tushirgichidan foydalanish mumkin.

 class Dog: Animal { var breed: String convenience override init(age: Int, name: String) { self.init(age: age, name: name, breed: "Mixed") // self, not super } init(age: Int, name: String, breed: String) { self.breed = breed super.init(age: age, name: name) } } class GuideDog: Dog { var isTrained: Bool // override init(age: Int, name: String) { // self.isTrained = false // // super.init(age: age, name: name, breed: "Mixed") // } convenience override init(age: Int, name: String, breed: String) { self.init(age: age, name: name, breed: breed, isTrained: false) // self, not super } init(age: Int, name: String, breed: String, isTrained: Bool) { self.isTrained = isTrained super.init(age: age, name: name, breed: breed) } } let dog = GuideDog(age: 3) // ✅ 


Ikkita Hayvonning qulaylik initsializatori tiklandi, It uchun qulaylik init (age:, name:) qayta qo‘lga kiritildi va faqat ikkita GuideDog ishga tushirgichi aniq ko‘rsatilgan.


Endi bizda har bir kichik sinfda atigi 2 ta aniq ko'rsatilgan boshlang'ich mavjud.

E'tibor bering, qulaylikni bekor qilish initsializatorlari super.init o'rniga self tayinlangan init deb atashadi.

Bu hiyla Tjeerd in 't Veen tomonidan "Swift in Depth" kitobining 5-bobida batafsil tushuntirilgan, men buni juda tavsiya qilaman.

Oraliq xulosa

  • Belgilangan ishga tushirgich barcha xususiyatlarning to'ldirilishini ta'minlaydi va super.init() chaqiradi.
  • Qulaylik ishga tushirgichi belgilangan ishga tushirgichni chaqirish orqali ishga tushirishni osonlashtiradi.
  • Qulaylik ishga tushiruvchisi, agar ular yangi xususiyatlarni e'lon qilsalar, pastki sinflar uchun mavjud bo'lmaydi.
  • Supersinfning qulaylik ishga tushirgichini tiklash uchun uning barcha belgilangan initsializatorlari bekor qilinishi kerak.
  • Qayta belgilashlar sonini minimallashtirish uchun qulaylikni bekor qilish ishga tushirgichidan foydalanish mumkin.

Kompilyator yordami

Agar quyi sinf yangi parametrlarni kiritmasa, u avtomatik ravishda barcha supersinf initsializatorlarini meros qilib olishini allaqachon muhokama qilgan edik.

 class Base { let value: Int init() { value = 0 } init(value: Int) { self.value = value } } class Subclass: Base { } let subclass = Subclass() // ✅ let subclass = Subclass(value: 3) // ✅


Biroq, yana bir muhim jihat bor: agar supersinfda faqat bitta tayinlangan initsializer bo'lsa va u parametrsiz bo'lsa ( init() argumentlarsiz), unda subklassdagi aniq e'lon qilingan initsializatorlar super.init() chaqirishga hojat yo'q . Bunday holda, Swift kompilyatori qo'ng'iroqni avtomatik ravishda mavjud super.init() ga argumentlarsiz kiritadi .

 class Base { init() { } } class Subclass: Base { let secondValue: Int init(secondValue: Int) { self.secondValue = secondValue // ✅ without explicit super.init() } }


Kod kompilyatsiya qilinadi, chunki super.init() bilvosita chaqiriladi. Bu quyidagi misollarning ba'zilari uchun juda muhimdir.

Majburiy

required initsializer quyi sinfda asosiy sinf bilan bir xil boshlang'ichga ega bo'lishi kerak bo'lgan barcha holatlarda qo'llaniladi. Bundan tashqari, super.init() ni chaqirishi kerak. Quyida required ishga tushirgich zarur bo'lgan misollar keltirilgan.

Umumiy

Umumiy turdagi init chaqirish faqat uni required init deb e'lon qilish orqali mumkin.

 class Base { } class Subclass: Base { } struct Factory<T: Base> { func initInstance() -> T { // ❌ Constructing an object of class T() // type 'T' with a metatype value } // must use a 'required' initializer }


Ushbu kod kompilyatsiya qilinmaydi, chunki Factory Base pastki sinflari haqida hech narsa bilmaydi. Garchi bu alohida holatda, Subclass parametrlarsiz init() mavjud bo'lsa-da, u yangi maydonni kiritganligini tasavvur qiling:

 class Subclass: Base { let value: Int init(value: Int) { self.value = value } }


Bu erda endi bo'sh init yo'q, shuning uchun uni required e'lon qilish kerak.

 class Base { required init() { } } class Subclass: Base { } struct Factory<T: Base> { static func initInstance() -> T { // ✅ T() } } let subclass = Factory<Subclass>.initInstance()


E'tibor bering, biz Subclass required init aniq e'lon qilmagan bo'lsak ham, kompilyator uni biz uchun yaratdi. Bu Compiler Assistance da muhokama qilindi. required init avtomatik ravishda meros qilib olinadi va super.init() deb nomlanadi.

 class Subclass: Base { required init() { super.init() } }

Protokollar

Protokollarda e'lon qilingan barcha ishga tushirgichlar required qilinishi kerak:

 protocol Initable { init() } class InitableObject: Initable { init() { // ❌ Initializer requirement 'init()' can only // be satisfied by a 'required' initializer } // in non-final class 'InitableObject' }


Shunga qaramay, bu kompilyator pastki sinf protokolni ishga tushirishni amalga oshirishini ta'minlashi uchun kerak. Biz allaqachon bilganimizdek, bu har doim ham sodir bo'lmaydi - agar init required bo'lmasa, pastki sinf uni bekor qilishga majbur emas va o'zining boshlang'ichini belgilashi mumkin.

 class IntValue: InitableObject { let value: Int init(value: Int) { self.value = value } } let InitableType: Initable.Type = IntValue.self let initable: Initable = InitableType.init()


Albatta, quyidagi kod kompilyatsiya qilinmaydi, chunki Base.init() required emas.

 class InitableObject: Initable { required init() { } // ✅ } class IntValue: InitableObject { let value: Int required init() { self.value = 0 } init(value: Int) { self.value = value } }

Self()

Xuddi shunday holat Self() initsializatorini statik usullarda chaqirganda ham yuzaga keladi.

 class Base { let value: Int init(value: Int) { self.value = value } static func instantiate() -> Self { Self(value: 3) // ❌ Constructing an object of class type 'Self' } // with a metatype value must use a 'required' initializer }


Har doimgidek, masala merosga bog'liq:

 class Subclass: BaseClass { let anotherValue: Int init(anotherValue: Int) { self.anotherValue = anotherValue } } let subclass = Subclass.instantiate() // ❌
 class BaseClass { let value: Int required init(value: Int) { // ✅ self.value = value } static func instantiate() -> Self { Self(value: 3) } }

required bo'lgandan qutulish: final

required maqsadi pastki sinflarda initsializatorni amalga oshirishni ta'minlash bo'lgani uchun, tabiiyki, final kalit so'zidan foydalanib merosni taqiqlash, boshlang'ichni required holda belgilash zaruratini olib tashlaydi.

 protocol Initable { init() } final class InitableObject: Initable { } // ✅
 protocol ValueInitable { init(value: Int) } final class ValueInitableObject: ValueInitable { init(value: Int) { } // ✅ }

Oraliq xulosa

  • Agar pastki sinf yangi parametrlarni kiritmasa, u o'zining yuqori sinfidagi barcha boshlang'ichlarni avtomatik ravishda meros qilib oladi.
  • Agar supersinfda faqat parametrlarsiz init() bo'lsa, u subsinf initsializatorlarida avtomatik ravishda chaqiriladi.
  • Jeneriklar, protokollar va Self() da foydalanish uchun pastki sinflarda mavjudligini kafolatlash uchun required ishga tushirgich kerak.

UIView()

Hujjatlarda topib bo'lmaydigan, lekin hamma joyda sirli ravishda qo'llaniladigan parametrlarsiz UIView() ishga tushirgichi haqida qisqacha eslatma.


Sababi, UIView parametrsiz init() ega bo'lgan NSObject dan meros bo'lib o'tadi. Shuning uchun , bu ishga tushirgich UIView interfeysida aniq e'lon qilinmagan, ammo u hali ham mavjud:

 @available(iOS 2.0, *) @MainActor open class UIView : UIResponder, NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem, UITraitEnvironment, UICoordinateSpace, UIFocusItem, UIFocusItemContainer, CALayerDelegate { open class var layerClass: AnyClass { get } public init(frame: CGRect) public init?(coder: NSCoder) open var isUserInteractionEnabled: Bool // no init()


Biroq, bu ishga tushirgich kodda ishga tushirilganda init(frame:) yoki Interface Builder orqali ishga tushirilganda init(coder:) chaqiradi. Buning sababi, UIView o'zining NSObject.init() ilovasini ta'minlaydi, buni method_getImplementation NSObject.init() va UIView.init() uchun turli manzillarni qaytarishi bilan tasdiqlanishi mumkin.

Muhtaram eslatmalar

Muvaffaqiyatsiz ishga tushirish

Muvaffaqiyatsiz init - bu ixtiyoriyni qaytaradigan

 final class Failable { let positiveValue: Int init?(value: Int) { guard value > 0 else { return nil } positiveValue = value } }

Enum

Xom qiymatga ega bo'lgan raqamlar bepul init?(rawValue:)

 enum Direction: String { case north case west case south case east } let north = Direction(rawValue: "north")

Enumlar uchun maxsus init ham yaratishingiz mumkin. Barcha enum initslari self belgilashi kerak.

 enum DeviceType { case phone case tablet init(screenWidth: Int) { self = screenWidth > 800 ? .tablet : .phone } }

Yakuniy xulosa

Biz Swift-da initsializatorlarning barcha muhim jihatlarini ko'rib chiqdik:


  • Initsializatorda barcha maydonlar to'ldirilishi kerak.

  • Ixtiyoriy var xususiyatlari sukut bo'yicha nil teng.

  • Strukturalar bepul a'zo bo'yicha ishga tushirgich oladi.

  • Maxsus ishga tushirgich aniqlanganda a'zolar bo'yicha ishga tushirgich yo'qoladi .

  • Belgilangan ishga tushirgich barcha maydonlarni to'ldirishni ta'minlaydi va super.init() ni chaqiradi.

  • Qulaylik ishga tushirgichi belgilangan ishga tushirgichni chaqirish orqali ishga tushirishni osonlashtiradi.

  • Qulaylik initsializatorlari har doim gorizontal ( self.init ) va belgilangan ishga tushirgichlar vertikal ( super.init ) bo'ladi.

  • Qulaylik ishga tushiruvchisi, agar ular yangi xususiyatlarni e'lon qilsalar, pastki sinflar uchun mavjud bo'lmaydi.

  • Supersinfning qulaylik ishga tushirgichini tiklash uchun uning barcha belgilangan initsializatorlari bekor qilinishi kerak.

  • Qayta belgilashlar sonini kamaytirish uchun qulaylikni bekor qilish boshlang'ichidan foydalanish mumkin.

  • Agar kichik sinf yangi parametrlarni kiritmasa, u o'zining yuqori sinfidagi barcha boshlang'ichlarni avtomatik ravishda meros qilib oladi.

  • Agar supersinfda faqat parametrlarsiz init() bo'lsa, u avtomatik ravishda subsinf initsializatorlarida chaqiriladi.

  • Kerakli initsializator uning generiklar, protokollar va Self() da foydalanish uchun quyi sinflarda mavjudligini ta'minlaydi.

  • UIView.init() UIView.init(frame:) yoki UIView.init(coder:) chaqiradi.

  • Muvaffaqiyatsiz ishga tushirgich ixtiyoriyni qaytaradi.

  • Xom qiymatga ega bo'lgan enumlar bepul init?(rawValue:) .

  • Barcha enum boshlang'ichlari self belgilashi kerak.


Umid qilamanki, siz ushbu maqolada foydali narsalarni topdingiz. Agar biror narsa noaniq bo'lib qolsa yoki siz noaniqlik topsangiz, Telegram orqali bepul tushuntirish uchun men bilan bog'laning: @kfamyn .

Tegishli havolalar

  1. Swift dasturlash tili (6) / Initializatsiya
  2. Swift in Depth, Tjeerd tomonidan 't Veen
  3. Telegram - @kfamyn