枚舉
- 聲明
//enum 關(guān)鍵字
enum Season { //新的數(shù)據(jù)類型,首字母大寫
case Spring
case Summer
case Autumn
case Winter
}
//也可以這樣簡(jiǎn)寫
enum Season {
case Spring, Summer, Autumn, Winter
}
- 獲取
var season = Season.Summer
var season:Season = Season.Summer //顯式
var season:Season = .Summer //可以這么簡(jiǎn)寫
- 原始值
可以給枚舉變量賦原始值 (Raw Value),例如:
enum Fruit:Int {
case Apple = 1
case Orange = 2
case Banana = 3
case Watermelon = 4
}
let fruit = Fruit(rawValue: 2) //返回值為可選型
Fruit.Watermelon.rawValue //4
//解包
if let fruit = Fruit(rawValue: 2) {
//do something
}
此外,關(guān)于原始值,還有其他用法,例如:
//可以只寫第一個(gè),后面的會(huì)依次加1
enum Fruit:Int {
case Apple = 1, Orange, Banana, Watermelon
}
//也可以都不寫,則默認(rèn)從0開始,依次加1
enum Fruit:Int {
case Apple, Orange, Banana, Watermelon
}
//定義是整型值的也可以不連續(xù)
enum Coin:Int {
case Penny = 1
case Nickel = 5
case Dime = 10
case Quarter = 25
}
//枚舉類型的值可以是 String 類型,例如:
enum ProgrammingLanguage:String {
case Swift = "Swift"
case Java = "Java"
case OC = "OC"
}
//若不初始化,則默認(rèn)是定義的字符
enum ProgrammingLanguage:String {
case Swift, Java, OC //即,分別是 "Swift", "Java", "OC"
}
- 關(guān)聯(lián)值
關(guān)聯(lián)值(Associate Value):可以關(guān)聯(lián)不同類型,而且可修改(與 Raw Value 互斥),例如:
enum ATMStatus {
case Success(Int)
case Error(String)
}
//也可有部分沒有關(guān)聯(lián)值
enum ATMStatus {
case Success(Int)
case Error(String)
case Waiting //無關(guān)聯(lián)值
}
使用舉例:
var balance = 1000 //余額
func withdraw(amount:Int) -> ATMStatus {
if balance >= amount {
balance -= amount
return .Success(balance) //可以這樣簡(jiǎn)寫
}
else {
return .Error("Not enough money")
}
}
let result = withdraw(100)
switch result {
case let .Success(newBalance):
print("¥\(newBalance) left in your count")
case let .Error(errorMessage):
print("Error: \(errorMessage)")
}
此外,還可以關(guān)聯(lián)多個(gè)值(其實(shí)是關(guān)聯(lián)了一個(gè)元組),例如:
enum Shape {
case Square(side:Double) //可以分別關(guān)聯(lián)不同的值
case Rectangle(width:Double, height:Double)
case Circle(centerX:Double, centerY:Double, radius:Double)
case Point
}
func area(shape:Shape) -> Double {
switch shape {
case let .Square(side):
return side * side
case let .Rectangle(width, height):
return width * height
case let .Circle( _, _, radius): //忽略一些變量
return M_PI * radius * radius //M_PI 為 π
case .Point:
return 0
}
}
//使用
let square = Shape.Square(side: 3)
let rectangle = Shape.Rectangle(width: 5, height: 3)
let circle = Shape.Circle(centerX: 6, centerY: 7, radius: 3)
let point = Shape.Point
- 遞歸枚舉
//使用關(guān)鍵字 indirect
indirect enum ArithmeticExpression {
case Number(Int)
case Addition(ArithmeticExpression, ArithmeticExpression) //調(diào)用了本身
case Multiplication(ArithmeticExpression, ArithmeticExpression)
}
//或者這樣寫
enum ArithmeticExpression2 {
case Number(Int)
indirect case Addition(ArithmeticExpression, ArithmeticExpression)
indirect case Multiplication(ArithmeticExpression, ArithmeticExpression)
}
//計(jì)算 (5 + 4) * 2 舉例:
let five = ArithmeticExpression.Number(5)
let four = ArithmeticExpression.Number(4)
let sum = ArithmeticExpression.Addition(five, four)
let two = ArithmeticExpression.Number(2)
let product = ArithmeticExpression.Multiplication(sum, two)
func evaluate(expression:ArithmeticExpression) -> Int {
switch expression {
case let .Number(value):
return value
case let .Addition(left, right):
return evaluate(left) + evaluate(right)
case let .Multiplication(left, right):
return evaluate(left) * evaluate(right)
}
}
evaluate(product)
evaluate(sum)
- 修改自身變量
枚舉中,若想通過方法對(duì)自身變量進(jìn)行修改,需要使用 mutating
關(guān)鍵字,例如:
enum Switch {
case On
case Off
mutating func click() {
switch self {
case .On:
self = .Off
case .Off:
self = .On
}
}
}
結(jié)構(gòu)體
- 聲明
//struct 關(guān)鍵字
struct Location { //新的數(shù)據(jù)類型,首字母大寫
let latitude:Double //若不初始化,則默認(rèn)沒有值。且 let 只能初始化一次
let longitude:Double
var placeName:String? //若為可選型,默認(rèn)初始化為 nil
}
//初始化一個(gè)結(jié)構(gòu)體(調(diào)用了默認(rèn)的構(gòu)造函數(shù),參數(shù)順序不能變)
let appleHeadQuarterLocation = Location(latitude: 37.3230, longitude: -122.0322)
//注意:只有 appleHeadQuarterLocation 和 latitude 都為 var 類型時(shí)才能對(duì) latitude 進(jìn)行修改。
//結(jié)構(gòu)體中變量的類型也可以是結(jié)構(gòu)體,例如:
struct Place {
let location:Location //Location 為結(jié)構(gòu)體類型
var name:String
}
- 構(gòu)造函數(shù)
struct Location2 {
var latitude:Double = 0 //可以賦初值
var longitude:Double = 0
}
Location2() //賦初值后可以這樣使用,調(diào)用了默認(rèn)的構(gòu)造函數(shù)
Location2().latitude
自定義構(gòu)造函數(shù):
struct Location3 {
let latitude:Double
let longitude:Double
//自定義構(gòu)造函數(shù) (使用 init 關(guān)鍵字)
init(coordinateString: String){
let commaIndex = coordinateString.rangeOfString(",")!.startIndex //這里暫時(shí)使用了強(qiáng)制解包,后文再解決這個(gè)問題
let firstElement = coordinateString.substringToIndex(commaIndex)
let secondElement = coordinateString.substringFromIndex(commaIndex.successor())
latitude = Double(firstElement)!
longitude = Double(secondElement)!
}
//注意:若添加了自定義的構(gòu)造函數(shù)后,默認(rèn)的構(gòu)造函數(shù)就不能用了
//此時(shí),建議再寫出默認(rèn)的構(gòu)造函數(shù),即:
init(latitude:Double, longitude:Double){
self.latitude = latitude
self.longitude = longitude
}
}
- 可失敗的構(gòu)造函數(shù)
結(jié)構(gòu)體可以有可失敗的構(gòu)造函數(shù)(Failable-Initializer ),即,如果構(gòu)造失敗,返回為 nil
。例如:
struct Location {
let latitude:Double
let longitude:Double
//可失敗的構(gòu)造函數(shù)
init?(coordinateString: String){
if let commaIndex = coordinateString.rangeOfString(",")?.startIndex {
if let firstElement = Double(coordinateString.substringToIndex(commaIndex)) {
if let secondElement = Double(coordinateString.substringFromIndex(commaIndex.successor())) {
self.latitude = firstElement
self.longitude = secondElement
}
else {
return nil
}
}
else {
return nil
}
}
else {
return nil
}
}
init(latitude:Double, longitude:Double){
self.latitude = latitude
self.longitude = longitude
}
}
上述構(gòu)造函數(shù)使用了多個(gè) if...else
語(yǔ)句,看起來很復(fù)雜。我們可以使用 guard
關(guān)鍵字來簡(jiǎn)化,使代碼條理更清晰。例如:
struct Location {
...
init?(coordinateString: String){
//使用 guard 關(guān)鍵字可以使條理更清晰
// guard let commaIndex = coordinateString.rangeOfString(",")?.startIndex else {
// return nil
// }
// guard let firstElement = Double(coordinateString.substringToIndex(commaIndex)) else {
// return nil
// }
// guard let secondElement = Double(coordinateString.substringFromIndex(commaIndex.successor())) else {
// return nil
// }
//還可以更加簡(jiǎn)潔的這樣寫
guard
let commaIndex = coordinateString.rangeOfString(",")?.startIndex,
let firstElement = Double(coordinateString.substringToIndex(commaIndex)),
let secondElement = Double(coordinateString.substringFromIndex(commaIndex.successor()))
else {
return nil
}
self.latitude = firstElement
self.longitude = secondElement
}
...
}
- 修改自身變量
同枚舉一樣,結(jié)構(gòu)體中,若想使用方法對(duì)自身變量進(jìn)行修改,也需要使用關(guān)鍵字 mutating
,例如:
struct Location {
var x = 0
mutating func go() { //自己改變自己
self.x += 1
}
}
類
- 聲明
Swift
中的類和結(jié)構(gòu)體很相似。使用關(guān)鍵字 class
,示例如下:
class Person {
//成員變量
var firstName:String
var lastName:String
var career:String? //可選型變量可以不初始化,默認(rèn)為 nil
//構(gòu)造函數(shù)
init(firstName:String, lastName:String){
self.firstName = firstName
self.lastName = lastName
}
}
- 可失敗的構(gòu)造函數(shù)
同結(jié)構(gòu)體一樣,類也有可失敗的構(gòu)造函數(shù),構(gòu)造對(duì)象失敗后返回 nil
。例如:
init?(fullName:String){
guard
let spaceindex = fullName.rangeOfString(" ")?.startIndex
else {
return nil
}
self.firstName = fullName.substringToIndex(spaceindex)
self.lastName = fullName.substringFromIndex(spaceindex.successor())
}
- 引用類型
類是引用類型。
let person1 = Person(firstName: "Edward", lastName: "Newgate")
let person2 = person1
person2.firstName = "Steve"
person2.lastName = "Jobs"
person2.career = "CEO"
//對(duì) person2 修改時(shí),person1 也改變了。(因?yàn)槎咧赶虻氖峭粋€(gè)對(duì)象)
- 類的等價(jià)
判斷類的兩個(gè)對(duì)象是否等價(jià),判斷的是其引用是否指向同一塊內(nèi)存。使用 ===
表示,例如:
person1 === person2 //false, 判斷引用類型(比較的引用,是否指向同一塊內(nèi)存)
person1 === person3 //true
person1 !== person2 //true, 不等于,即不是同一塊內(nèi)存
屬性和方法
- 計(jì)算屬性
計(jì)算屬性:依賴其他屬性而存在的屬性。
struct Point {
var x = 0.0
var y = 0.0
}
struct Size {
var width = 0.0
var height = 0.0
}
class Rectangle {
var origin = Point()
var size = Size()
//計(jì)算屬性
// var area:Double{
// return size.width * size.height
// }
//也可以這樣聲明
var area:Double{
get{
return size.width * size.height
}
}
//getter, setter
var center:Point { //必須為 var 類型,且顯式聲明類型
//getter
get {
let centerX = origin.x + size.width/2
let centerY = origin.y + size.height/2
return Point(x: centerX, y: centerY)
}
//setter
// set(newCenter) {
// origin.x = newCenter.x - size.width/2
// origin.y = newCenter.y - size.height/2
// }
set { //可以這么寫,newValue 是默認(rèn)值
origin.x = newValue.x - size.width/2
origin.y = newValue.y - size.height/2
}
}
init(origin:Point, size:Size){
self.origin = origin
self.size = size
}
}
- 類型屬性
類型屬性,即類的屬性,相當(dāng)于靜態(tài)變量,使用 static
關(guān)鍵字。例如:
class Player {
var name:String
var score = 0 //個(gè)人總分
static var highestScore = 0 //所有玩家最高分,類的屬性 (static 關(guān)鍵字)
init(name:String){
self.name = name
}
}
- 類型方法
類型方法,即類的方法,相當(dāng)于靜態(tài)方法,使用 static
關(guān)鍵字。例如:
class Matrix {
var m:[[Int]] //二維數(shù)組
var row:Int
var col:Int
...
//類方法,生成單位矩陣
static func identityMatrix(n:Int) -> Matrix? {
if n <= 0 {
return nil
}
var arr2d:[[Int]] = []
for i in 0..<n {
var row = [Int](count:n, repeatedValue:0) //生成一行全為0的元素
row[i] = 1
arr2d.append(row) //添加到二維數(shù)組中
}
return Matrix(arr2d)
}
}
- 屬性觀察器
屬性觀察器可以監(jiān)測(cè)一個(gè)屬性,在其將要改變或改變后進(jìn)行一些操作。示例代碼如下:
class LightBulb {
static let maxCurrent = 30
var current = 0 {
//賦值前的邏輯
// willSet(newCurrent){ //新的值,可以省略不寫,使用系統(tǒng)默認(rèn)值 newValue
// print("new current is \(newCurrent)")
// }
willSet{ //效果同前者
print("new current is \(newValue)")
}
//賦值完成后做的事情
didSet(oldCurrent){ //oldCurrent 表示原來的值,可以省略不寫,使用系統(tǒng)默認(rèn)值 oldValue
if current == LightBulb.maxCurrent {
print("The current value get to the maximum point.")
}
else if current > LightBulb.maxCurrent {
print("current too hight, falling back to previous one.")
current = oldCurrent
}
print("The current is \(current)")
}
}
}
- 延遲屬性
延遲屬性,lazy
關(guān)鍵字。一個(gè)屬性加載一次后保存其結(jié)果,避免每次都重新加載。示例代碼:
class Book {
let name:String
//延遲屬性
lazy var content:String? = {
return nil
}()
init(name:String){
self.name = name
}
}
- 訪問控制
public: 可以被模塊外訪問。
internal: 可以被本模塊訪問。
private: 可以被本文件訪問。
繼承和構(gòu)造函數(shù)
- 繼承
示例代碼(這里 Guldan 類繼承自 Hero 類):
public class Hero {
var name:String
var life:Int = 100
public init(name:String){
self.name = name
}
}
final class Guldan: Hero {
}
注:若不想一個(gè)類被繼承,可在前面添加 final
關(guān)鍵字。
- 重寫
重寫/覆蓋 (關(guān)鍵字override
),就是子類重寫父類的屬性和方法。示例代碼:
//父類
public class Hero {
var name:String
var life:Int = 100
var description:String{
return "I'm \(name)."
}
func beAttacked(attack:Int) {
life -= 10
}
public init(name:String){
self.name = name
}
}
//子類,使用了 final 關(guān)鍵字, 該類不可被繼承
final class Guldan: Hero {
//屬性重寫 (override 關(guān)鍵字)
override var description: String{
return "Your soul belongs to me!"
}
//構(gòu)造方法重寫
override init(name: String) { //構(gòu)造方法重載
self.group = ""
print("my name is \(name)")
super.init(name: name)
}
//方法重寫
override func beAttacked(attack: Int) {
life -= 15
}
}
注:若不想方法被重寫,可以在方法前使用 final
關(guān)鍵字。
- 便利構(gòu)造函數(shù)和指定構(gòu)造函數(shù)
便利構(gòu)造函數(shù)(關(guān)鍵字 convenience
),是在構(gòu)造函數(shù)中調(diào)用了其他的構(gòu)造函數(shù)。而其他的構(gòu)造函數(shù)則成為指定的 (designated) 構(gòu)造函數(shù)。示例代碼:
//父類
public class Hero {
...
//指定的構(gòu)造函數(shù)
public init(name:String){
self.name = name
}
}
//子類
final class Guldan: Hero {
//構(gòu)造函數(shù)重寫
override init(name: String) { //構(gòu)造方法重載
self.group = ""
print("my name is \(name)")
super.init(name: name)
}
//便利的構(gòu)造函數(shù)
convenience init(firstName:String, lastName:String){
self.init(name:firstName + " " + lastName) //調(diào)用指定的初始化函數(shù)
}
...
}
- 構(gòu)造函數(shù)的繼承
子類構(gòu)造函數(shù)的繼承原則:
- 如果子類沒有實(shí)現(xiàn)任何父類的指定構(gòu)造函數(shù),則自動(dòng)繼承父類所有的指定構(gòu)造函數(shù)。
- 如果子類實(shí)現(xiàn)了父類所有的指定構(gòu)造函數(shù),則自動(dòng)繼承父類所有的便利構(gòu)造函數(shù)。
其他
- 文檔和注釋
三條斜杠 ///
可以生成文檔注釋;
使用 MARK
, TODO
和 FIXME
可以給代碼添加一些提醒,示例如下:
//MARK: - init 方法
//TODO: 有待添加一些功能
//FIXME: 有些不影響程序運(yùn)行的小問題,有待以后調(diào)整
效果如圖所示: