標籤:
Swift是蘋果公司開發的一門新語言,它當然具備物件導向的許多特性,現在開始介紹Swift中類和對象的文法。
對象和類
用"class"加上類名字來建立一個類,屬性聲明和聲明常量或者變數是一樣的,只是它是在類裡邊聲明的而已。方法和函式宣告也是一樣的:
class Shape { var numberOfSides = 0 func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." }}
建立類對象也很簡單,注意這裡沒有用new關鍵字,類對象的屬性和方法的訪問方式是通過.實現的
var shape = Shape()shape.numberOfSides = 7var shapeDescription = shape.simpleDescription()
類的聲明裡邊,通常都會有初始化方法init,
class NamedShape { var numberOfSides: Int = 0 var name: String init(name: String) { self.name = name } func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." }}
注意這裡用self來指代當前類對象,這樣就區分了屬性name和傳入init方法的參數name。
每個屬性都需要被賦值,要麼在聲明它的時候,或者在初始化方法中。
用deinit方法來建立解構函數,在類對象被釋放之前做一些清理工作。
類的繼承文法也很簡單,用冒號加上父類名稱就可以了。沒有約定子類必須要繼承自哪些根類,因此繼承不是必須的。子類通過override標識覆蓋父類方法。如果子類中有與父類同名的方法而沒有override,則編譯器會報錯。編譯器也會探測標識了override但是父類中又沒有同名的方法。
class Square: NamedShape { var sideLength: Double init(sideLength: Double, name: String) { self.sideLength = sideLength super.init(name: name) numberOfSides = 4 } func area() -> Double { return sideLength * sideLength } override func simpleDescription() -> String { return "A square with sides of length \(sideLength)." }}let test = Square(sideLength: 5.2, name: "my test square")test.area()test.simpleDescription()
簡單屬性可以直接儲存,屬性也可以有存取器:
class EquilateralTriangle: NamedShape { var sideLength: Double = 0.0 init(sideLength: Double, name: String) { self.sideLength = sideLength super.init(name: name) numberOfSides = 3 } var perimeter: Double { get { return 3.0 * sideLength } set { sideLength = newValue / 3.0 } } override func simpleDescription() -> String { return "An equilateral triangle with sides of length \(sideLength)." }}var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")println(triangle.perimeter)triangle.perimeter = 9.9println(triangle.sideLength)
在setter中,新值的名稱隱式地是newValue,也可以在set後顯示地指明別的名稱。
如果你的屬性不需要計算,但是在設定值之前或者之後仍然需要寫一些邏輯,可以用willSet和didSet,比如,下邊的類就確保它的三角形的邊長和正方形的邊長始終相等:
class TriangleAndSquare { var triangle: EquilateralTriangle { willSet { square.sideLength = newValue.sideLength } } var square: Square { willSet { triangle.sideLength = newValue.sideLength } } init(size: Double, name: String) { square = Square(sideLength: size, name: name) triangle = EquilateralTriangle(sideLength: size, name: name) }}var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")println(triangleAndSquare.square.sideLength)println(triangleAndSquare.triangle.sideLength)triangleAndSquare.square = Square(sideLength: 50, name: "larger square")println(triangleAndSquare.triangle.sideLength)
類的方法和一般函數有一個很重要的區別。一般函數的參數名只在函數內部被用到,但是類方法的參數名在你調用方法的時候也被用到了(第一個參數除外)。預設情況下,當你調用某個方法的時候,該方法與其內部都有相同的參數名。你可以指定另外的名稱,這個名稱將在方法內部使用:
class Counter { var count: Int = 0 func incrementBy(amount: Int, numberOfTimes times: Int) { count += amount * times }}var counter = Counter()counter.incrementBy(2, numberOfTimes: 7)
當處理可省略變數的時候,可以在運算比如屬性、方法、下標操作之前加上問號。如果問號之前的值是nil,問號之後的所有運算式被忽略掉,整個運算式的值也是nil。否則,可省略值被展開,問號之後的所有運算式都基於展開的可省略值。無論如何,整個運算式的值都是可省略值。
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")let sideLength = optionalSquare?.sideLength
枚舉類型和結構體
用enum來建立枚舉類型變數。像類和其他類型一樣,枚舉類型也可以有與之相應的方法:
enum Rank: Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King func simpleDescription() -> String { switch self { case .Ace: return "ace" case .Jack: return "jack" case .Queen: return "queen" case .King: return "king" default: return String(self.rawValue) } }}let ace = Rank.Ace //Enum Value
let aceRawValue = ace.rawValue //1
在上邊的例子裡,枚舉類型變數Rank的原始類型(raw-type)是Int類型,因此只需要給第一個值賦值,剩下的值會一次自動賦予。也可以把枚舉變數的原始類型設定為字串或者浮點數,用rawValue來擷取枚舉變數的原始值。用init?(rawValue:)初始化器從一個原始值建立一個枚舉類型的執行個體。
if let convertedRank = Rank(rawValue: 3) { let threeDescription = convertedRank.simpleDescription()}
枚舉類型的成員值就是實際的值,並不是原始值(raw value)的另一種書寫方式,事實上,並沒有所謂的真正意義上的原始值,並不需要為每個枚舉類型成員賦原始值
enum Suit { case Spades, Hearts, Diamonds, Clubs func simpleDescription() -> String { switch self { case .Spades: return "spades" case .Hearts: return "hearts" case .Diamonds: return "diamonds" case .Clubs: return "clubs" } }}let hearts = Suit.Heartslet heartsDescription = hearts.simpleDescription()
注意這裡用了兩種引用枚舉類型執行個體的成員值的方式:當把它作為值複製給常量hearts時,是用的顯示地指明全稱Suit.Hearts,因為常量沒有隱式地指明類型;而在switch內部,枚舉類型的成員值是用簡寫方式.Hearts被引用的,這是因為self的類型已經是已知合適的類型了。在任何變數類型已知並且合適的時候,都可以使用這種簡寫方式。
結構體
用struct關鍵字來建立結構體,結構體支援很多類的行為,包括方法和初始化器。結構體和類最大的區別在於當在代碼裡傳遞的時候,結構體永遠是被拷貝的,而類只傳遞了引用。
struct Card { var rank: Rank var suit: Suit func simpleDescription() -> String { return "The \(rank.simpleDescription()) of \(suit.simpleDescription())" //在字串中直接參考資料表達式或者變數 }}let threeOfSpades = Card(rank: .Three, suit: .Spades) //注意這種簡寫形式,是因為rank和suit的變數類型都已經確定了let threeOfSpadesDescription = threeOfSpades.simpleDescription()
枚舉類型成員的執行個體可以擁有和執行個體關聯的值(associated value),枚舉類型成員的不同執行個體可以有不同的值和它們相關聯,這些關聯值是在建立執行個體的時候提供的。
關聯值(associated value)和原始值(raw value)是不同的:枚舉類型成員的原始值對所有執行個體而言是相同的,在定義該枚舉類型的時候就需要給出原始值。
舉個栗子,在向一個伺服器請求日出和日落時間的資料,伺服器的返回分為兩種情況:返回相應的時間或者返回一個錯誤
enum ServerResponse { case Result(String, String) case Error(String)} let success = ServerResponse.Result("6:00 am", "8:09 pm")let failure = ServerResponse.Error("Out of cheese.") switch success {case let .Result(sunrise, sunset): let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."case let .Error(error): let serverResponse = "Failure... \(error)"}
注意sunrise和sunset是如何作為匹配switch的case的一部分從ServerResponse中被取出的。
Swift學習筆記二