paint-brush
Swift init(), එක් වරක් සහ සියල්ලටමවිසින්@kfamyn
නව ඉතිහාසය

Swift init(), එක් වරක් සහ සියල්ලටම

විසින් Kiryl Famin19m2025/03/21
Read on Terminal Reader

දිග වැඩියි; කියවීමට

මෙම ලිපිය Swift ආරම්භකකරුවන්ට අත්‍යවශ්‍ය සියල්ල ආවරණය කරයි: memberwise, designated, convenience, convenience override; අවශ්‍ය භාවිත අවස්ථා; parameterless UIView() initializer; compiler assist; failable init, enum init සහ තවත් දේ.
featured image - Swift init(), එක් වරක් සහ සියල්ලටම
Kiryl Famin HackerNoon profile picture
0-item
1-item

හැඳින්වීම

හෙලෝ! මගේ නම කිරිල් ෆමින්, මම iOS සංවර්ධකයෙක්.


අද, මට Swift හි initializers වැනි සරල මාතෘකාවක් හොඳින් පරීක්ෂා කිරීමට අවශ්‍යයි. එහි සරල බව පෙනෙන්නට තිබුණත්, සමහර විට මෙම මාතෘකාව පිළිබඳ සම්පූර්ණ අවබෝධයක් නොමැතිකම නිසා විස්තර සොයා බැලීමකින් තොරව ඉක්මනින් නිවැරදි කිරීමට අවශ්‍ය කලකිරීමට පත්වන දෝෂ ඇති වේ.


මෙම ලිපියෙන්, අපි ආරම්භකයින්ට අදාළ සියල්ල ආවරණය කරන්නෙමු, ඒවා අතර:


  • අභිරුචි එකක් නිර්වචනය කරන අතරතුර ව්‍යුහයේ සාමාජික මට්ටමේ ආරම්භකය රඳවා ගන්නේ කෙසේද

  • පන්තිවල සෑම විටම ආරම්භකයක් ලිවීම අවශ්‍ය නොවන්නේ ඇයි

  • නම් කරන ලද ආරම්භක යන්ත්‍රයක super.init ඇමතීම සැමවිටම අවශ්‍ය නොවන්නේ ඇයි?

  • super.init ඇමතීමට පෙර උපපංතියක සියලුම ක්ෂේත්‍ර පුරවා තිබිය යුත්තේ ඇයි?

  • උපපංතිවල අවම අතිච්ඡාදනයන් සහිත සියලුම මාපිය ආරම්භකකරුවන්ට ප්‍රවේශ වන්නේ කෙසේද

  • හරියටම required ආරම්භකයක් අවශ්‍ය වූ විට

  • UIView.init() සැමවිටම පරාමිතීන් නොමැතිව හඳුන්වනු ලබන්නේ ඇයි, නමුත් init(frame:) සහ init(coder:) අභිබවා යන්නේ ඇයි?


...සහ තවත්. නමුත් අපි එය පියවරෙන් පියවර ගනිමු.

අන්තර්ගත වගුව

මූලික කරුණු

ව්‍යුහයන්

  • සාමාජිකත්ව ආරම්භකය
  • විකල්ප
  • var vs let
  • සාමාජිකත්ව ආරම්භකයක් රඳවා තබා ගැනීම

පන්ති

  • නම් කරන ලද ආරම්භකය
  • පහසුව සඳහා ආරම්භකය
  • සුපිරි පන්තියේ පහසුව සඳහා ආරම්භකය රඳවා තබා ගැනීම
  • අතිච්ඡාදන ගණන අවම කිරීම
  • සම්පාදක සහාය
  • required ආරම්භකකාරකය: generics, protocols, Self() , final
  • පරාමිතීන් නොමැතිව UIView()

ගෞරවනීය සඳහන් කිරීම්

  • අසාර්ථක ආරම්භය
  • එනම්ස්

සාරාංශය

අදාළ සබැඳි

මූලික කරුණු

ඇපල් හි මාර්ගෝපදේශය වන ස්විෆ්ට් ක්‍රමලේඛන භාෂාව (6) (ආරම්භකයින් සඳහා පුදුම සහගත ලෙස සවිස්තරාත්මක) මෙසේ පවසයි:


ආරම්භ කිරීම යනු පන්තියක, ව්‍යුහයක හෝ ගණන් කිරීමේ අවස්ථාවක් භාවිතය සඳහා සකස් කිරීමේ ක්‍රියාවලියයි. මෙම ක්‍රියාවලියට එම අවස්ථාවේ ගබඩා කර ඇති සෑම දේපලක් සඳහාම ආරම්භක අගයක් සැකසීම සහ නව අවස්ථාව භාවිතයට සූදානම් වීමට පෙර අවශ්‍ය වෙනත් ඕනෑම සැකසුමක් හෝ ආරම්භයක් සිදු කිරීම ඇතුළත් වේ.


ඔබ මෙම ආරම්භක ක්‍රියාවලිය ක්‍රියාත්මක කරන්නේ initializers නිර්වචනය කිරීමෙනි, ඒවා විශේෂිත වර්ගයක නව අවස්ථාවක් නිර්මාණය කිරීමට කැඳවිය හැකි විශේෂ ක්‍රම වැනිය. Objective-C initializers මෙන් නොව, Swift initializers අගයක් ආපසු ලබා නොදේ. ඔවුන්ගේ ප්‍රධාන කාර්යභාරය වන්නේ පළමු වරට භාවිතා කිරීමට පෙර වර්ගයක නව අවස්ථා නිවැරදිව ආරම්භ කර ඇති බව සහතික කිරීමයි.


හොඳයි, මම හිතන්නේ මට මෙතනට කිසිවක් එකතු කිරීමට අවශ්‍ය නැහැ.

ව්‍යුහයන්

ව්‍යුහ ආරම්භකකරුවන් සාකච්ඡා කිරීමෙන් පටන් ගනිමු. උරුමයක් නොමැති නිසා මෙය තරමක් සරල ය, නමුත් ඔබ දැනගත යුතු නීති කිහිපයක් තවමත් තිබේ.

සාමාජිකත්ව ආරම්භකය

අපි සරල ව්‍යුහයක් ලියමු:

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


ආරම්භකයක් පැහැදිලිව ප්‍රකාශ නොකර ව්‍යුහය ආරම්භ කිරීමට අපට හැකි වූ බව සලකන්න. මෙය සිදුවන්නේ ව්‍යුහයන්ට සම්පාදකය මඟින් ජනනය කරන ලද සාමාජික මට්ටමේ ආරම්භකයක් ලැබෙන බැවිනි. මෙය ක්‍රියාත්මක වන්නේ ව්‍යුහයන් සඳහා පමණි .


Refactor → Generate memberwise initializer තේරීමෙන්, එය පෙනෙන්නේ කෙසේදැයි ඔබට දැක ගත හැකිය:


Xcode හි සාමාජික මට්ටමේ ආරම්භකයක් ජනනය කිරීම


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


අත්සනින්, සියලු පරාමිතීන් සඳහා අගයන් ලබා දීමට අපොහොසත් වීමෙන් සම්පාදන දෝෂයක් ඇති වන බව පහසුවෙන් දැකගත හැකිය:

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


කෙසේ වෙතත්, ඔබට අවශ්‍ය තර්ක ගණන අඩු කිරීමට අවශ්‍ය නම්, ඔබට අභිරුචි ආරම්භකයක් අර්ථ දැක්විය හැකිය:

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


isBlocked පුරවා නොමැති නම්, සියලුම ව්‍යුහ ගුණාංග ආරම්භකකාරකයක පුරවා ගත යුතු බැවින්, මෙය සම්පාදන දෝෂයකට හේතු වන බව සලකන්න.

විකල්ප, var vs let

ක්ෂේත්‍රයක් පැහැදිලිව පුරවා ගැනීමට අවශ්‍ය නොවන එකම අවස්ථාව වන්නේ එය විකල්ප ( ? ) විචල්‍යයක් වන විට පමණි ( var ). එවැනි අවස්ථාවන්හිදී, ක්ෂේත්‍රය පෙරනිමියෙන් nil වනු ඇත:

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


කෙසේ වෙතත්, මෙම අවස්ථාවේදී අපි memberwise initializer භාවිතා කිරීමට උත්සාහ කළහොත්, අපට සම්පාදන දෝෂයක් ලැබෙනු ඇත:

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

සාමාජිකත්ව ආරම්භකයක් රඳවා තබා ගැනීම

මෙය සිදුවන්නේ අභිරුචි ආරම්භකයක් ප්‍රකාශ කිරීමෙන් සාමාජික මට්ටමේ ආරම්භකය ඉවත් වන බැවිනි. එය තවමත් පැහැදිලිව අර්ථ දැක්විය හැකි නමුත් එය ස්වයංක්‍රීයව ලබා ගත නොහැක.


කෙසේ වෙතත්, memberwise initializer රඳවා ගැනීමට කුඩා උපක්‍රමයක් තිබේ: අභිරුචි initializer extension ප්‍රකාශ කරන්න.

 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


ව්‍යුහයන් සඳහා සාරාංශය

  • සියලුම ක්ෂේත්‍ර ආරම්භකකාරකයක පුරවා තිබිය යුතුය.
  • විකල්ප var ක්ෂේත්‍ර පෙරනිමියෙන් nil සකසා ඇත
  • ව්‍යුහයන්ට නොමිලේ සාමාජිකත්ව ආරම්භකයක් ලැබේ.
  • අභිරුචි ආරම්භකයක් ප්‍රකාශ කළහොත් සාමාජික මට්ටමේ ආරම්භකය අතුරුදහන් වේ.
  • ව්‍යුහයේ සාමාජික මට්ටමේ ආරම්භකය රඳවා ගැනීමට, දිගුවක අභිරුචි එකක් අර්ථ extension

පන්ති

නම් කරන ලද ආරම්භකය

පන්තියක් සඳහා ප්‍රාථමික ආරම්භකය නම් කරන ලද ආරම්භකය වේ. එය අරමුණු දෙකක් ඉටු කරයි:

  1. සියලුම ක්ෂේත්‍ර පිරී ඇති බව සහතික කරයි.
  2. පන්තිය උරුම වී ඇත්නම්, එය සුපිරි පන්තියේ ආරම්භකය ලෙස හැඳින්වේ.
 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 ඇමතීමට පෙර සියලුම ක්ෂේත්‍ර පිරවිය යුතුය . මන්ද, superclass initializer උපපංතිය මගින් අභිබවා ගිය ක්‍රම කැඳවිය හැකි අතර එමඟින් ජනාකීර්ණ නොවූ උපපංති ගුණාංග වෙත ප්‍රවේශ විය හැකිය.

 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) } }


මේ අනුව, අපි self.breed = breed සකසා නොතිබුනේ නම්, අපට ධාවන කාල දෝෂයක් ඇති වීමට ඉඩ තිබුණි, මන්ද Animal initializer එක Dog පන්තියෙන් overrided getInfo() ක්‍රමය කැඳවනු ඇත. මෙම ක්‍රමය තවමත් ජනනය කර නොමැති breed දේපල වෙත ප්‍රවේශ වීමට උත්සාහ කරයි.


ව්‍යුහයන් මෙන් නොව, පන්තිවලට ව්‍යංග සාමාජික මට්ටමේ ආරම්භකයක් නොලැබේ. ආරම්භ නොකළ ගුණාංග තිබේ නම්, සම්පාදන දෝෂයක් ඇතිවේ:

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

පහසුව සඳහා ආරම්භකය

පන්තිවලට පහසු ආරම්භකයක් ද තිබිය හැකිය. නම් කරන ලද ආරම්භකයන් මෙන් නොව, ඒවා මුල සිටම වස්තුවක් නිර්මාණය නොකරන නමුත් අනෙකුත් ආරම්භකයන්ගේ තර්කනය නැවත භාවිතා කිරීමෙන් ආරම්භක ක්‍රියාවලිය සරල කරයි.

 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 } }


Convenience initializers හට designated initializers හෝ වෙනත් convenience initializers ඇමතිය හැක. අවසාන වශයෙන්, designated initializer සැමවිටම කැඳවනු ලැබේ.

පහසුව, නම් කරන ලද සහ සුපිරි පන්තියේ ආරම්භක


පහසු ආරම්භක යන්ත්‍ර සෑම විටම තිරස් අතට යයි (self.init), සහ නම් කරන ලද ආරම්භක යන්ත්‍ර සිරස් අතට යයි (super.init).

සුපිරි පන්තියේ පහසුව සඳහා ආරම්භකය රඳවා තබා ගැනීම

උපපංතියක් නව ගුණාංග ප්‍රකාශ කළ වහාම, සුපිරිපංතියේ සියලුම පහසු ආරම්භක වෙත ප්‍රවේශය අහිමි වේ.

 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 


වත්මන් ආරම්භක ධූරාවලිය, එක් init එකක් පමණක් පැහැදිලිව ප්‍රකාශ කර ඇත.


සුපිරි පන්තියේ නම් කරන ලද සියලුම ආරම්භක අභිබවා යාමෙන් මෙය නිවැරදි කළ හැක.

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


පහසු ආරම්භක දැන් නැවත ලබාගෙන ඇත, නමුත් ආරම්භක දෙකක් පැහැදිලිව ප්‍රකාශ කර ඇත.


මේ ආකාරයෙන්, ඊළඟ උපපංතියේ පහසු ආරම්භකයක් භාවිතා කිරීමට, ඔබ ආරම්භක දෙකක් අභිබවා යා යුතු බව දැකීම පහසුය.

 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) // ✅ 


පහසුව සඳහා ආරම්භක යන්ත්‍ර නැවත ලබා ගනී, නමුත් GuideDog මඟින් ආරම්භක යන්ත්‍ර තුනක් පැහැදිලිව සඳහන් කරයි.


අතිච්ඡාදන ගණන අවම කිරීම

කෙසේ වෙතත්, පහසුව සඳහා අතික්‍රමණය කිරීමේ ආරම්භකයක් භාවිතා කිරීමෙන් මෙය වළක්වා ගත හැකිය.

 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) // ✅ 


සත්වයාගේ පහසුව සඳහා ආරම්භක දෙකක් නැවත ලබා ගන්නා ලදී, බල්ලාගේ පහසුව සඳහා ආරම්භක (වයස:, නම:) නැවත ලබා ගන්නා ලදී සහ GuideDog හි ආරම්භක දෙකක් පමණක් පැහැදිලිව දක්වා ඇත.


දැන් අපට සෑම උපපංතියකම පැහැදිලිව නිශ්චිත ආරම්භක 2 ක් පමණක් ඇත.

convenience override initializers super.init වෙනුවට self designated init ලෙස හඳුන්වන ආකාරය සැලකිල්ලට ගන්න.

මෙම උපක්‍රමය Tjeerd විසින් රචිත "Swift in Depth" හි 5 වන පරිච්ඡේදයේ හොඳින් පැහැදිලි කර ඇත, එය මම බෙහෙවින් නිර්දේශ කරන පොතකි.

අතරමැදි සාරාංශය

  • නම් කරන ලද ආරම්භකයක් සියලුම ගුණාංග පිරවූ බව සහතික කරන අතර super.init() ලෙස හඳුන්වයි.
  • පහසු ආරම්භකයක් නම් කරන ලද ආරම්භකයක් ඇමතීමෙන් ආරම්භ කිරීම සරල කරයි.
  • උපපංති නව ගුණාංග ප්‍රකාශ කළහොත් පහසුව සඳහා ආරම්භකයක් ලබා ගත නොහැක.
  • සුපිරි පන්තියක පහසුව සඳහා ආරම්භක යන්ත්‍රය ප්‍රතිසාධනය කිරීම සඳහා, එහි නම් කරන ලද සියලුම ආරම්භක යන්ත්‍ර අභිබවා යා යුතුය.
  • අතිච්ඡාදනය කිරීම් ගණන අවම කිරීම සඳහා, පහසුව සඳහා අතිච්ඡාදනය කිරීමේ ආරම්භකයක් භාවිතා කළ හැකිය.

සම්පාදක සහාය

උපපංතියක් නව පරාමිතීන් හඳුන්වා නොදෙන්නේ නම්, එය සුපිරිපංතියේ සියලුම ආරම්භක ස්වයංක්‍රීයව උරුම කර ගන්නා බව අපි දැනටමත් සාකච්ඡා කර ඇත්තෙමු.

 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) // ✅


කෙසේ වෙතත්, තවත් වැදගත් කරුණක් තිබේ: සුපිරි පන්තියට නම් කරන ලද එක් ආරම්භකයක් පමණක් තිබේ නම් සහ එය පරාමිති රහිත නම් ( init() තර්ක නොමැතිව), එවිට උප පන්තියේ පැහැදිලිව ප්‍රකාශ කරන ලද ආරම්භකයින්ට super.init() ඇමතීමට අවශ්‍ය නොවේ . මෙම අවස්ථාවේදී, Swift සම්පාදකය ස්වයංක්‍රීයව ඇමතුම ලබා ගත හැකි super.init() තර්ක නොමැතිව ඇතුල් කරයි.

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


කේතය සම්පාදනය වන්නේ super.init() ව්‍යංගයෙන් හැඳින්වෙන බැවිනි. පහත උදාහරණ කිහිපයක් සඳහා මෙය ඉතා වැදගත් වේ.

අවශ්‍යයි

උපපංතියකට මූලික පන්තියට සමාන ආරම්භකකාරකයක් තිබිය යුතු සෑම අවස්ථාවකම required ආරම්භකකාරකයක් භාවිතා වේ. එය super.init() ලෙසද හැඳින්විය යුතුය. required ආරම්භකකාරකයක් අවශ්‍ය වන අවස්ථා සඳහා උදාහරණ පහත දැක්වේ.

ජෙනරික්ස්

සාමාන්‍ය වර්ගයකින් init ඇමතීමට හැකි වන්නේ එය required init ලෙස ප්‍රකාශ කිරීමෙන් පමණි.

 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 }


මෙම කේතය සම්පාදනය නොවේ, මන්ද Factory Base හි උප පන්ති ගැන කිසිවක් නොදන්නා බැවිනි. මෙම විශේෂිත අවස්ථාවේදී, Subclass පරාමිතීන් නොමැතිව init() එකක් තිබුණද, එය නව ක්ෂේත්‍රයක් හඳුන්වා දුන්නේ නම් සිතන්න:

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


මෙන්න, එහි තවදුරටත් හිස් init නොමැති බැවින්, එය required පරිදි ප්‍රකාශ කළ යුතුය.

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


අපි Subclass required init පැහැදිලිව ප්‍රකාශ නොකළද, සම්පාදකයා එය අප වෙනුවෙන් ජනනය කළ බව සලකන්න. මෙය සම්පාදක සහාය තුළ සාකච්ඡා කරන ලදී. required init ස්වයංක්‍රීයව උරුම වූ අතර එය super.init() ලෙස හැඳින්වේ.

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

ප්‍රොටෝකෝල

ප්‍රොටෝකෝලවල ප්‍රකාශ කර ඇති සියලුම ආරම්භක required විය යුතුය:

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


නැවතත්, මෙය අවශ්‍ය වන්නේ සම්පාදකයා විසින් උපපංතිය ප්‍රොටෝකෝල ආරම්භකය ක්‍රියාත්මක කරන බව සහතික කිරීම සඳහා ය. අප දැනටමත් දන්නා පරිදි, මෙය සැමවිටම සිදු නොවේ - init required නොවේ නම්, උපපංතිය එය අභිබවා යාමට බැඳී නොමැති අතර තමන්ගේම ආරම්භකය නිර්වචනය කළ හැකිය.

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


ඇත්ත වශයෙන්ම, Base.init() required නොවන නිසා පහත කේතය සම්පාදනය නොවේ.

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

ස්වයං()

ස්ථිතික ක්‍රම වලදී Self() ආරම්භකය ඇමතීමේදීද මෙවැනිම තත්වයක් ඇතිවේ.

 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 }


සෑම විටම මෙන්, ගැටළුව පවතින්නේ උරුමය තුළ ය:

 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 ඉවත් කිරීම: final

required හි අරමුණ උපපංතිවල ආරම්භකයක් ක්‍රියාත්මක කිරීම බලාත්මක කිරීම බැවින්, ස්වාභාවිකවම, final මූල පදය භාවිතා කරමින් උරුමය තහනම් කිරීමෙන් ආරම්භකයක් required ලෙස සලකුණු කිරීමේ අවශ්‍යතාවය ඉවත් වේ.

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

අතරමැදි සාරාංශය

  • උපපංතියක් නව පරාමිතීන් හඳුන්වා නොදෙන්නේ නම්, එය ස්වයංක්‍රීයව එහි සුපිරිපංතියෙන් සියලුම ආරම්භකයන් උරුම කර ගනී.
  • සුපිරි පන්තියේ පරාමිතීන් නොමැතිව init() පමණක් තිබේ නම්, එය උප පන්තියේ ආරම්භක යන්ත්‍රවල ස්වයංක්‍රීයව හැඳින්වේ.
  • ජෙනරික්ස්, ප්‍රොටෝකෝල සහ Self() වල භාවිතය සඳහා උපපංතිවල එහි පැවැත්ම සහතික කිරීම සඳහා required ආරම්භකයක් අවශ්‍ය වේ.

UIVE()

පරාමිතීන් නොමැතිව UIView() ආරම්භකය පිළිබඳ කෙටි සඳහනක්, එය ලේඛනවල සොයාගත නොහැකි නමුත් අභිරහස් ලෙස සෑම තැනකම භාවිතා වේ.


හේතුව UIView හට පරාමිතීන් නොමැතිව init() එකක් ඇති NSObject වෙතින් උරුම වීමයි. එබැවින් , මෙම ආරම්භකකාරකය UIView අතුරුමුහුණතෙහි පැහැදිලිව ප්‍රකාශ කර නැත, නමුත් එය තවමත් පවතී:

 @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()


කෙසේ වෙතත්, ආවරණය යටතේ, මෙම ආරම්භකකාරකය කේතයෙන් ආරම්භ කළ විට init(frame:) ලෙසද, අතුරුමුහුණත් සාදන්නා හරහා ආරම්භ කළ විට init(coder:) ලෙසද හඳුන්වයි. මෙය සිදුවන්නේ UIView තමන්ගේම NSObject.init() ක්‍රියාත්මක කිරීම සපයන බැවිනි, method_getImplementation NSObject.init() සහ UIView.init() සඳහා විවිධ ලිපින ආපසු ලබා දෙන බව තහවුරු කළ හැකිය.

ගෞරවනීය සඳහන් කිරීම්

අසාර්ථක ආරම්භය

අසාර්ථක විය හැකි init එකක් යනු විකල්පයක් ආපසු ලබා දෙන එකක් පමණි

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

එනුම්

අමු අගයක් සහිත එනම් වලට නොමිලේ init?(rawValue:)

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

ඔබට enums සඳහා අභිරුචි init එකක් ද නිර්මාණය කළ හැකිය. සියලුම enum inits self පැවරිය යුතුය.

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

අවසාන සාරාංශය

අපි Swift හි initializers වල සියලුම අත්‍යවශ්‍ය අංග ආවරණය කර ඇත්තෙමු:


  • ආරම්භකයක, සියලුම ක්ෂේත්‍ර පුරවා තිබිය යුතුය.

  • විකල්ප var ගුණාංග පෙරනිමියෙන් nil .

  • ව්‍යුහයන්ට නොමිලේ සාමාජිකත්ව ආරම්භකයක් ලැබේ.

  • අභිරුචි ආරම්භකයක් අර්ථ දක්වා ඇති විට සාමාජික මට්ටමේ ආරම්භකය අතුරුදහන් වේ .

  • නම් කරන ලද ආරම්භකයක් සියලුම ක්ෂේත්‍ර පුරවා ඇති බව සහතික කරන අතර super.init() අමතයි.

  • පහසු ආරම්භකයක් නම් කරන ලද ආරම්භකයක් ඇමතීමෙන් ආරම්භ කිරීම සරල කරයි.

  • පහසු ආරම්භක යන්ත්‍ර සෑම විටම තිරස් අතට යයි ( self.init ), සහ නම් කරන ලද ආරම්භක යන්ත්‍ර සිරස් අතට යයි ( super.init ).

  • උපපංති නව ගුණාංග ප්‍රකාශ කළහොත් පහසුව සඳහා ආරම්භකයක් ලබා ගත නොහැක.

  • සුපිරි පන්තියක පහසුව සඳහා ආරම්භක යන්ත්‍රය ප්‍රතිසාධනය කිරීම සඳහා, එහි නම් කරන ලද සියලුම ආරම්භක යන්ත්‍ර අභිබවා යා යුතුය.

  • අතිච්ඡාදනය කිරීම් ගණන අවම කිරීම සඳහා, පහසුව සඳහා අතිච්ඡාදනය කිරීමේ ආරම්භකයක් භාවිතා කළ හැකිය.

  • උපපංතියක් නව පරාමිතීන් හඳුන්වා නොදෙන්නේ නම්, එය ස්වයංක්‍රීයව එහි සුපිරිපංතියෙන් සියලුම ආරම්භකයන් උරුම කර ගනී.

  • සුපිරි පන්තියේ පරාමිතීන් නොමැතිව init() පමණක් තිබේ නම්, එය ස්වයංක්‍රීයව උප පන්තියේ ආරම්භක තුළ කැඳවනු ලැබේ.

  • අවශ්‍ය ආරම්භකයක්, ජෙනරික්ස්, ප්‍රොටෝකෝල සහ Self() වල භාවිතය සඳහා උපපංතිවල එහි පැවැත්ම සහතික කරයි.

  • UIView.init() මඟින් UIView.init(frame:) හෝ UIView.init(coder:) අමතයි.

  • අසාර්ථක ආරම්භකයක් විකල්පයක් ආපසු ලබා දෙයි.

  • අමු අගයක් සහිත එනම් වලට නොමිලේ init?(rawValue:) ලැබේ.

  • සියලුම enum ආරම්භකයින් self පැවරිය යුතුය.


මෙම ලිපියෙන් ඔබට ප්‍රයෝජනවත් යමක් හමු වූ බව මම බලාපොරොත්තු වෙමි. යමක් අපැහැදිලි නම් හෝ ඔබට සාවද්‍ය බවක් පෙනේ නම්, නොමිලේ පැහැදිලි කිරීමක් සඳහා ටෙලිග්‍රෑම් හරහා මාව සම්බන්ධ කර ගැනීමට නිදහස් වන්න: @kfamyn .

අදාළ සබැඳි

  1. ස්විෆ්ට් ක්‍රමලේඛන භාෂාව (6) / ආරම්භ කිරීම
  2. Swift in Depth by Tjeerd in 't Veen
  3. විදුලි පණිවුඩය - @kfamyn