2016年4月11日 星期一

swift 學習筆記 4: Class and Structure

Class       : 抽象化分類型別, 實體化後稱作分類體
Structure : 抽象化結構型別, 實體化後稱作結構體

分類(class)及結構體(structure) 是程式建構中一般常用且很彈性的結構區塊,  裏面定義了屬性(property)及方法(method)用來運作分類及結構體的功能, 對於常數(constant),變數(variable)及程序(function) 它們都同樣使用相同的語法

不像其它程式語言, swift 並不需要將自訂的分類及結構分離成介面(interface)與實現(implementation)兩個檔案, 而是將分類及結構體定義在一個檔案裡, 其他程式便可以用其外部介面直接使用

分類的實體(instance)傳統上認知它就是一個物件. 但在 swift 裏面, 它更像是其他程式語言裡的程序, 本章大多數所敘述的程序都可以指定給實體, 因此 instance 被當成作是更廣泛的用語

分類與結構體的比較
相同點:
1. 定義屬性來保存數值(value)
2. 定義方法提供運作
3. 定義下標索引(subscript)方法,透過下標語法來取用內部數值
4. 定義起始程序設定初始狀態
5. 可以被擴展(extended)將預設的運用加以擴充
6. 可以與協定搭配來提供特定功能的標準運作

分類另外有著與結構體所不同的能力:
1. 分類可以繼承其它分類的特性
2. 型別標示(type casting)讓運行時可以檢視及解釋物件(class instance)的型別
3. 消滅程序(deinitalizer)讓物件可以釋放它所指定的資源
4. 參考計數(Reference counting)允許超過一個以上的物件來引用

宣告的語法
分類及結構體有相同的語法來宣告, 分別採是用關鍵字  class 及 structure , 且整個定義內容都是放在大括號 {} 裡頭, 例如

struct MystructDefinition {
// define propertys and methods
var width=0;
}

class   MyclassDefinition {
// define propertys and methods
var st =MystructDefinition()
var name:String?
}

let myInstance=MyclassDefinition()
let myInstance.name="A new instance"

當定義了一個分類及結構體後, 實際上是定義了一個全新的型別, 標準的 swift 型別名稱是將首字頭大寫相連接(NewClassName), 而屬性及方法的名稱則是用第一個字小寫(myPropertyOrMethod)命名,有別於型別名稱作區分, 可以參考上述的內容.

其中 MystructDefinition() 會將新的結構體實體化, 而 name 賦予了一個字串型別的 nil (表示空字串), 他是一個可無(optinonal)宣告
而 MyclassDefinition() 則是將分類允以實體化成物件, 如要取用物件屬性或方法等成員時, 使用句點語法 '.' 直接取用, 參考下面範例:

Class MyNewClass{
var name:String?
}
let a=MyNewClass()          // a is a constant of  new Class, so it can't be assignd in the next time.
let c=MyNewClass()          //  c is different from with a
a.name="My Name"         // but a.name is a variable defined in the class.
//  a class instance is a reference type, even if it is a constant reference, it's property can also be assigned a new value.
// but a structure instance is a value type, if it is a constant value, it's propety can't be assigned even if it was declared as var in structure.
c.name="Youe Name"     //  c also has a name property
let b=a                                    //  b refer to the same class as a
b.name="New Name"       //  a.name will be modified,too. but c.name doesn't

在上述例子中,新分類後面接了小括號(),就是將class實體化成一個新instance,該instance稱做class instance.
如果新結構後面接了小括號(),也是將struct實體化成一個新instance,該instance稱做structure instance.

所有 swift 的基本型別像是整數, 浮點數, 邏輯, 字串, 陣列, 字典等型別都是數值型別(value types), 它們是以結構體在幕後實現的.

在 swift 裡面,所有結構體及列舉體也都是數值型別, 這意味著當這些結構體及列舉體被傳遞(指定)時,將會整個複製過去,因此他並不會影響到別的實體

但分類體卻是一個參考型別(reference type),因此當結構體被實體化後,指定給一個常數或變數時,它其實是指向該分類體. 所有的參考到該分類體的instance都可以改變其內容, 且改的都是同一個實體

因此將 class instance 指定給一個新變數, 除非是實體化成一個新的分類體(如上述的 c), 否則只是將指標傳遞過去而已(如上述 let b=a), 並非將整個分類體複製過去

因於分類是屬於參照型別(reference type), 有別於數值型別(value type), 有可能在幕後好幾個常數或變數參考到相同的分類體(有別於結構體與列舉體,他們是將整個物件複製過去), 有時候要找出兩個常數或變數是否確實參考到相同的實體,可以透過用等效運算子( ===  或  !== )來檢視, 須注意的是, 等效並不是相等的意思,  等效運算指的是有無參照到相同的分類體


定義客制資料型態可以採用分類或結構當成是程式碼的架構區塊, 然而結構體總是傳值,而分類體總是傳參,這意味著他們適合不同的工作,對於要決定一個專案的資料結構及功能,需要考慮的是到底分類體好還是結構體好,底下有一些準則可以考慮使用結構
1.結構主要功用是將相當少量及簡單的資料數值加以打包
2.可以合理的預期打包的數值將會被複製而不是去參照
3.由結構體所儲存的任何屬性,他們本身是數值型別,同時預期這些東西將會被複製而不是去參照
4. 結構體不需要繼承別的已存在類型的屬性或行為

一些候選使用結構體的例子包括
1. 幾合型態的尺寸,譬如長寬都用精密(Double)型別
 2. 一系列範圍參考方式,譬如起點及長度都用整數(Int)型別
 3. 三維座標系統的點, 譬如x,y,z 屬性都用精密(Double)型別

在 swiftt 裡, 基本資料型別像 Sting, Array, Dictionary 是使用結構體來實現,這意味著當它被賦予後指定給一個新常數或變數時,將會被整個複製過去, 或者當他們傳給程序(function)或方法(method)時也是如此(實際上, swift 在幕後, 只有當需要複製時才會執行搬運的動作. 他會處理所有數值的複製工作.以保證效能最佳化,你並不應該為了搶佔效能而去避免指定工作)
但在 Foundation 裡 NSString, NSArray, NSDitionary 是用分類而非結構來實現的, 與上述行為並不相同, 因此再 Foundation 裡的字串,陣列,及字典等總是將已存在本尊的指標傳過去,而非將本尊整個複製過去



沒有留言: