سازنده (initializer)
سازندهها، متدهای خاصی هستند که وجود آنها برای ساخت اشیاء لازم است. آنها به شما اجازه میدهند که مقادیری را به هر یک از فیلدهای کلاس اختصاص دهید و کدهایی که را که میخواهید هنگام ایجاد یک شیء اجرا شوند را به برنامه اضافه کنید. اگر از هیچ سازندهای در کلاستان استفاده نکنید، کامپایلر، از سازنده پیشفرض، که یک سازنده بدون پارامتر است، استفاده میکند. میتوانید در برنامهتان از تعداد زیادی سازنده استفاده کنید که، دارای پارامترهای متفاوتی باشند. در مثال زیر یک کلاس که شامل سازنده است را، مشاهده میکنید:
1: class Person 2: { 3: var name : String 4: var age : Int 5: var height: Double 6: 7: init() 8: { 9: name = "No Name" 10: age = 0 11: height = 0.0 12: } 13: 14: init(n: String, a: Int, h: Double) 15: { 16: self.name = n 17: self.age = a 18: self.height = h 19: } 20: 21: func ShowInformation() 22: { 23: print("Name : \(name)") 24: print("Age : \(age) years old") 25: print("Height: \(height) cm") 26: } 27: } 28: 29: var firstPerson = Person() 30: var secondPerson = Person(n: "Mike", a: 23, h: 158) 31: 32: firstPerson.name = "Jack" 33: firstPerson.age = 21 34: firstPerson.height = 160 35: firstPerson.ShowInformation() 36: 37: print() //Separator 38: 39: secondPerson.ShowInformation()
Name: Jack Age: 21 years old Height: 160cm Name: Mike Age: 23 years old Height: 158cm
همانطور که مشاهده میکنید، در مثال بالا، دو سازنده را به کلاس Person اضافه کردهایم. یکی از آنها سازنده پیشفرض (خطوط 12-7) و دیگری سازندهای است که سه آرگومان قبول میکند (خطوط 19- 14). در داخل بدنه سازنده پیشفرض (خطوط 11-9)، مقادیر پیشفرضی به فیلدهای کلاس (خطوط 5-3) اختصاص دادهایم. سازندهها نیز مانند توابع میتوانند سربارگذاری شوند. حال اجازه دهید که چطور میتوانیم یک سازنده خاص را هنگام تعریف یک نمونه از کلاس فراخوانی کنیم:
var firstPerson = Person() var secondPerson = Person(n: "Mike", a: 23, h: 158)
در اولین نمونه ایجاد شده از کلاس Person از سازنده پیشفرض استفاده کردهایم چون پارامتری برای دریافت آرگومان ندارد. در دومین نمونه ایجاد شده، از سازندهای استفاده میکنیم، که دارای سه پارامتر است. اگر خطوط 34-32 را حذف، برنامه را کامپایل و اجرا کنید، مقادیر پیشفرضی که در خطوط 11-9 به فیلدها اختصاص دادهایم در خروجی نمایش داده میشوند.
اگر بخواهید بجز این مقادیر پیشفرض، مقادیر دیگری به فیلدها اختصاص دهید، کافیست که یک شیء از کلاس ایجاد کرده و سپس فیلدها را مقداردهی کنید (کاری که در خطوط 34-32 انجام دادهایم). حال به شیء دوم که از سازنده دارای پارامتر استفاده میکند، توجه کنید، مشاهده میکنید که با فراخوانی تابع ShowInformation() همه چیز همانطور که انتظار میرود اجرا میشود. این بدین دلیل است که شما هنگام تعریف نمونه و از قبل مقادیری به هر یک از فیلدها اختصاص دادهاید، بنابراین، آنها نیاز به مقدار دهی مجدد ندارند، مگر اینکه، شما بخواهید این مقادیر را اصلاح کنید.
استفاده از کلمه کلیدی self
راهی دیگر برای ایجاد مقادیر پیشفرض استفاده از کلمه کلیدی self است. مثال زیر اصلاح شده مثال قبل است و نحوه استفاده از 4 سازنده با تعداد پارامترهای مختلف را نشان میدهد:
1: class Person 2: { 3: var name : String 4: var age : Int 5: var height: Double 6: 7: init() 8: { 9: name = "No Name" 10: age = 0 11: height = 0 12: } 13: 14: convenience init(name: String) 15: { 16: self.init(name: name, age: 0, height: 0) 17: } 18: 19: convenience init(name: String, age: Int) 20: { 21: self.init(name: name, age: age, height: 0) 22: } 23: 24: init(name: String, age: Int, height: Double) 25: { 26: self.name = name 27: self.age = age 28: self.height = height 29: } 30: 31: func ShowInformation() 32: { 33: print("Name : \(name)") 34: print("Age : \(age) years old") 35: print("Height: \(height) cm\n") 36: } 37: } 38: 39: var firstPerson = Person() 40: var secondPerson = Person(name: "Jack") 41: var thirdPerson = Person(name: "Mike", age: 23) 42: var fourthPerson = Person(name: "Chris", age: 18, height: 152) 43: 44: firstPerson.ShowInformation() 45: secondPerson.ShowInformation() 46: thirdPerson.ShowInformation() 47: fourthPerson.ShowInformation()
Name : No Name Age : 0 years old Height: 0.0 cm Name : Jack Age : 0 years old Height: 0.0 cm Name : Mike Age : 23 years old Height: 0.0 cm Name : Chris Age : 18 years old Height: 152.0 cm
ما چهار سازنده بری اصلاح کلاسمان تعریف کردهایم. شما میتوانید تعداد زیادی سازنده برای مواقع لزوم در کلاس داشته باشید. اولین سازنده یک سازنده پیشفرض است (سازنده اصلی). دومین سازنده یک پارامتر از نوع رشته دریافت میکند (خطوط 17-14). سومین سازنده دو پارامتر (خطوط 22-19) و چهارمین سازنده سه پارامتر میگیرد (خطوط 29-24). به چهارمین سازنده توجه کنید. سه سازنده دیگر به این سازنده وابسته هستند. در خطوط 12-7 یک سازنده پیشفرض بدون پارامتر تعریف شده است. توجه کنید که از کلمه کلیدی convenience باید قبل از کلمه کلیدی ()init استفاده کنید. با آنکه Swift از سربارگذاری توابع و سازندهها پشتیبانی میکند ولی استفاده از کلمه کلیدی convenience به شما اجازه میدهد که از تکرار کدنویسی جلوگیری کنید. توجه کنید که تمام سازندههایی که با convenience شروع میشوند باید سازنده اصلی را فراخوانی کنند. این کار با استفاده از کلمه کلیدی self انجام میشود (خطوط 16 و 21).
حال به نحوه فراخوانی این سازندهها میپردازیم. در خطوط 42-39 ما سه چهار شیء از کلاس Person ایجاد کردهایم. در خط 39 هیچ پارامتری به سازنده کلاس Person ندادهایم در نتیجه سازنده پیشفرض (خطوط 12-7) فراخوانی شده و مقادیر 0.0، 0، No Name چاپ میشوند. در خط 40 ما یک آرگومان رشتهای به سازنده ارسال کردهایم. کامپایلر به طور خودکار سازندهای که دارای یک پارامتر است (خطوط 17-14) را فراخوانی میکند. در این سازنده ما یک پارامتر تعریف کردهایم ولی در خط 16 آن، مقادیر پیشفرضی به فیلدهای age و height دادهایم. وقتی این پارامتر با یک مقدار رشتهای پر شد، سپس به پارامترهای سازنده چهارم ارسال شده و در کنار دو مقدار پیشفرض دیگر (0 برای age و 0.0 برای height) قرار میگیرد. این روند در مورد بقیه سازندهها نیز صدق میکند. در داخل بنده هر کدام از سازندهها، اگر کدی نوشته شود، در ابتدای همه کدها اجرا میشوند.
همانطور که مشاهده میکنید با ایجاد چندین سازنده برای یک کلاس، چندین راه برای ایجاد یک شیء بر اساس دادههایی که نیاز داریم به وجود میآید. در مثال بالا 4 نمونه از کلاس Person ایجاد کردهایم و چهار تغییر در سازنده آن به وجود آوردهایم. سپس مقادیر مربوط به فیلدهای هر نمونه را نمایش میدهیم. یکی از موارد استفاده از کلمه کلیدی self به صورت زیر است. فرض کنید نام پارامترهای متد کلاس شما یا سازنده، شبیه نام یکی از فیلدها باشد:
init(name: String, age: Int, height: Double) { name = name age = age height = height }
این نوع کدنویسی ابهام بر انگیز است و کامپایلر نمیتواند متغیر را تشخیص داده و مقداری به آن اختصاص دهد. اینجاست که از کلمه کلیدی self استفاده میکنیم:
init(name: String, age: Int, height: Double) { self.name = name self.age = age self.height = height }
قبل از هر فیلدی کلمه کلیدی self را مینویسیم و نشان میدهیم که این همان چیزی است که میخواهیم به آن مقداری اختصاص دهیم.