Swift 與眾不同的地方
switch(元組)
-
特點
- 其他語言中的switch語句只能比較離散的整形數據(字符可以轉換成整數)
- 但是swift中可以比較整數、浮點數、字符、字符串、和元組數據類型,而且它可以是離散的也可以使連續的范圍
- 而且在swift中case語句不需要顯示的添加break語句,分支語句會自動進行跳轉
- 每個switch語句至少有一個default語句
-
switch中比較元組
- 可以在元組中進行值綁定,來對某一個值進行判斷
- 可以使用where 語句對元組中的條件進行判斷
跳轉語句
- break、contune、fallthrough、return
break
-
主要用戶循環體中終止循環
-
break的使用有兩種方式
break // 沒有標簽 break label // 添加標簽 // break語句中標簽的使用 label1: for var x = 0; x < 5; x++ { // 標簽1 label2: for var y = 0; y > 0; y-- { // 標簽2 if x == y { break label1 // 默認是跳出標簽2,加上標簽,可以直接跳出到指定循環 } print("(x,y) = (\(x),\(y))") } }
continue
-
continue
的使用和break類似,可以使用標簽指定繼續的循環// continue語句中標簽的使用 label1: for var x = 0; x < 5; x++ { // 標簽1 label2: for var y = 0; y > 0; y-- { // 標簽2 if x == y { continue label1 // 默認是跳出標簽2,加上標簽,可以直接跳出到指定循環 } print("(x,y) = (\(x),\(y))") } }
fallthrough
- fallthrough是貫通語句,在swift的swiftch語句中case語句不能貫通,但是如果我們需要設置貫通語句,可以使用fallthrough語句
- 在switch語句中case后fallthrough,會執行下一個case語句
函數
-
參數傳遞
- 外部參數名和內部參數名
- 外部參數名可以在調用函數時顯示出來
func rectangle(W width:Int, H height:Int) -> Int { // 其中W\H是外部參數名,在外部調用這個方法時會顯示出來,提示這個參數是神馬意思 // width\height 是內部參數,在函數內部調用使用 return width * height }
- 也可以讓內部便令名變為外部變量名,使用字符 “#”
func rectangle(#width:Int, #height:Int) -> Int{ // 其中W\H是外部參數名,在外部調用這個方法時會顯示出來,提示這個參數是神馬意思 // width\height 是內部參數,在函數內部調用使用 return width * height }
-
參數默認值
func rectangle(#width:Int = 100, #height:Int = 100) -> Int { // 其中W\H是外部參數名,在外部調用這個方法時會顯示出來,提示這個參數是神馬意思 // width\height 是內部參數,在函數內部調用使用 return width * height }
-
可變參數
func sum(numbers: Double... ) -> Double { var total: Double = 0 for num in numbers { total += num } return total }
-
參數的引用傳遞
- 在眾多數據類型中,只有類是引用傳遞,其他的數據類型如整形、浮點型、布爾型、字符串、元組、集合、數據、枚舉、結構體都是值傳遞。
- 如果一定要把一個值傳遞的類型的數據變為引用傳遞模型的話,可使用關鍵字'inout'
func rectangle(inout width:Int, increased:Int = 1 ) { width += increased } var value:Int = 10 rectangle(&value) // 結果是11 rectangle(&value,100) // 結果是111
-
函數返回值
- 特別之處是可以返回一個元組,表示多個值
func rectangleArea(width:Double, increased:Double = 1 ) -> (area:Double,height:Double) //返回面積和高度
-
函數類型
- 函數類型包括函數參數類型和返回值類型
(Double, Double) -> Double //傳入寬高,計算面積
- 這個就是函數類型,函數類型可以作為其他函數的返回類型
- 比如寫一個通用的方法來計算更多種圖形的面積,這時可以使用這個函數類型作為返回值
- 函數類型還可以作為參數類型使用,可以直接使用返回值作為參數,然后可以在函數內部調用這個函數
-
函數重載
- 和C++中函數重載類似,但是在swift中
函數返回值類型
、外部參數名
也可以作為不同函數的判斷標准
- 和C++中函數重載類似,但是在swift中
-
嵌套函數
- 可以在函數內部定義並調用函數
泛型和泛型函數
-
泛型就是在運行時才確定類型的一種機制,這個C++中的泛型如出一轍
-
就是定義一個模板,使用多種場景
-
函數參數或者返回值到運行時才能確定
func add(a:Int, b:Int) -> Int { return a + b } func add(a:Double, b:Double) -> Double { return a + b }
-
如果用泛型計算兩個數的和,可以寫成下面這個樣
func add<T>)(a:T, b:T) -> T { return a + b } // 或者指定多重類型 func add<T,U>(a:T, b:U) -> T { return a + T(b) }
-
如果比較兩個類型的話,那么必須要遵守
Comparable
協議才可以func isEquals<T: Comparable>(a:T, b:T) -> Bool { return (a == b) }
閉包
-
閉包是自包含的匿名函數代碼塊,可以作為表達式、函數參數和函數返回值。
{ (參數列表) -> 返回值類型 in 語句組 }
使用舉例
-
完整版本
{(a:Int, b:Int) -> Int in return a + b }
-
簡化版本
{a,b in return a + b }
- 如果閉包中只有一條return語句,那么return 語句可以省略
{a,b in a + b }
- 縮寫參數名稱
{$0 + $1}
swift會自動推到出參數類型,$0表示第一個參數,$1表示第二個參數 - 閉包作為返回值,直接可以為變量和常量賦值
let reslut:Int = {(a:Int, b:Int) -> Int in return a + b }(10, 89)
- 如果閉包中只有一條return語句,那么return 語句可以省略
-
捕獲上下文中的變量和常量
- 嵌套函數和閉包可以訪問其所在上下文中的常量和變量,這就是
捕獲值
。即便是定義這些常量或變量的作用域已經不存在,嵌套函數或閉包仍然可以在函數體內或閉包內修改或引用這些值。
- 嵌套函數和閉包可以訪問其所在上下文中的常量和變量,這就是
swift中的面向對象
枚舉
-
swift中枚舉可以存儲多種數據類型,並不是真正的整數
// 默認並不是整形 enum WeekDays { case Monday case Tuesday case Wednesday case Thursday case Friday } // 簡寫 enum WeekDays { case Monday, Tuesday, Wednesday, Thursday, Friday }
-
注意:在switch中使用枚舉類型時,語句中的case必須全部包含枚舉中所有成員,不能多也不能少,包括default語句。
-
指定沒枚舉的原始值,可以是字符、字符串、整數、浮點數等
// 指定枚舉的原始值 enum WeekDays: Int { case Monday = 0 case Tuesday case Wednesday case Thursday case Friday }
-
原始值使用的話,要用到函數
toRaw()
和fromRaw()
結構體
- swift中結構體和類非常類似,可以定義成員變量和方法
- 結構體不具備繼承、運行時強制類型轉換、析構函數、引用計數等
- 除了對象是引用傳遞,其他數據類型都是值傳遞,引用之間的比較可以使用 ‘=’ 和 ‘!=’
可選類型和可選鏈
-
“?” 和 "!"
- 不確定一個變量是否有值,可以加 ?
-
可選綁定 : 如果賦值不為nil的話就執行if語句
if let result: Double? = divide(100,0) { print("success") } else { print("failure") }
-
強制拆封 : 使用 ! 來強制拆封
let result: Double? = divide(100,0) print(result!)
-
可選鏈
- 一些可選類型內部包含其他可選類型,然后產生層級關系。
訪問限定
- 訪問范圍的界定主要有:模塊和源文件
- 訪問級別:public、internal、private
- 可修飾類、結構體、枚舉等面向對象的類型,還可以修飾變量、常量、下標、元組、函數、屬性等。以上這些統稱“實體”
- 使用方式
public
: 只要在import進所在模塊,那么在該模塊中都可訪問internal
: 只能訪問自己模塊的任何internal實體,不能訪問其他模塊中的internal實體,默認就是internal修飾符private
: 只能在當前源文件中訪問的實體。
- 設計原則
- 如果是自己在本文件內部使用,就用默認的就行。
- 如果是開發第三方框架的話,那么一定要設計好訪問級別,接口一定要public。其他的可以private
屬性和下標
1、存儲屬性
-
存儲屬性適用於類和結構體兩種類型,包括常量屬性(
let
)和變量屬性(var
)- 在一個類中定義一個結構體對象屬性或者類對象屬性時就算是存儲屬性,可以指定默認值
-
可以對存儲屬性進行延遲加載
-
屬性觀察者
- 使用在一般的存儲屬性和計算屬性上
willSet
在設置新值之前調用didSet
在設置新值之后馬上調用
var fullName: String { didSet { fullName = firstName + "." + secondName }
2、計算屬性
-
計算屬性本身不存儲數據,只從其他存儲屬性中獲得數據。類、結構體、枚舉都可以定義計算屬性
-
計算屬性只能使用
var
修飾var firstName: String = "Jone" var secondName: String = "Hu" // 計算屬性 var fullName: String { get { return firstName + "." + secondName } set (newValue) { let names = newValue.componentsSeparatedByString(".") firstName = names[0] secondName = names[1] } }
-
只讀計算屬性,只寫set方法即可,這是可以省略
set
,直接return
即可var firstName: String = "Jone" var secondName: String = "Hu" // 計算屬性 var fullName: String { return firstName + "." + secondName }
3、靜態屬性
- 可以在類、結構體、枚舉中定義靜態屬性
4、下標
-
一些集合類型,可以使用下標訪問
/** * 定義二維數組,使用下標訪問數組 * 內部還是一個一維數組,不過展示給外界的時一個二維訪問方式 */ struct DoubleArray { // 屬性定義 let rows: Int let cols: Int var grid: [Int] // 構造方法 init(rows: Int, cols: Int) { self.rows = rows self.cols = cols grid = Array(count: rows * cols, repeatedValue: 0) // 利用泛型創建一個數組 } // 下標定義 subscript(row: Int, col: Int) -> Int { get { return grid[row * col + col] } set (newValue) { grid[row * col + col] = newValue } } } // 使用二維數組 var arr2 = DoubleArray(rows: 10, cols: 10) // 初始化二維數組 for var i = 0; i < 10; i++ { for var j = 0; j < 10; j++ { arr2[i,j] = i * j } } // 輸出二維數組 for var i = 0; i < 10; i++ { for var j = 0; j < 10; j++ { print("\t \(arr2[i,j])") } print("\n") }
方法
- 類、結構體、枚舉中都可以定義方法
- 這里主要說結構體和枚舉中方法的定義
- 默認情況下,結構體和枚舉中的方法是不能修改屬性的
- 如果要修改屬性的話,需要在方法之前加關鍵字
mutating
,稱之為變異方法
靜態方法
-
結構體和枚舉中靜態方法用
static
,類中靜態方法使用class
-
1、結構體中的靜態方法
- 不能訪問示例屬性和示例方法
/** * 結構體中的靜態方法 */ struct Account { var owner: String = "Jack" static var interestRate: Double = 0.668 // 靜態方法 static func interestRateBy(amount: Double) -> Double { return interestRate * amount } func messageWith(amount: Double) -> String { let interest = Account.interestRateBy(amount) return "\(self.owner) 的利息是 \(interest)" } } // 調用靜態方法 print(Account.interestRateBy(10_000.00)) // var myAccount = Account() print(myAccount.messageWith(10_000))
-
2、枚舉中的靜態方法
- 不能訪問示例屬性和示例方法
/// 枚舉中的靜態方法 enum Account1 { case 中國銀行 case 中國工商銀行 case 中國建設銀行 case 中國農業因銀行 static var interestRate: Double = 0.669 // 靜態方法定義 static func interestBy(amount: Double) -> Double { return interestRate * amount } } // 靜態方法的調用 print(Account1.interestBy(10_000.00))
-
3、類中的靜態方法
- 不能訪問示例屬性和示例方法
/// 類中的靜態方法,使用關鍵字class class Account2 { var ower: String = "Jack" class func interestBy(amount: Double) -> Double { return 0.889 * amount } } // 調用靜態方法 print(Account2.interestBy(10_000.00))
構造和析構
- 只有類和結構體才有構造
init()
和析構函數deinit
- 在創建實例過程中需要一些初始化操作,這個過程稱為構造
- 在實例最后被釋放的過程中,需要清楚資源,這個過程稱為析構
- 注意: 構造器 可以重載,沒有返回值
構造器
- 構造器主做一些屬性的初始化操作
- 如果不寫init方法,那么會自動生成一個空的init構造器
- 如果有繼承關系,要先調用父類的構造器
- 橫向代理與向上代理
- 橫向代理:構造器調用發生在本類內部,添加
convenience
關鍵字即可作為便利構造器,便利構造器必須調用本類內部的其他構造器 - 向上代理:有繼承關系,就先調用父類的構造器
- 橫向代理:構造器調用發生在本類內部,添加
析構器
- 析構器只作用於類
- 析構器沒有返回值,沒有參數,不能重載
繼承
- swift單繼承
- 重寫屬性、下標以及方法
- 重寫父類的方法使用
override
- 終止屬性或者方法的繼承可以使用
final
- 類型檢查
is
as
Any
AnyObject
is
類型判斷as
類型轉換Any
任何類型,包括類和其他數據類型AnyObject
任何類
擴展和協議
擴展extension
- 擴展的類型可以使類、結構體、枚舉
- 擴展可以增加屬性和方法
- 擴展計算屬性、方法、構造器、下標
- 注意:擴展類的構造器的時只能增加遍歷構造器,指定構造器和析構器只能由源類型指定
協議 protocol
- 類似C++中的純虛類
- 可以定義屬性和方法
- 協議可以繼承協議
swift內存管理
- swift內存管理遵循ARC特性
- 對引用類型進行引用計數,基本數據類型由系統管理
循環引用問題
- swift中解決循環引用由兩種方式
- 1、弱引用(
weak reference
) - 2、無主引用(
unowned reference
)
- 1、弱引用(
- 弱引用可以沒有值,因此必須設置成可選類型
- 無主引用適用於引用對象永遠有值
閉包中的循環引用問題
-
閉包中的循環引用的解決方法和上面的一樣,使用弱引用和無主引用
class Person { let firstName: String = "Jack" let secondName: String = "lu" /** * 解決閉包強循環引用 */ lazy var fullName: (String, String) -> String = { // [weak self] (firstName: String, secondName: String) -> String in [unowned self] (firstName: String, secondName: String) -> String in return firstName + secondName } }
OC與Swift
-
OC和swift可以混合開發
-
1、swift 調用 OC
- 橋接文件 "<工程名>-Bridging-Header.h"
- 在橋接文件中引入OC頭文件即可
-
2、OC調用swift
- 包含頭文件,這個頭文件命名樣式 "<工程名>-swift.h"
- 在swift源文件中要把類聲明為
@objc
- 這時新建
swift
類就不需要選擇新建swift文件,而是選擇Cocoa Touch Class
,然后選擇語言類型位swift