خبرنامه
 
پست الکترونیکی خود را وارد نمایید
شماره خبر : 885
تاریخ انتشار :
آشنایی با برنامه نویسی تحت بستر Swift : بخش دوم

آشنایی با برنامه نویسی تحت بستر Swift : بخش دوم

اگر اولین مقاله از این سری را خوب مطالعه کرده باشید حتماً به یاد دارید که ما در آن مقاله در مورد فلسفه شکل گیری زبان برنامه نویسی Swift، نحوه املای دستورات آن و یک سری تفاوت های کلیدی این زبان با زبان شیگرای C صحبت کردیم. در این مقاله در مورد نحوه املای دستورات بیشتر صحبت خواهیم کرد. همچنین شما چیزهایی را در مورد optionalها یاد گرفته و در نهایت خواهید فهمید که سیستم مدیریت حافظه در زبان برنامه نویسی Swift چگونه کار می کند.
حلقه ها و شرطها :


If :

به طور کلی ساختار دستورات شرطی If در زبان Swift و زبان برنامه نویسی شیگرای C شبیه به هم بوده و فقط در دو نکته ظریف با هم تفاوت دارند :
پرانترهایی که حول متغیر شرطی قرار می گیرند الزامی به وجود آن ها نیست یعنی اینکه اختیاری هستند.
آکولاد های مجعر باید قرار داده شوند.
این دو مورد تنها تفاوت هایی هستند که بین این دو زبان برنامه نویسی وجود دارد.
محدوده ها :
همانطور که در مقاله اول ملاحظه کردید، زبان برنامه نویسی Swift از دو عملگر محدوده ای ..< و ... برخوردار است. از این دو عملگر همانطور که از نام آنها مشخص است به منظور تعیین محدوده ای از مقادیر استفاده می شود.
هر دوی این عملگرها هم از نوع عملگر محدوده نیم بسته هستند و هم از نوع عملگر محدوده کاملاً بسته.
یک محدوده نیمه بسته به این معناست که به عنوان مثال الگوی 1..<5، مقادیر 1 تا 4 را ارائه داده و از مقدار 5 صرف نظر می شود. از آن طرف یک محدوده کاملاً بسته نیز مانند 1...5، علاوه بر ارائه مقادیر 1 تا 4، مقدار 5 را نیز دربر می گیرد.
ما می توانیم از محدوده ها در حلقه های For، زیر اسکرپیت آرایه و یا حتی در دستورات switch از آنها بهره ببریم. به مثال های زیر دقت کنید :

 

// for loop example
for i in 1..<10 {
    
}
// iterates from 1 to 9

 

// array subscript example
let someArray = ["apple","pair","peach","watermelon","strawberry"]
for fruit in someArray[2..<4] {
    println(fruit)
}
// outputs: peach and watermelon

// switch example
switch someInt {
    case 0:
    // do something with 0
    case 1..<5:
    // do something with 1,2,3,4
    case 5...10:
    // do something with 5,6,7,8,9,10
    default:
    // everything else
}

 

Switch :
قدرت و توانمندی دستورات Switch در زبان برنامه نویسی Swift نسبت به همتایان خود در زبان شیگرای C بیشتر هستند. در زبان شیگرای C، نتیجه حاصله از یک دستور Switch لازم است تا از نوع عددی بوده و مقادیر هر یک از دستورات Case باید یک ثابت و یا یک عبارت ثابت باشند. اما این حالت در Swift وجود ندارد به این معنا که دستورات case می توانند هر نوع داده‌ای باشند حتی می توانید از محدوده ها نیز بهره ببرید.
در زبان برنامه نویسی Swift، دستور Switch از هیچ دستور breakای استفاده نکرده و به صورت خودکار نیز از یک دستور case به دستور case دیگر سوییچ نمی کند.
زمانی که یک دستور Switch را می نویسید باید دقت داشته باشید که تمامی شرطها به واسطه دستور case متعلق به خود مدیریت می شوند در غیر این صورت به هنگام کامپایل کد با خطا مواجه خواهید شد. یک روش مطمئن برای تحت پوشش قرار دادن تمامی شرطها، این است که یک دستور default case به آن اضافه کنید.

 

let vegetable = "red pepper"
switch vegetable {
case "celery":
    let vegetableComment = "Add some raisins and make ants on a log."
case "cucumber", "watercress":
    let vegetableComment = "That would make a good tea sandwich."
default:
    let vegetableComment = "Everything tastes good in soup."
}

 

در زبان برنامه نویسی Swift، دستورات case به صورت پیشفرض، شکسته نمی شوند. این نوع سیاست به صورت عمدی از طرف طراحان این زبان شکل گرفته تا از خطاهای معمول و متداول جلوگیری کنند.
اگر یک دستور Case خاص نیاز به شکسته شدن داشت، شما می توانید از لغت کلیدی fallthrough برای فرمان دادن به کامپایلر برای این منظور و به صورت زیر بهره ببرید :

 

switch someInt {
    case 0:
    // do something with 0
    case 1:
    // do something with 1
    case 2:
    // do something with 2
        fallthrough
    default:
    //do something for everything else
}
 
// case 2 will fall through to default case

 

 

البته دنباله این ویژگی ها همین جا به پایان نمی رسد.  طراحان این زبان دو ویژگی دیگر را نیز با نام های  value bindings و where clause به این زبان اضافه کرده اند. ویژگی اول یعنی Value binding، با لغات کلیدی case و let به منظور مقید کردن یک ثابت با دستور case منطبق مورد استفاده قرار می گیرد. از آن طرف دستور where clause نیز، یک شرط اضافی را به دستورcaseای که از لفت کلیدی where استفاده کرده، اضافه می کند.
این دو مفهوم با ذکر چند مثال، بهتر درک خواهند شد. قطعه کد زیر به شما نشان خواهد داد که چگونه value binding کار می کند.

 

let somePoint = (xaxis:2, yaxis:0)
switch somePoint {
case (let x, 0):
    println("on the x-axis with an x value of \(x)")
case (0, let y):
    println("on the y-axis with a y value of \(y)")
case let (x, y):
    println("somewhere else at (\(x), \(y))")
}

 

اولین دستور case، یعنی case (let x, 0)، مقادیر را در صورتی که yaxis برار صفر بوده و به ازای هر مقدار برای xaxis، ما xaxis را مقید به ثابت X کرده تا در داخل دستور case مورد استفاده قرار بگیرد.
در مثال زیر می توانید استفاده از where clause را به صورت واقعی ملاحظه و بررسی کنید :

 

let vegetable = "red pepper"
switch vegetable {
case "celery":
    println("Add some raisins and make ants on a log.")
case let x where x.hasSuffix("pepper"):
    println("I'm allergic to \(x)")
default:
    println( "Everything tastes good in soup.")
}
 
// outputs: I'm allergic to red pepper

 

توابع و Closure ها :
توابع :
تعریف توابع و closureها در زبان برنامه نویسی Swift امری ساده است. برنامه نویسان زبان شیءگرای C آنها را بیشتر با نام توابع و بلوک ها می شناسند.
در زبان برنامه نویسی Swift، پارامترهای یک تابع می توانند از مقادیر پیشفرض برخوردار باشند. این سیاست ما را بیشتر یاد زبان های اسکریپتی‌ای همچون PHP و Ruby می اندازد. نحوه املای توابع به مانند زیر می باشد :

 

func functionName(parameterName: Type = DefaultValue) -> returnType {
    [...]
    return returnType;
}

 

برای نوشتن یک تابع با نام sayHello که از یک پارامتر با نام name و از نوع رشته ای برخوردار بوده و در پایان کار یک مقدار منطقی از نوع Bool را بر می گرداند از تکه کد زیر می بایست استفاده کنیم :

 

func sayHello(name: String) -> Bool {
    println("hello \(name)");
    return true;
}
 
sayHello("World")
// output
// hello World

 

به منظور تعیین مقدار پیشفرض برای پارامتر name، باید از الگوی کد زیر استفاده کنید :

 

func sayHello(name: String = "World") -> Bool {
    println("hello \(name)");
    return true;
}
 
sayHello()
// output
// hello World
 
sayHello("mike")
// output
// hello mike

 

ویژگی ای که در زبان شیگرای C فقدان آن کاملاً احساس می شود tuple‌ها هستند. در زبان Swift، توابع می توانند چندین مقدار را از یک الگوی tuple برگردانند. Tupleها در واقع به عنوان یک متغیر واحد عمل می کنند، به این معنا که شما می توانید از آن، درست به مانند یک متغیر بهره ببرید.
نحوه استفاده از tuple بسیار آسان است. در اصل اگر مقاله پیشین را خوب مطالعه کرده باشید حتماً به یاد دارید زمانی که ما یک دیکشنری را شمارش کردیم در واقع از tupleها نیز استفاده کردیم. در تکه کد بعدی زوج کلید و مقدار در واقع یک tuple است :

 

for (key,value) in someDictionary {
    println("Key \(key) has value \(value)"
}

 

حال به نظر شما چگونه باید از tupleها استفاده کرده و به طور کلی چگونه از آنها به صورت کاربردی بهره بگیریم؟ اجازه دهید تا با ذکر مثالی دیگر قضیه را بیشتر روشن کنیم.  بیاید تابع sayHello بالا را طوری تغییر دهیم که به هنگام پایان علاوه بر برگردادن یک مقدار منطقی، پیغامی را نیز نمایان کند. در واقع ما این کار را با برگرداندن یک tuple و با الگوی (Bool, String) انجام می دهیم. کد تغییر یافته و نهایی ما به شکل زیر خواهد بود :

 

func sayHello(name: String = "World") -> (Bool, String) {
    let greeting = "hello \(name)"
    return (true, greeting);
}
 
let (success, greeting) = sayHello()
println("sayHello returned success:\(success) with greeting: \(greeting)");
// output
// sayHello returned success:1 with greeting: hello World

 

خیل عظیمی از برنامه نویسان زبان شیگرای C برای مدت هاست که منتظر اضافه شدن tupleها به این زبان هستند.
یک ویژگی دلچسب دیگر tupleها این است که ما می توانیم متغیرهای برگشتی را نام گذاری کنیم. که در این صورت مثال قبلی باید به شکل زیر تغییر می یابد :

 

func sayHello(name: String = "World") -> (success: Bool, greeting: String) {
    let greeting = "hello \(name)"
    return (true, greeting);
}
 
let status = sayHello()
println("sayHello returned success:\(status.success) with greeting: \(status.greeting)");
// output
// sayHello returned success:1 with greeting: hello World

 

این حالت بدان معناست که یعنی به جای تعریف یک ثابت جداگانه به ازای هر یک از عناصر برگشتی از یک tuple، ما می توانیم به اجزای برگشتی tuple با استفاده از علامت دات(نقطه)، همانطور که در مثال بالا مشخص است دسترسی پیدا کنیم.
Closureها :
Closureها در زبان برنامه نویسی Swift در واقع همان مفهوم بلوکها در زبان شیگرای C  هستند. آنها را می توان به صورت درون خطی، به عنوان پارامتر و یا حتی به عنوان مقدار برگشتی تابع ها مورد استفاده قرار داد. نحوه به کارگیری Closureها در زبان Swift دقیقاً به همانگونه ای است که در ما در زبان شیگرای C شاهد آن بوده و هستیم.
نحوه تعریف Closureها بسیار ساده است. به طور واقعی، یک تابع یک الگوی خاص از Closureها تلقی می شود. بنابراین جای تعجبی وجود ندارد که تعریف یک Closure بسیار شبیه تعریف یک تابع به نظر برسد.
Closureها در اصل از نوع first-class هستند به این معنا که می توان آنها را به وسیله توابع، درست به مانند هر نوع داده دیگری همچون Int, String, Bool به عنوان پارامتر به کار برده و یا به عنوان مقدار برگشتی از آنها استفاده کرد.
Closureها الزاماً بلوکهای کدی هستند که می توانند در مواقع مورد نیاز مورد فراخوانی قرار گرفته و دسترسی به حوضه‌ یا میدانی که آنها در آن تعریف شده اند داشته باشند.
ایجاد یک closure بدون نام در اصل به سادگی قرار دادن یک قطعه کد در یک جفت آکولاد مجعر است. پارامترها و نوع برگشتی یک closure به واسطه لغت کلیدی in از بدنه closure جدا شده اند.
فرض کنید می خوانیم closureای را تعریف کنیم که اگر شماره زوج بود مقدار true را برگشت بدهد. در این صورت closure مورد نظر ما باید به مانند زیر باشد :

 

let isEven = {
(number: Int) -> Bool in
let mod = number % 2
return (mod==0)
}

 

کلوژر isEven تنها از یک پارامتر از جنس Int استفاده کرده و مقدار برگشتی آن نیز از نوع منطقی است. به طور خلاصه اگر بخواهیم در مورد نوع این کلوژر صحبت کنیم باید بگوییم که نوع آن یا به صورت (number: Int) -> Bool بوده و یا از الگوی (Int -> Bool) بهره می برد.
حال ما می توانیم از این کلوژر در هر جایی از کدهایمان درست مانند فراخوانی یک بلوک در زبان شیگرای C بهره ببریم.
به منظور انتقال این نوع از کلوژر به عنوان پارامتر یک تابع، ما باید از نوع کلوژر در تعریف تابع و به صورت زیر بهره ببریم :

 

let isEven = {
    (number: Int) -> Bool in
    let mod = number % 2;
    return (mod==0);
}
 
func verifyIfEven(number: Int, verifier:(Int->Bool)) ->Bool {
    return verifier(number);
}
 
verifyIfEven(12, isEven);
// returns true
 
verifyIfEven(19, isEven);
// returns false

 

کلاس ها و ساختارها :
کلاس ها :
حال وقت آن رسیده است تا در مورد مهمترین جزء یک زبان برنامه نویسی شیگراء، یعنی کلاس ها صحبت کنیم. همانطور که پیشتر گفته شد کلاسها به صورت کلی در یک فایل پیاده سازی واحد که با پسوند .swift می باشد تعریف شده اند. اعلانات مشخصه و متدها، همگی تحت این فایل تعریف شده اند.
به طور کلی ما کلاس را با استفاده از لغت کلیدی class و به دنبال آن نام کلاس تعریف می کنیم. بدنه کلاس، یعنی همان جایی که خصوصیات و رفتارها تعریف می شوند نیز در بین یک جفت آکولاد قرار می گیرند. درست به مانند الگوی دستوری زیر :

 

class Hotel {
    //properties
    //functions
}

 

به منظور ایجاد یک نمونه از کلاس Hotel باید از الگوی زیر استفاده کنیم :

 

let h = Hotel()

 

در زبان Swift هیچ نیازی به فراخوانی ini روی شیءها نیست، چرا که این حالت به صورت خودکار اتفاق می افتد.
ساختار ارث بری تحت این زبان درست به مانند زبان شیءگرای C  است. به این صورت که یک نماد دو نقطه نام کلاس پدر و فرزند را از یکدیگر جدا می کند. در مثال زیر، کلاس Hotel از کلاس BigHotel ارث می برد. در اینجا Hotel کلاس فرزند و BigHotel نیز کلاس پدر است :

 

class BigHotel: Hotel {
 
}

 

به مانند زبان شیگرای C، در زبان برنامه نویسی Swift نیز ما از نماد نقطه برای دسترسی به خصوصیات شیء استفاده می کنیم. به الگوی نوشتاری دستورات زیر دقت

کنید :

 

// Objective-C
UIView* view = [[UIView alloc] init];
[self.view addSubview:view];
 
// Swift
let view = UIView()
self.view.addSubview(view)

 

خصوصیات :
یکی از تفاوت های زبان شیگرای C و Swift این است که زبان Swift قادر به تشخیص متغیرهای نمونه و خصوصیات از یکدیگر نیست. در واقع یک متغیر نمونه یک مشخصه است.
اعلان یک مشخصه درست به مانند تعریف یک متغیر یا ثابت است که با استفاده از لغات کلیدی var و let صورت می پذیرد. تنها تفاوت موجود در واقع در ساختار کاربردی‌ای است که آنها تعریف شده اند که معنای کاربردی یک کلاس را مشخص می کند :

 

class Hotel {
    let rooms = 10
    var fullRooms = 0
}

 

در مثال بالا، rooms یک ثابت تغییر ناپذیر بوده که با مقدار 10 پر شده است. از آن طرف fullRooms نیز یک متغیر است که با مقدار پیشفرض 0 تنظیم شده، که بعدا می توانیم در صورت نیاز مقدار آن را تغییر دهیم.
اما قانونی که وجود دارد این است که خصوصیات باید به هنگام اعلان ارزش دهی یا همان مقدار دهی اولیه شوند. تنها استثناء در مورد این قانون، optionalها هستند که در بخش های بعدی مفصلاً در موردشان صحبت خواهیم کرد. با ما همراه باشید.
خصوصیات محاسبه شده(Computed properties) :
زبان برنامه نویسی Swift، همچنین می تواند خصوصیات محاسبه شده را تعریف کند. خصوصیات محاسبه شده چیزی بیشتر از دستورات setters و getters که قادر به ذخیره مقدار نبوده، نیستند. همانطور که از نام ها مشخص است، خصوصیات یا محاسبه شده اند یا به طور کل مورد ارزیابی قرار گرفته اند.
در زیر می توانید مثالی از یک مشخصه محاسبه شده را مشاهده کرده و بررسی کنید. در این مثال من مشخصه rooms را به یک متغیر تبدیل کرده تا به نتیجه مورد نظر برسیم . در ادامه کار متوجه خواهید شد که دلیل این کار چیست.

 

class Hotel {
    var rooms = 10
    var fullRooms = 0
    var description: String {
        get {
            return "Size of Hotel: \(rooms) rooms capacity:\(fullRooms)/\(rooms)"
        }
    }
}

 

به این علت که مشخصه description تنها خواندنی است و فقط شامل یک دستور برگشتی است، ما می توانیم از لغت کلیدی get و همچنین آکولادهای آن صرف نظر کرده و تنها دستور return را دست نخورده باقی بگذاریم. این مقدار کد برای ابتدای کار لازم است در ادامه کار ما از این مقدار کد در بین کدهای دیگر استفاده خواهیم کرد :

 

class Hotel {
    var rooms = 10
    var fullRooms = 0
    var description: String {
        return "Size of Hotel: \(rooms) rooms capacity:\(fullRooms)/\(rooms)"
    }   
}

 

ما همچنین می توانیم خصوصیات محاسبه شده را با حالت read-write تعریف کنیم. در کلاس Hotel که پیش از این تعریف کردیم، ما می خواهیم مشخصه emptyRoom، تعداد اتاق های خالی موجود در hotel را بگیرد، همچنین می خواهیم تا مشخصه fullRooms را هر زمان که مشخصه محاسبه شده emptyRooms را تنظیم کردیم، بروز شود. ما می توانیم این کار را با استفاده از لغت کلیدی set همانطور که در پایین ملاحظه می کنید انجام دهیم :

 

class Hotel {
    var rooms = 10
    var fullRooms = 0
    var description: String {
        return "Size of Hotel: \(rooms) rooms capacity:\(fullRooms)/\(rooms)"
    }   
    var emptyRooms :Int {
        get {
            return rooms - fullRooms
        }
        set {
            // newValue constant is available here
            // containing the passed value
            if(newValue < rooms) {
                fullRooms = rooms - newValue
            } else {
                fullRooms = rooms
            }
        }
    }
}
 
let h = Hotel()
h.emptyRooms = 3
h.description
// Size of Hotel: 10 rooms capacity:7/10

 

در بخش setter متعلق به emptyRooms، ثابت newValue به کمک ما آمده و مقداری را که به setter ارسال شده، ارائه می کند. همچنین مهم است که دقت داشته باشید، خصوصیات محاسبه شده همیشه با استفاده از لغت کلیدی var به عنوان متغیر اعلان می شوند. این امر به آن دلیل است که مقدار محاسبه شده توانایی تغییرپذیری دارد.
متدها :
پیش از این، مبحث توابع را در این مقاله تاحدی تحت پوشش قرار دادیم. حال نوبت به متدها رسیده است. به طور خلاصه اگر بخواهیم اشاره کنیم، در واقع متدها چیزی بیشتر از همان توابع که مقید به یک نوع مانند یک کلاس شده اند، نیستند. در مثال زیر ما از یک متد نمونه با نام bookNumberOfRooms در کلاسی با نام Hotel که پیش از این ایجاد شده استفاده کرده ایم :

 

class Hotel {
    var rooms = 10
    var fullRooms = 0
    var description: String {
        return "Size of Hotel: \(rooms) rooms capacity:\(fullRooms)/\(rooms)"
    }
    var emptyRooms :Int {
        get {
            return rooms - fullRooms
        }
        set {
            // newValue constant is available here
            // containing the passed value
            if(newValue < rooms) {
                fullRooms = rooms - newValue
            } else {
                fullRooms = rooms
            }
        }
 
    }
    func bookNumberOfRooms(room:Int = 1) -> Bool
    {
        if(self.emptyRooms>room) {
            self.fullRooms++;
            return true
        } else {
            return false
        }
    }
}
 
let h = Hotel()
h.emptyRooms = 7
h.description
//Size of Hotel: 10 rooms capacity:3/10
h.bookNumberOfRooms(room: 2)
// returns true
h.description
//Size of Hotel: 10 rooms capacity:5/10
h.bookNumberOfRoom()
// returns true
h.description
//Size of Hotel: 10 rooms capacity:6/10

 

ارزش دهنده های اولیه یا همان initializers :
ارزش دهنده اولیه پیشفرض برای کلیه کلاس ها تابع init در نظر گرفته شده است. در تابع init، ما مقادیر اولیه به ازای هر نمونه ای که ایجاد کرده ایم را تنظیم می کنیم.
به عنوان مثال، اگر ما به یک زیرکلاس با نام Hotel با 100 اتاق نیاز داشته باشیم، سپس ما همچنین نیاز به یک ارزش دهنده داریم تا مشخصه rooms را تحت مقدار 100 تنظیم کند.
حتماً به یاد دارید زمانی که من rooms را از یک ثابت به یک متغیر در کلاس Hotel تغییر دادم. دلیل اینکه ما نمی توانیم ثابت های ارثی را در یک زیرکلاس تغییر دهیم در واقع این است که تنها متغیرهای ارثی قادر به تغییر هستند. به مثال زیر دقت کنید :

ستند. به مثال زیر دقت کنید :
class BigHotel: Hotel {
    init() {
        super.init()
        rooms = 100
    }
}
 
let bh = BigHotel()
println(bh.description);
//Size of Hotel: 100 rooms capacity:0/100
ارزش دهنده ها یا همان Initializerها می توانند پارامترهایی را به عنوان ورودی بپذیرند. مثال زیر به شما نشان می دهد که این روش چگونه کار می کند :
class CustomHotel: Hotel {
    init(size:Int) {
        super.init()
        rooms = size
    }
}
 
let c = CustomHotel(size:20)
c.description
//Size of Hotel: 20 rooms capacity:0/20
بی اثر کردن خصوصیات محاسبه شده و متدها :

بی اثر کردن خصوصیات محاسبه شده و متدها یکی از دلچسب ترین کارهای قابل انجام در زبان برنامه نویسی Swift است. در زبان Swift، یک زیرکلاس می تواند کارکرد خصوصیات محاسبه شده و متدها را بی اثر کند. به منظور انجام این کار، ما از لغت کلیدی override بهره می بریم. حال اجازه دهید برای روشن شدن بیشتر قضیه، کارکرد مشخصه محاسبه شده description در کلاس CustomHotel را بی اثر کنیم. به دستورات زیر دقت کنید :
class CustomHotel: Hotel {
    init(size:Int) {
        super.init()
        rooms = size
    }
    override var description:String {
        return super.description + " Howdy!"
    }
}
 
let c = CustomHotel(size:20)
c.description
// Size of Hotel: 20 rooms capacity:0/20 Howdy!
نتیجه حاصله این است که description در واقع نتیجه مقدار نهایی متد description متعلق به کلاس پدر یا همان superclass را همراه با رشته "Howdy!" که به آن اضافه شده، بر میگرداند.
چیزی که در مورد بی اثر کردن کارایی مشخصه های محاسبه شده و متدها به نظر جالب می رسد در واقع لغت کلیدی override است. زمانی که کامپایلر به لغت کلیدی override می رسد، بررسی می کند تا ببیند کلاس پدر، متدی را که بی اثر شده، به کار می گیرد یا خیر.
همچنین کامپیالر بررسی می کند تا ببیند متدها و خواص یک کلاس با متدها و خواصی که در ساختار درختی ارث بری جایگاه بالاتری دارند تداخل ایجاد می کند یا خیر.
دقیقاً یادم نیست که چند بار یک هنگام مواجهه با متدهای overridden در زبان شیگرای C، به خاطر خطاهای تایپی از کوره در رفتم چرا که کد، بدون گفتن هیچ نشانه ای اجرا نمی شد. اما در زبان برنامه نویسی Swift، کامپایلر به صورت دقیق هر جا نیاز به توضیحی باشد آنرا به شما ارائه خواهد کرد.
ساختارها یا Structures :
ساختارها نیاز در زبان برنامه نویسی Swift، به مانند زبان های C و نوع شیگرای آن با لغت کلیدی strcut تعریف می شوند. با این تفاوت که ساختارها در زبان Swift بسیار قدرتمندتر نسبت به دو زبان گفته شده، طراحی شده اند. در زبان C، ساختارها تنها مقادیر و اشاره گر ها را تعریف می کنند. از آن طرف ساختارها در زبان Swift نیز به مانند ساختارها در C بوده با این تفاوت که از متدها و خصوصیات محاسبه شده نیز پشتیبانی می کنند.
هر آنچه که شما بتوانید با یک کلاس انجام دهید با ساختار نیز می توانید آن را انجام دهید. منتها دو تفاوت مهم در این بین وجود دارد :
ساختارها به مانند کلاسها، قادر به پشتیبانی از فرایند وراثت نیستند.
ساختارها به واسطه یک مقدار منتقل می شوند در حالی که کلاس ها به واسطه مرجع، مورد انتقال قرار می گیرند.
در دستورات زیر می توانید نحوه بکارگیری چند ساختار در زبان برنامه نویسی Swift را ملاحظه کنید :

 


struct Rect {
    var origin: Point
    var size: Size
    var area: Double {
        return size.width * size.height
    }
    func isBiggerThanRect(r:Rect) -> Bool {
        return (self.area > r.area)
    }
}
 
struct Point {
    var x = 0
    var y = 0
}
    
struct Size {
    var width = 0
    var height = 0
}

Optionals :راه حلی برای یک مسئله :
اگر از برنامه نویسان زبان شیگرای C باشید، مبحث Optionalها، یک مفهوم کاملاً جدید را برای شما تداعی می کند. در اصل وظیفه آنها این است  که هر مسئله ای که ما به عنوان برنامه نویس با آنها روبرو می شویم را حل و فصل کنند. به طور کلی زمانی که ما به یک متغیری دسترسی پیدا می کنیم که درباره مقدار آن مطمئن نیستیم، ما معمولاً یک نماینده یا indicator را به عنوان خروجی برمی گردانیم. این نماینده که با نام sentinel شناخته می شود برای این است که معین شود که مقدار برگشتی یک مقدار بی ارزش است. حال اجازه دهید تا با ذکر یک مثال از زبان شیگرای C، قضیه را روشن تر کنیم. با ما همراه باشید.
به مثال زیر دقت کنید :

 


NSString* someString = @"ABCDEF";
NSInteger pos = [someString rangeOfString:@"B"].location;
 
// pos = 1

 

در مثال بالا، ما سعی می کنیم به واسطه کدها، مکان و موقعیت @"B" را در someString پیدا کنیم. حال اگر @"B" پیدا شد، مکان یا موقعیت آن در pos ذخیره می شود. اما سوال اینجاست اگر @"B" در someString پیدا نشد چه اتفاقی خواهد افتاد؟
مستندات موجود نشان می دهد که در واقع rangeOfString:، مقدار NSRange را همراه با مکانی که تحت ثابت NSNotFound تنظیم شده، برمیگرداند. در مورد rangeOfString:، sentinel در اینجا با مقدار NSNotFound ذخیره می شود. در واقع کاربرد Sentinelها این است که مشخص کنند مقدار برگشتی معتبر نیست.
در Cocoa، از این مفهوم استفاده های زیادی می شود، اما مقدار Sentinel از یک دستور به دستور دیگر متفاوت است. این مقدار می تواند حالت های مقداری 0, -1, NULL, NSIntegerMax, INT_MAX, Nil را دربر داشته باشد.
مسئله‌ای که برای یک برنامه نویس وجود دارد این است که او باید به خاطر بیاورد که کدام sentinel تحت کدام context مورد استفاده قرار گرفته است. اگر برنامه نویس دقت نداشته باشد، این احتمال وجود دارد که مقدار معتبر برای یک sentinel یا بالعکس را اشتباه فرض کند. حال خبر خوب این است که زبان Swift این مشکل را با استفاده از optionalها حل کرده است.  در این بین توجه شما را به نقل قول آقای برایان لنیر در این زمینه جلب می کنم :
" optionalها در واقع یک sentinel (نگهبان) هستند تا بر تمامی آنها نظاره گر باشند".
Optionalها از دو وضعیت برخوردار هستند، یکی وضعیت nil که یعنی Optional هیچ مقداری را دربر ندارد و وضعیت دوم نیز بدان معناست که Optional دربر دارنده یک مقدار معتبر است. به طور کلی Optionalها را به عنوان یک بسته همراه با نشانگر تصور کنید که به شما اعلام می کند که محتویات بسته، معتبر هستند یا خیر.
استفاده و کاربرد :
تمامی انواع قابل تعریف در زبان برنامه نویسی Swift، می توانند به یک Optional تبدیل شود. برای این منظور کافی است تا یک نماد علامت سوال(؟) را بعد از اعلان نوع به مانند زیر اضافه کنید :

 


let someInt: Int?
 
// someInt == nil

 

ما می توانیم یک مقدار را به یک بسته optional درست به مانند ثابتها و متغیرها، نسبت دهیم :

 


someInt = 10
 
// someInt! == 10

 

به خاطر داشته باشید که optionalها، در واقع به مانند بسته ها هستند. زمانی که ما دستور let someInt: Int? را اعلان کردیم، ما همچنین یک جعبه خالی با مقدار nil را نیز تعریف کردیم. با ذخیره مقدار 10 در optional، جعبه شامل یک مقدار عددی می شود که برابر با 10 بوده و نشانگر یا indicator آن نیز مقدار not nil را نشان می دهد.
به منظور دسترسی به محتویات یک optional می توانیم از عملگر ! استفاده کنیم. البته باید پیش از باز کردن آن مطمئن شوید که optional شامل یک مقدار معتبر است.  در غیر این صورت با یک خطای زمان اجرا روبرو خواهید شد. با دقت به دستورات زیر متوجه خواهید شد که چگونه ما می توانیم به مقدار ذخیره شده تحت یک optional دسترسی پیدا کنیم. :

 


if ( someInt != nil) {
    println("someInt: \(someInt!)")
} else {
    println("someInt has no value")
}
 
// someInt: 10

 

الگوی دستوری بالا در زبان برنامه نویسی Swift بسیار متداول است. البته ما می توانیم بلوک کد بالا را با استفاده از optional binding و با کمک لغات کلیدی if let ساده تر کنیم. دستورات زیر همان دستورات بالا هستند با این تفاوت که ساده تر شده اند :

 


if let value = someInt {
    println("someInt: \(value)")
} else {
    println("someInt has no value")
}

 


Optionalها تنها نوعی هستند که قادر به نگهداری مقدار nil هستند. این بدان معناست که ثوابت و متغیرها قادر به نگهداری و ارزش دهی اولیه تحت مقدار nil نیستند. این در واقع یک نوع سیاست برای حفظ ایمنی دستورات Swift بوده و یعنی اینکه تمامی ثوابت و متغیرهای غیر optional باید دارای یک مقدار باشند.
مدیریت حافظه :
اگر به خاطر داشته باشید در گذشته و به هنگامی که ARC معرفی شد ما از لغات کلیدی strong و weak به منظور تعریف مالک شی استفاده می کردیم.
زبان Swift نیز همچنین از یک مدل مالک strong و weak برخوردار بوده با این تفاوت که یک مدل جدید دیگر با نام unowned نیز به این مجموعه اضافه شده است. حال اجازه دهید تا به هر یک از مدلهای مالک شی در زبان برنامه نویسی Swift نگاهی بیندازیم. با ما همراه باشید.
مدل strong :
مراجع Strong در زبان برنامه نویسی Swift به عنوان مدل پیشفرض مورد استفاده قرار می گیرد. اغلب اوقات، ما مالک شیءی می شویم که در حال ارجاء به آن هستیم..
چون ارجاعات Strong به صورت پیشفرض هستند، نیازی نیست تا به صورت آشکارا یک ارجاء strong به یک شیء یا هر ارجاعی را به یک ارجاء strong را به صورت مداوم ذکر کنیم..
مدل weak :
یک ارجاء weak در زبان برنامه نویسی Swift، نقاط ارجاء به یک شیءی که ما مسئولیتی در مورد حضور مستمر و پویای آن نداریم را مشخص می کند. این مدل اساساً بین دو شیءی مورد استفاده قرار می گیرد که نیازی به دیگری برای اینکه چرخه حضور شیء ادامه یابد نیست.
نکته ای که وجود دارد این است که در زبان برنامه نویسی Swift، ارجاعات weak همیشه باید متغیرهایی همراه با نوع optional باشند. این حالت به خاطر آن است که زمانی که شیء مورد ارجاء قرار گرفته از حالت اختصاص یافته خارج می شود به مقدار nil تبدیل می شوند. همانطور که در دستور زیر ملاحظه می کنید از لغت کلیدی weak به منظور اعلان یک متغیر به عنوان weak استفاده شده است :
weak var view: UIView?
مدل Unowned :
ارجاعات Unowned نوع جدیدی برای برنامه نویسان زبان شیگرای C به شمار می روند. یک ارجاع Unowned یعنی اینکه ما هیچ مسئولیتی من بابت پویا و پایدار نگه داشتن شی مورد ارجاع قرار گرفته نداریم درست به مانند ارجاعات weak.
اما تفاوتی که این حالت با weak دارد این است که یک ارجاع Unowned زمانی که شیء از حالت اختصاص یافته خارج می شود مقدار آن به nil تبدیل نمی شود. دیگر تفاوت مهم موجود این است که ارجاعات unowned به عنوان نوع non-optional تعریف نمی شوند. در حالی که این سیاست در مورد ارجاعات weak بالعکس است.
ارجاعات Unowned همچنین می توانند به عنوان ثابت در نظر گرفته شوند. یک شیء Unowned بدون مالک خود از هویتی برخوردار نبوده و بنابراین ارجاعات Unowned هرگز تحت مقدار nil تنظیم نمی شوند. ارجاعات Unowned قبل از اعلان متغیر یا ثابت به لغت کلیدی Unowned نیاز دارند. به مانند زیر :
unowned var view: UIView
نتیجه گیری :
زبان برنامه نویسی Swift با وجود اینکه سابقه حضور بلند مدتی در بین برنامه نویسان ندارد اما زبانی فوق العاده است که از ویژگی های بالقوه زیادی به نفع برنامه نویس استفاده می کند.
در پایان توصیه می کنم که اگر هنوز این پلتفرم کدنویسی را دریافت نکرده اید هر چه زودتر آن را از طریق لینک The Swift Programming Language به صورت رایگان دانلود کرده و کار با آن را شروع کنید. امیدوارم از این مقاله آموزشی بهره لازم را برده باشید.

مترجم:هادی نجار

منبع:code.tutsplus.com

تعداد بازدید : 3177

نظرات
آرمان
چقد خوووووووووووووب بوووووووووووود !!!! واقعا لازم داشتم
ناشناس
خیلی آموزشاتون عالیه.البته امیدوارم مباحث تخصصی تر و سنگین تر رو هم بیان کنید.با تشکر
ارسال نظر

سوال امنیتی : مجموع دو عدد 8 و 2 =