枚舉
- 聲明
//enum 關鍵字
enum Season { //新的數據類型不见,首字母大寫
case Spring
case Summer
case Autumn
case Winter
}
//也可以這樣簡寫
enum Season {
case Spring, Summer, Autumn, Winter
}
- 獲取
var season = Season.Summer
var season:Season = Season.Summer //顯式
var season:Season = .Summer //可以這么簡寫
- 原始值
可以給枚舉變量賦原始值 (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
}
此外,關于原始值,還有其他用法袋狞,例如:
//可以只寫第一個,后面的會依次加1
enum Fruit:Int {
case Apple = 1, Orange, Banana, Watermelon
}
//也可以都不寫映屋,則默認從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"
}
//若不初始化棚点,則默認是定義的字符
enum ProgrammingLanguage:String {
case Swift, Java, OC //即早处,分別是 "Swift", "Java", "OC"
}
- 關聯(lián)值
關聯(lián)值(Associate Value):可以關聯(lián)不同類型,而且可修改(與 Raw Value 互斥)瘫析,例如:
enum ATMStatus {
case Success(Int)
case Error(String)
}
//也可有部分沒有關聯(lián)值
enum ATMStatus {
case Success(Int)
case Error(String)
case Waiting //無關聯(lián)值
}
使用舉例:
var balance = 1000 //余額
func withdraw(amount:Int) -> ATMStatus {
if balance >= amount {
balance -= amount
return .Success(balance) //可以這樣簡寫
}
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)")
}
此外砌梆,還可以關聯(lián)多個值(其實是關聯(lián)了一個元組),例如:
enum Shape {
case Square(side:Double) //可以分別關聯(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
- 遞歸枚舉
//使用關鍵字 indirect
indirect enum ArithmeticExpression {
case Number(Int)
case Addition(ArithmeticExpression, ArithmeticExpression) //調用了本身
case Multiplication(ArithmeticExpression, ArithmeticExpression)
}
//或者這樣寫
enum ArithmeticExpression2 {
case Number(Int)
indirect case Addition(ArithmeticExpression, ArithmeticExpression)
indirect case Multiplication(ArithmeticExpression, ArithmeticExpression)
}
//計算 (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)
- 修改自身變量
枚舉中贬循,若想通過方法對自身變量進行修改咸包,需要使用 mutating
關鍵字,例如:
enum Switch {
case On
case Off
mutating func click() {
switch self {
case .On:
self = .Off
case .Off:
self = .On
}
}
}
結構體
- 聲明
//struct 關鍵字
struct Location { //新的數據類型杖虾,首字母大寫
let latitude:Double //若不初始化烂瘫,則默認沒有值。且 let 只能初始化一次
let longitude:Double
var placeName:String? //若為可選型奇适,默認初始化為 nil
}
//初始化一個結構體(調用了默認的構造函數坟比,參數順序不能變)
let appleHeadQuarterLocation = Location(latitude: 37.3230, longitude: -122.0322)
//注意:只有 appleHeadQuarterLocation 和 latitude 都為 var 類型時才能對 latitude 進行修改芦鳍。
//結構體中變量的類型也可以是結構體,例如:
struct Place {
let location:Location //Location 為結構體類型
var name:String
}
- 構造函數
struct Location2 {
var latitude:Double = 0 //可以賦初值
var longitude:Double = 0
}
Location2() //賦初值后可以這樣使用温算,調用了默認的構造函數
Location2().latitude
自定義構造函數:
struct Location3 {
let latitude:Double
let longitude:Double
//自定義構造函數 (使用 init 關鍵字)
init(coordinateString: String){
let commaIndex = coordinateString.rangeOfString(",")!.startIndex //這里暫時使用了強制解包怜校,后文再解決這個問題
let firstElement = coordinateString.substringToIndex(commaIndex)
let secondElement = coordinateString.substringFromIndex(commaIndex.successor())
latitude = Double(firstElement)!
longitude = Double(secondElement)!
}
//注意:若添加了自定義的構造函數后,默認的構造函數就不能用了
//此時注竿,建議再寫出默認的構造函數茄茁,即:
init(latitude:Double, longitude:Double){
self.latitude = latitude
self.longitude = longitude
}
}
- 可失敗的構造函數
結構體可以有可失敗的構造函數(Failable-Initializer ),即巩割,如果構造失敗裙顽,返回為 nil
。例如:
struct Location {
let latitude:Double
let longitude:Double
//可失敗的構造函數
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
}
}
上述構造函數使用了多個 if...else
語句宣谈,看起來很復雜愈犹。我們可以使用 guard
關鍵字來簡化,使代碼條理更清晰闻丑。例如:
struct Location {
...
init?(coordinateString: String){
//使用 guard 關鍵字可以使條理更清晰
// 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
// }
//還可以更加簡潔的這樣寫
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
}
...
}
- 修改自身變量
同枚舉一樣漩怎,結構體中,若想使用方法對自身變量進行修改嗦嗡,也需要使用關鍵字 mutating
勋锤,例如:
struct Location {
var x = 0
mutating func go() { //自己改變自己
self.x += 1
}
}
類
- 聲明
Swift
中的類和結構體很相似。使用關鍵字 class
侥祭,示例如下:
class Person {
//成員變量
var firstName:String
var lastName:String
var career:String? //可選型變量可以不初始化叁执,默認為 nil
//構造函數
init(firstName:String, lastName:String){
self.firstName = firstName
self.lastName = lastName
}
}
- 可失敗的構造函數
同結構體一樣,類也有可失敗的構造函數矮冬,構造對象失敗后返回 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"
//對 person2 修改時胎署,person1 也改變了吆录。(因為二者指向的是同一個對象)
- 類的等價
判斷類的兩個對象是否等價,判斷的是其引用是否指向同一塊內存琼牧。使用 ===
表示恢筝,例如:
person1 === person2 //false, 判斷引用類型(比較的引用,是否指向同一塊內存)
person1 === person3 //true
person1 !== person2 //true, 不等于障陶,即不是同一塊內存
屬性和方法
- 計算屬性
計算屬性:依賴其他屬性而存在的屬性滋恬。
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()
//計算屬性
// 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 是默認值
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
}
}
- 類型屬性
類型屬性恢氯,即類的屬性,相當于靜態(tài)變量,使用 static
關鍵字勋拟。例如:
class Player {
var name:String
var score = 0 //個人總分
static var highestScore = 0 //所有玩家最高分勋磕,類的屬性 (static 關鍵字)
init(name:String){
self.name = name
}
}
- 類型方法
類型方法,即類的方法敢靡,相當于靜態(tài)方法挂滓,使用 static
關鍵字。例如:
class Matrix {
var m:[[Int]] //二維數組
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) //添加到二維數組中
}
return Matrix(arr2d)
}
}
- 屬性觀察器
屬性觀察器可以監(jiān)測一個屬性赶站,在其將要改變或改變后進行一些操作。示例代碼如下:
class LightBulb {
static let maxCurrent = 30
var current = 0 {
//賦值前的邏輯
// willSet(newCurrent){ //新的值纺念,可以省略不寫贝椿,使用系統(tǒng)默認值 newValue
// print("new current is \(newCurrent)")
// }
willSet{ //效果同前者
print("new current is \(newValue)")
}
//賦值完成后做的事情
didSet(oldCurrent){ //oldCurrent 表示原來的值,可以省略不寫陷谱,使用系統(tǒng)默認值 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
關鍵字。一個屬性加載一次后保存其結果烟逊,避免每次都重新加載渣窜。示例代碼:
class Book {
let name:String
//延遲屬性
lazy var content:String? = {
return nil
}()
init(name:String){
self.name = name
}
}
- 訪問控制
public: 可以被模塊外訪問。
internal: 可以被本模塊訪問宪躯。
private: 可以被本文件訪問乔宿。
繼承和構造函數
- 繼承
示例代碼(這里 Guldan 類繼承自 Hero 類):
public class Hero {
var name:String
var life:Int = 100
public init(name:String){
self.name = name
}
}
final class Guldan: Hero {
}
注:若不想一個類被繼承,可在前面添加 final
關鍵字眷唉。
- 重寫
重寫/覆蓋 (關鍵字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 關鍵字, 該類不可被繼承
final class Guldan: Hero {
//屬性重寫 (override 關鍵字)
override var description: String{
return "Your soul belongs to me!"
}
//構造方法重寫
override init(name: String) { //構造方法重載
self.group = ""
print("my name is \(name)")
super.init(name: name)
}
//方法重寫
override func beAttacked(attack: Int) {
life -= 15
}
}
注:若不想方法被重寫党饮,可以在方法前使用 final
關鍵字肝陪。
- 便利構造函數和指定構造函數
便利構造函數(關鍵字 convenience
),是在構造函數中調用了其他的構造函數刑顺。而其他的構造函數則成為指定的 (designated) 構造函數氯窍。示例代碼:
//父類
public class Hero {
...
//指定的構造函數
public init(name:String){
self.name = name
}
}
//子類
final class Guldan: Hero {
//構造函數重寫
override init(name: String) { //構造方法重載
self.group = ""
print("my name is \(name)")
super.init(name: name)
}
//便利的構造函數
convenience init(firstName:String, lastName:String){
self.init(name:firstName + " " + lastName) //調用指定的初始化函數
}
...
}
- 構造函數的繼承
子類構造函數的繼承原則:
- 如果子類沒有實現(xiàn)任何父類的指定構造函數,則自動繼承父類所有的指定構造函數蹲堂。
- 如果子類實現(xiàn)了父類所有的指定構造函數狼讨,則自動繼承父類所有的便利構造函數。
其他
- 文檔和注釋
三條斜杠 ///
可以生成文檔注釋柒竞;
使用 MARK
, TODO
和 FIXME
可以給代碼添加一些提醒政供,示例如下:
//MARK: - init 方法
//TODO: 有待添加一些功能
//FIXME: 有些不影響程序運行的小問題,有待以后調整
效果如圖所示: