Swift學習筆記(二)

Swift函數

Swift函數包含參數類型和返回值類型

函數定義

Swift使用關鍵字func定義函數。

函數定義時可以指定0個,一個或多個輸入參數和一個返回值類型。

函數的實參傳遞順序必須和形參相同,->后定義返回值類型

func funcName(形參/ 空) -> returnType {
    statement
    ...
    return parameters
}

函數參數

Swift可以接收一個或多個參數,我們可以用元組(Tuple)向函數傳遞一個或多個參數。也可以創建無參函數。

元組作為函數返回值

元組(Tuple)與數組類似,但元組中的元素可以是任何類型,使用圓括號。

可以使用元組類型(Tuple)讓多個值作為一個復合值從函數中返回。如果不確定返回值是否非nil,可以返回可選的元組,例如(Int,Int)?。可選元組類型(Int, Int)?與元組包含可選類型如(Int?, Int?)是不同的,前者整個元組是可選的,后者只是每個值是可選的。

func minMax(array: [Int]) -> (min: Int, max: Int)? {
    if array.isEmpty { return nil }
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}

函數參數名稱

函數參數都有一個外部參數和一個局部參數名。局部參數名在函數實現的內部使用,外部參數名用于在函數調用時傳遞給函數的參數,可以在局部參數名前指定外部參數名,中間以空格分隔。如果提供了外部參數名,在調用函數時必須使用外部參數名。

func funcName(inputString str: String) -> String {

    return str
}

可變參數

當傳入函數的參數數量不確定時,可以在變量類型后面假如...來定義可變參數。

func vari<N>(members: N...){
    for i in members {
        print(i)
    }
}

常量、變量、I/O參數

一般默認在函數中定義的參數都是常量參數,只可查詢使用,不能改變值。如果要什么變量參數可以在前面加上var,這樣就可以改變參數的值,如func getName(var id:String)...。函數一般是傳值,不是傳引用,此時參數值可以在函數內部中改變但是并不影響原來的值。如果要修改參數原來的值,可以把該參數定義為輸入輸出參數(In-Out Parameters),在參數前加inout關鍵字,此時需要傳引用。一個輸入輸出參數有傳入函數的值,這個值被函數修改,然后傳出函數,替換原來的值。

func swapTwoInts(inout a: Int,inout b: Int){
    
   let t = a
    a = b
    b = t
}

var x = 0,y = 100
print("x = \(x) ;y = \(y)")

swapTwoInts(&x, b:&y)
print("x = \(x) ;y = \(y)")

輸出結果:

x = 0 ;y = 100
x = 100 ;y = 0

函數類型

每種函數都有種特定的函數類型,由函數的參數類型和返回類型組成。函數可以定義任何參數及類型。如果具有同樣的參數類型和返回類型則為同一種函數類型。既然函數可以認為是一種類型,那我們可以將函數作為參數類型或返回類型使用。

func sum(a: Int, b: Int) -> Int {
    return a + b
}
var addition: (Int, Int) -> Int = sum
print("輸出結果: \(addition(40, 89))")

func another(addition: (Int, Int) -> Int, a: Int, b: Int) {
    print("輸出結果: \(addition(a, b))")
}
another(sum, a: 10, b: 20)

函數嵌套

函數嵌套指在函數內定義一個新的函數,外部的函數可以調用函數內定義的函數。

// 嵌套函數
func calcDecrement(forDecrement total: Int) -> () -> Int {
    var overallDecrement = 0
    func decrementer() -> Int {
        overallDecrement -= total
        return overallDecrement
    }
    return decrementer
}


calcDecrement(forDecrement: 20)()

Swift閉包

閉包(Closures)是自包含的功能代碼塊,可以在代碼中使用或用來作為參數傳值。

swift中的閉包與OC中的block和其他一些語言中的匿名函數比較類似。

全局函數和嵌套函數其實就是特殊的閉包。

閉包的形式

全局函數 嵌套函數 閉包表達式
有名字但不能捕獲任何值。 有名字,也能捕獲封閉函數內的值。 無名閉包,使用輕量級語法,可以根據上下文環境捕獲值。

Swift中閉包的優化:

  • 根據上下文推斷參數和返回值類型。
  • 從單行表達式閉包中隱式返回(閉包只有一行代碼,可以省略return)。
  • 可以使用簡化參數名,如$0,$1...(從0開始表示第i個參數)
  • 提供了尾隨閉包語法

語法:

{(parameters) -> returnType in
   statements
}

實例:

let divide = {(val1: Int, val2: Int) -> Int in 
   return val1 / val2 
}
let result = divide(200, 20)
print (result)

閉包表達式

閉包表達式是一種利用簡潔語法構建內聯閉包的方式。

sort函數

Swift標準庫提供了sort排序函數,會根據您提供的用于排序的閉包函數將已知類型數組的值進行排序。排序完成會返回一個排序好的數組,原數組不會被更改。sort函數需要提供兩個參數。

  • 已知類型的數組。
  • 閉包函數。該閉包函數需要傳入與數組元素類型相同的兩個值,并返回一個布爾值用來表明第一個值是否排在第二個值前面。
let names = ["AT", "AE", "D", "S", "BE"]

// 使用普通函數(或內嵌函數)提供排序功能,閉包函數類型需為(String, String) -> Bool。
func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
var reversed = names.sort(backwards)

參數名稱縮寫

通過$0,$1,$2來順序調用閉包的參數。var reversed = names.sort({$0 > $1})

運算符函數

>的定義public func ><T : Comparable>(lhs: T, rhs: T) -> Bool
Swift 的String類型定義了關于大于號 (>) 的字符串實現,其作為一個函數接受兩個String類型的參數并返回Bool類型的值。 而這正好與sort(_:)方法的第二個參數需要的函數類型相符合。 因此,您可以簡單地傳遞一個大于號,Swift可以自動推斷出您想使用大于號的字符串函數實現:var reversed = names.sort(>)

尾隨閉包

尾隨閉包是一個書寫在函數括號之后的閉包表達式,函數支持將其作為函數最后一個參數調用。

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // 函數體部分
}

// 以下是不使用尾隨閉包進行函數調用
someFunctionThatTakesAClosure({
    // 閉包主體部分
})

// 以下是使用尾隨閉包進行函數調用
someFunctionThatTakesAClosure() {
  // 閉包主體部分
}

實例: var reversed = names.sort() { $0 > $1 }

捕獲值和引用類型

閉包可以在其定義的上下文中捕獲常量或變量,存儲一份副本,即使定義這些常量和變量的原域已經不存在,閉包仍然可以在閉包函數體內引用和修改這些值。同時函數和閉包都是引用類型,無論將函數還是閉包賦值給一個常量還是變量,實際上都是將常量/變量的值設置為對應函數/閉包的引用。

func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}

let incrementByTen = makeIncrementor(forIncrement: 10)

// 返回的值為10
incrementByTen()

// 返回的值為20
incrementByTen()

// 返回的值為30
incrementByTen()

// 返回的值為40
incrementByTen()

let alsoIncrementByTen = incrementByTen

// 返回的值也為50
print(alsoIncrementByTen())

Swift枚舉

枚舉也是一種數據類型,只是這種類型只包含自定義的特定數據,它是一組有共同特性的數據的集合。Swift使用關鍵字enum來定義。

Swift枚舉功能為:

  • 聲明在類中,可以通過實例化類來訪問他的值。
  • 枚舉也可以定義構造函數來提供一個初始成員值;可以在原始的實現基礎上擴展功能。
  • 可以遵守協議來提供標準功能。

語法:

enum enumname {
   // 枚舉定義放在這里
}

實例:

// 定義枚舉
enum DaysofaWeek {
    case Sunday
    case Monday
    case TUESDAY
    case WEDNESDAY
    case THURSDAY
    case FRIDAY
    case Saturday
}

var weekDay = DaysofaWeek.THURSDAY
weekDay = .THURSDAY // weekDay類型已知,可用.語法取值

當weekDay的類型已知時,再次為其賦值可以省略枚舉名。使用顯式類型的枚舉值可以讓代碼具有更好的可讀性。

枚舉中定義的值(如 Sunday,Monday,……和Saturday)是這個枚舉的成員值(或成員)。case關鍵詞表示一行新的成員值將被定義。

注意: 和 C 和 Objective-C 不同,Swift 的枚舉成員在被創建時不會被賦予一個默認的整型值。在上面的DaysofaWeek例子中,Sunday,Monday,……和Saturday不會隱式地賦值為0,1,……和6。相反,這些枚舉成員本身就有完備的值,這些值是已經明確定義好的DaysofaWeek類型。

相關值和原始值

枚舉可分為相關值原始值

相關值 原始值
不同數據類型 相同數據類型
實例: enum {10,0.8,"Hello"} 實例: enum {10,35,50}
值的創建基于常量或變量 預先填充的值
相關值是當你在創建一個基于枚舉成員的新常量或變量時才會被設置,并且每次當你這么做得時候,它的值可以是不同的。 原始值始終是相同的

相關值

以下實例中我們定義一個名為 Student 的枚舉類型,它可以是 Name 的一個相關值(Int,Int,Int,Int),或者是 Mark 的一個字符串類型(String)相關值。

enum Student{
    case Name(String)
    case Mark(Int,Int,Int)
}
var studDetails = Student.Name("Runoob")
var studMarks = Student.Mark(98,97,95)
switch studMarks {
case .Name(let studName):
    print("學生的名字是: \(studName)。")
case .Mark(let Mark1, let Mark2, let Mark3):
    print("學生的成績是: \(Mark1),\(Mark2),\(Mark3)。")
}

原始值

原始值可以是字符串、字符或者任意整型值或浮點型值。每個原始值在它的枚舉聲明中必須是唯一的。

當原始值為整型時,不需要顯示的為每個成員賦值。如果第一個沒有賦值,會默認為0。隱式賦值的值一次增1.

enum Month: Int {
    case January = 1, February, March, April, May, June, July, August, September, October, November, December
}

let yearMonth = Month.May.rawValue
print("數字月份為: \(yearMonth)。")

Swift結構體

Swift結構體是構建代碼所用的一種通用且靈活的構造體,我們可以為結構體定義屬性(常量,變量)和添加方法,從而擴展結構體的功能。

與OC的不同點:

  • 結構體不需要包含實現文件和接口
  • 結構體允許我們創建一個單一文件,并且系統會自動生成面向其它代碼的外部接口。

結構體總是通過被復制的形式在代碼中傳遞,因此它的值是不可以修改的。

語法

struct NameStruct { 
   Definition 1
   Definition 2
   ……
   Definition N
}

我們可以通過結構體名來訪問結構體成員,實例化結構體使用let關鍵字。結構體內使用成員屬性使用 self 關鍵字。

以下實例化通過結構體實例化時傳值并且克隆一個結構體:

struct MarksStruct {
   var mark: Int

   init(mark: Int) {
      self.mark = mark
   }
}
var aStruct = MarksStruct(mark: 98)
var bStruct = aStruct // aStruct 和 bStruct 是使用相同值的結構體!
bStruct.mark = 97
print(aStruct.mark) // 98
print(bStruct.mark) // 97

結構體的應用

在你的代碼中,你可以使用結構體來定義你的自定義數據類型。

結構體實例總是通過值傳遞來定義你的自定義數據類型。

按照通用的準則,當符合一條或多條以下條件時,請考慮構建結構體:

  • 結構體的主要目的是用來封裝少量相關簡單數據值。
  • 有理由預計一個結構體實例在賦值或傳遞時,封裝的數據將會被拷貝而不是被引用。
  • 任何在結構體中儲存的值類型屬性,也將會被拷貝,而不是被引用。
  • 結構體不需要去繼承另一個已存在類型的屬性或者行為。

舉例來說,以下情境中適合使用結構體:

  • 幾何形狀的大小,封裝一個width屬性和height屬性,兩者均為Double類型。
  • 一定范圍內的路徑,封裝一個start屬性和length屬性,兩者均為Int類型。
  • 三維坐標系內一點,封裝x,y和z屬性,三者均為Double類型。

結構體實例是通過值傳遞而不是通過引用傳遞。

Swift類

Swift并不要求你為自定義類去創建獨立的接口和實現文件。只需要在一個單一的文件中定義一個類,系統會自動生成面向其它代碼的外部接口。

類和結構體的對比

共同點:

  • 定義屬性用于存儲值
  • 定義方法用于提供功能
  • 定義附屬腳本用于訪問值
  • 定義構造器用于生成初始化值
  • 通過擴展以增加默認實現的功能
  • 符合協議以對某類提供標準功能

與結構體相比,類還有如下的附加功能:

  • 繼承允許一個類繼承另一個類的特征
  • 類型轉換允許在運行時檢查和解釋一個類實例的類型
  • 解構器允許一個類實例釋放任何其所被分配的資源
  • 引用計數允許對一個類的多次引用

語法:

Class Classname {
   Definition 1
   Definition 2
   ……
   Definition N
}

作為引用類型訪問類屬性

累的屬性可以通過.來訪問,格式為實例化類名.屬性名

恒等運算符

因為類是引用類型,有可能有多個常量和變量在后臺同時引用某一個類實例。

為了能夠判定兩個常量或者變量是否引用同一個類實例,Swift內建了兩個恒等運算符。

恒等運算符 不恒等運算符
運算符為:=== 運算符為:!==
如果兩個常量或者變量引用同一個類實例則返回 true 如果兩個常量或者變量引用不同一個類實例則返回 true

參考:

Swift 教程 | 菜鳥教程

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,179評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,628評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,444評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,948評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,185評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,717評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,794評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,414評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,750評論 2 370

推薦閱讀更多精彩內容

  • 86.復合 Cases 共享相同代碼塊的多個switch 分支 分支可以合并, 寫在分支后用逗號分開。如果任何模式...
    無灃閱讀 1,400評論 1 5
  • 一直沒有時間好好看一下swift,最近復習了一遍語法,這里記錄swift學習過程中遇到的一些問題和要點,和Obje...
    bomo閱讀 2,379評論 0 25
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young閱讀 3,848評論 1 10
  • Hello Word 在屏幕上打印“Hello, world”,可以用一行代碼實現: 你不需要為了輸入輸出或者字符...
    restkuan閱讀 3,202評論 0 6
  • 昨天,閨女給我捎來一盒蛋撻,色艷味美,一口氣讓我吃個干凈。 吃完蛋撻,望著精美的包裝盒,回味著美味,腦子又開始胡思...
    微危道人閱讀 991評論 35 40