Swift語法基礎入門三(函數, 閉包)

来源:http://www.cnblogs.com/l110/archive/2016/01/20/5143856.html
-Advertisement-
Play Games

Swift語法基礎入門三(函數, 閉包)函數:函數是用來完成特定任務的獨立的代碼塊。你給一個函數起一個合適的名字,用來標識函數做什麼,並且當函數需要執行的時候,這個名字會被用於“調用”函數格式:func 函數名稱(參數名:參數類型, 參數名:參數類型...) -> 函數返回值 { 函數實現部分 }沒...


Swift語法基礎入門三(函數, 閉包)

函數:

  • 函數是用來完成特定任務的獨立的代碼塊。你給一個函數起一個合適的名字,用來標識函數做什麼,並且當函數需要執行的時候,這個名字會被用於“調用”函數
  • 格式:
  • func 函數名稱(參數名:參數類型, 參數名:參數類型...) -> 函數返回值 { 函數實現部分 }

沒有參數沒有返回值

  1. 可以寫為 ->Void
  2. 可以寫為 ->()
  3. 可以省略
  4. Void。它其實是一個空的元組(tuple),沒有任何元素,可以寫成()
func say() -> Void {
    print("hello")
}
say()

func say1() -> () {
    print("hello")
}
say1()

// 推薦
func say2() {
    print("hello")
}
say2()

有參數沒有返回值

內部/外部參數

  • 內部參數: Swift2.0以前, 預設情況下的參數都是內部參數
  • Swift2.0開始, 預設將第二個參數名稱作為外部參數
  • 如果沒有明確地指定外部參數, 那麼系統預設會從第二個參數開始, 將參數的名稱作為外部參數
  • 外部參數只能外部用, 函數內部不能使用, 函數內部只能使用內部參數
  • 忽略外部參數: 在內部參數前加_
// Swift2.0之前, 預設是不會將第二個參數開始的參數名稱作為外部參數的, 必須自己手動指定
func sum(i: Int, j: Int) {
    print(i + j)
}
sum(10, j: 20)

func sum1(first i: Int, second j: Int) {
    print(i + j)
}
sum1(first: 10, second: 20)

預設參數(Default Parameter Values)

  • 格式: func method(parameter: Int = 0){}
  • 當預設值被定義後,調用這個函數時可以忽略這個參數
  • 其它語言的預設參數必須寫在最後面, Swift可以寫在任意位置

註意

  • 將帶有預設值的參數放在函數參數列表的最後。這樣可以保證在函數調用時,非預設參數的順序是一致的,同時使得相同的函數在不同情況下調用時顯得更為清晰。
func sum2(i: Int, j: Int = 10) {
    print(i + j)
}
//sum2(10, j: 20)
sum2(10)

// 不推薦這樣寫, 最好將預設參數寫在最後
func sum3(i: Int = 20, j: Int) {
    print(i + j)
}

常量參數和變數參數(Constant and Variable Parameters)

  • 函數參數預設是常量, 在函數內部不能修改
  • 如果想在函數中修改參數, 必須在參數前加上var

註意

  • 對變數參數所進行的修改在函數調用結束後便消失了,並且對於函數體外是不可見的。變數參數僅僅存在於函數調用的生命周期中
func sum4(let i: Int, let j: Int) {
    print(i + j)
}
sum4(10, j: 20)


var num1 = 10
var num2 = 20
//func swap(value1: Int, value2: Int){
//    let temp = value1
//    value1 = value2
//    value2 = temp
//}

// 註意: 操作的是局部變數, 對實參沒有影響
func swap1(var value1: Int, var value2: Int){
    print("交互前: value1 = \(value1), value2 = \(value2)")
    let temp = value1
    value1 = value2
    value2 = temp
    print("交互後: value1 = \(value1), value2 = \(value2)")
}

swap1(num1, value2: num2)
print(num1)
print(num2)

輸入輸出參數(In-Out Parameters)

  • 變數參數,正如上面所述,僅僅能在函數體內被更改。如果你想要一個函數可以修改參數的值,並且想要在這些修改在函數調用結束後仍然存在,那麼就應該把這個參數定義為輸入輸出參數(In-Out Parameters)
  • 定義一個輸入輸出參數時,在參數定義前加 inout 關鍵字

註意

  • 輸入輸出參數不能有預設值,而且可變參數不能用 inout 標記。如果你用 inout 標記一個參數,這個參數不能被 var 或者 let 標記。
func swap2(inout value1: Int, inout value2: Int){
    print("交互前: value1 = \(value1), value2 = \(value2)")
    let temp = value1
    value1 = value2
    value2 = temp
    print("交互後: value1 = \(value1), value2 = \(value2)")
}
swap2(&num1, value2: &num2)
print(num1)
print(num2)

可變參數(Variadic Parameters)

  • 一個可變參數可以接收零個或多個值
  • 如果沒有變參函數 , 並且函數的參數個數又不確定那麼只能寫多個方法或者用將函數參數改為集合
  • 格式 func method(parameter: Int...){}
  • 可變參數在函數中可以當做一個數組

註意

  • 一個函數最多只能有一個可變參數
  • 變參只能是同種類型的數據
  • 變參必須指定數據類型
  • 如果函數有一個或多個帶預設值的參數,而且還有一個可變參數,那麼把可變參數放在參數表的最後
func sum5(numbers: Int...) {
//    print(numbers)
    var sum = 0
    for number in numbers {
        sum += number
    }
    print(sum)
}
sum5(1, 2, 3)

// 不推薦寫法, 和預設值一樣, 變參最好寫在最後
func sum6(numbers: Int..., var sum: Int) {
    //    print(numbers)
    for number in numbers {
        sum += number
    }
    print(sum)
}
sum6(1, 2, 3, sum: 0)

// 推薦寫法
func sum7(var sum: Int = 100, numbers: Int...) {
    //    print(numbers)
    for number in numbers {
        sum += number
    }
    print(sum)
}
sum7(numbers: 1, 2, 3)

// 一個函數中只能有一個變參
//func sum8(numbers: Int..., values: Int...){
//    print(numbers)
//    print(values)
//}


// 有參數有返回值
func sum8(i: Int, j: Int) -> Int {
    return i + j
}
let result = sum8(10, j: 20)
print(result)

閉包

閉包

  • 閉包是自包含的函數代碼塊,可以在代碼中被傳遞和使用。Swift 中的閉包與 C 和 Objective-C 中的代碼塊(blocks)以及其他一些編程語言中的匿名函數比較相似
  • 閉包可以捕獲和存儲其所在上下文中任意常量和變數的引用。這就是所謂的閉合併包裹著這些常量和變數,俗稱閉包
  • 閉包的使用和block一樣, 用於保存一段代碼, 用作回調, 用作執行耗時操作
  • 閉包格式: in關鍵字的目的是便於區分返回值和執行語句
     {
         (形參列表) -> 返回值類型
         in
         執行語句
     }
    
        // 正常寫法
        loadData ({ () -> () in
            print("執行了")
        })
        */

        /*
        // 閉包的其它寫法
        // 1.如果閉包是函數的最後一個參數, 那麼可以把閉包寫在調用函數的()後面
        // 這種寫法, 我們稱之為 "尾隨閉包"
        loadData("123") {
            () -> ()
            in
            print("執行了")
        }


        // 2.如果函數只接收一個參數, 並且這個參數是閉包, 那麼調用函數的()可以省略
        // 這種寫法, 我們稱之為 "尾隨閉包"
        loadData {
            () -> ()
            in
            print("執行了")
        }
func loadData(since_id: String, finished: ()->()) -> Void {
        dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
            print("子線程做耗時操作 \(NSThread.currentThread())")

            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                print("主線程更新UI \(NSThread.currentThread())")
                finished()
            })
        }
    }

    /*
    func loadData(finished: ()->()) -> Void {
        dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
            print("子線程做耗時操作 \(NSThread.currentThread())")

            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                print("主線程更新UI \(NSThread.currentThread())")
                finished()
            })
        }
    }

閉包的迴圈引用

  • 閉包迴圈強引用
  • block

    • 閉包和block很像, 都是提前準備好代碼, 在需要時執行
    • block會對外部變數進行強引用, 保證執行代碼時變數還在
    • block中用到self一定要非常小心 閉包
    • 閉包也一樣, 會對外部變數進行強引用, 保證執行代碼時變數還在
    • 如果您將閉包賦值給一個類實例的屬性,並且該閉包通過訪問該實例或其成員而捕獲了該實例,您將創建一個在閉包和該實例間的迴圈強引用
    • Swift開發中能不寫self就不寫self, 一看到self就想到閉包
  • OC中如何解決迴圈引用

    • __weak typeof(self) weakSelf = self;
    • 特點: 對象釋放後會自動將變數賦值為nil
    • __unsafe_unretained typeof(self) weakSelf = self;
    • 特點: 對象釋放後不會自動將變數賦值為nil, 指向一塊廢棄的存儲空間
  • Swift中如何解決迴圈引用

    • weak var weakSelf = self
    • weak 相當於OC中的 __weak, 和OC一樣 對象釋放後會自動將變數賦值為nil
    • 所以被weak修飾的變數是可選類型

    • unowned var weakSelf = self

    • unowned 相當於OC中的__unsafe_unretained, 和OC一樣, 對象釋放後不會自動將變數賦值為nil
    • 所以被unowned修飾的變數, 不是可選類型

      註意: weak和unowned只能修飾對象類型, 因為只有對象類型才有引用計數

  • 應用場景:

    • 什麼時候用weak
      • 當被保存的對象有可能提前釋放時就用weak
    • 什麼時候用unowned
      • 當被保存的對象在使用時不會被提前釋放時就用unowned
  • 捕獲列表

    • 可以在調用閉包時在形參列表前面通過[]指定捕獲列表, 告訴系統如何處理指定的這些值
        //weak var weakSelf = self
        //unowned var weakSelf = self

        callBack = { [unowned self ,weak btn = self.button] () -> () in
            //self.view.backgroundColor = UIColor.redColor()
            //weakSelf.view.backgroundColor = UIColor.redColor()
            self.view.backgroundColor = UIColor.redColor()
            print(btn)
        }

        loadData(callBack!)
    }

    func loadData(finished: ()->()) -> Void {

        dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
            print("子線程做耗時操作 \(NSThread.currentThread())")

            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                print("主線程更新UI \(NSThread.currentThread())")
                finished()
            })
        }
    }
  • 析構函數
    • 析構器只適用於類類型,當一個類的實例被釋放之前,析構器會被立即調用
    • 類似於OC中的dealloc方法
    • 析構器是在實例釋放發生前被自動調用。你不能主動調用析構器
    • 一般情況下, 當使用自己的資源時, 在析構函數中進行一些額外的清理
    • 例如,如果創建了一個自定義的類來打開一個文件,並寫入一些數據,你可能需要在類實例被釋放之前手動去關閉該文件

    deinit {
        print("88")
    }

End


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、android序列化簡介我們已經知道在Android使用Intent/Bindler進行IPC傳輸數據時,需要將對象進行序列化。JAVA原本已經提供了Serializable介面來實現序列化,使用起來非常簡單,主要用於對象持久化以及對象的網路傳輸。Serializable開銷比較大,因為序列化和...
  • 適配器模式的定義:將一個類的介面,轉換成客戶期望的另一個介面。適配器讓原本介面不相容的類可以合作無間。 適配器模式其實也可以叫做轉換器模式,由定義可知適配器其實就是包裝某些對象從而讓他們的幾口開起來不像自己而像是別的東西。舉一個簡單的例子 : 假設現在已有一個軟體系統,你希望它能和一個新的廠...
  • 1:動畫屬性UIViewAnimationOptions說明a:常規動畫屬性設置(可以同時選擇多個進行設置)UIViewAnimationOptionLayoutSubviews:動畫過程中保證子視圖跟隨運動。UIViewAnimationOptionAllowUserInteraction:動畫過...
  • 效果圖1 string.xmlDefault Progressbar:2 attrs.xml 3 activity_main....
  • 源碼測試示例:package com.example.popupwindown;import android.os.Bundle;import android.app.Activity;import android.view.Gravity;import android.view.Menu;impo...
  • 一,效果圖。二,工程圖。三,代碼。RootViewController.h#import @interface RootViewController : UIViewController{ UITableView *myTableView;}@endRootViewController.m#i...
  • 本文目錄 1. iOS巨集的經典用法 2. Apple的習慣3. \_\_attribute\_\_ iOS巨集的經典用法 1.常量巨集、表達式巨集 2.帶參數的巨集 3.函數巨集(是一個沒有返回值的代碼塊,通常當做一行語句使用) 4.內聯函數 (一般有返回值) 5.變參巨集 函數可變參數 關於巨集定義...
  • 控制器 :一個iOS的app很少只由一個控制器組成,除非這個app極其簡單當app中有多個控制器的時候,我們就需要對這些控制器進行管理有多個view時,可以用一個大的view去管理1個或者多個小view,控制器也是如此,用1個控制器去管理其他多個控制器比如,用一個控制器A去管理3個控制器B、C、D,...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...