Swift003-訪問修飾詞 函數(shù) 閉包

Swift003-訪問修飾詞 函數(shù) 閉包

訪問限制詞

在 Swift 語言中,訪問修飾符有五種,分別為 fileprivate,private,internal,public 和 open。
權(quán)限從高到底 open > public > interal > fileprivate > private

  • private 訪問級別所修飾的屬性或者方法只能在當前類里訪問(swift4開始 extension 里也可以訪問 private 的屬性)。
  • fileprivate 訪問級別所修飾的屬性或者方法在當前的 Swift 源文件里可以訪問。
  • internal 訪問級別所修飾的屬性或方法在源代碼所在的整個模塊都可以訪問。
  • internal 訪問級別所修飾的屬性或方法在源代碼所在的整個模塊都可以訪問。
    • 如果是框架或者庫代碼,則在整個框架內(nèi)部都可以訪問,框架由外部代碼所引用時,則不可以訪問。
    • 如果是 App 代碼,也是在整個 App 代碼,也是在整個 App 內(nèi)部可以訪問。
    • 默認訪問級別,internal修飾符可寫可不寫
  • public 可以被任何人訪問。但其他 module 中不可以被重寫(override)和繼承,而在 module 內(nèi)可以。
  • open 可以被任何人使用,包括 override 和繼承

函數(shù)

  • 一個完整的函數(shù)由 訪問修飾符+類型+func+方法名+參數(shù)標簽+參數(shù)名稱+返回值 組成
  • 面向?qū)ο笊衔覀兞晳T稱 方法
// 定義 
// 多個參數(shù)可以(但最好不要)有相同的參數(shù)標簽,不可以有相同的參數(shù)名稱 
// "_"下劃線用于隱藏標簽 
// 參數(shù)可以寫進固定值
// 返回值有多個時可以利用元組,也可以用數(shù)組,字典的形式
public class func test(_ fruit: String, priceLabel price: Float, count: Int, shop: String = "超市") -> (String, Float, Int) {
        return (fruit, price, count)
 }
 // 使用
 test2("pear", priceLabel: 1.25, count: 1)
  • 類方法
public class func test1() {
    print("類方法")
}
  • 靜態(tài)方法
public class func test2() {
    print("靜態(tài)方法")
}
  • 實例方法(對象方法)
func test3() {
    print("實例方法")
}
  • 無參數(shù)無返回值(Void而已,省略)
func test4() {
    print("無參數(shù)無返回值")
}
  • 可變形參(可變參數(shù):參數(shù)數(shù)量不定)
func test5(nums: Int...) {
    let sum = nums.reduce(0) { (result, num) -> Int in
        return result + num
    }
    print("\(nums) 的和: \(sum)")
}
test5(nums: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
  • 輸入輸出參數(shù)

默認情況下,函數(shù)參數(shù)是常量。嘗試從該函數(shù)體內(nèi)更改函數(shù)參數(shù)的值會導致編譯時錯誤。這意味著無法更改參數(shù)的值。
通過將inout關(guān)鍵字放在參數(shù)類型之前來編寫輸入輸出參數(shù)。一個輸入輸出參數(shù)傳遞進函數(shù)的值,可以由函數(shù)修改并替換原來的值。
將變量作為輸入輸出參數(shù)的參數(shù)傳遞。不能傳遞常量或文字值作為參數(shù),因為不能修改常量和文字。當使用輸入輸出參數(shù)調(diào)用函數(shù)時在變量的名稱前直接放置一個&,以指示該函數(shù)可以修改它。
輸入輸出參數(shù)不能具有默認值,并且可變參數(shù)不能標記為inout。

func inoutFunc(argument1: inout Int, argument2: inout Int) {
    let temp = argument1
    argument1 = argument2
    argument2 = temp
}
var inout1 = 1
var inout2 = 2
inoutFunc(argument1: &inout1, argument2: &inout2)
print("inout1: \(inout1), inout2: \(inout2)")

函數(shù)類型

每個函數(shù)都有一個特定的函數(shù)類型,由函數(shù)的參數(shù)類型和返回類型組成。形式上表示為:(參數(shù)類型) -> 返回值類型。

  • 函數(shù)類型作為參數(shù)類型

可以使用函數(shù)類型,作為另一個函數(shù)的參數(shù)類型。這使得可以為函數(shù)調(diào)用者保留函數(shù)實現(xiàn)的某些方面,以便在調(diào)用函數(shù)時提供:

func testAdd(a:Int, b:Int) -> Int {
    return a + b
}
func testFuncParam(_ addFunction: (Int, Int) -> Int, a:Int, b:Int) {
    print("Result:\(addFunction(a,b))")
}
func testBasic() {
    testFuncParam(testAdd, a: 5 ,b: 7)
}
  • 函數(shù)類型作為返回類型

可以使用函數(shù)類型作為另一個函數(shù)的返回類型。通過在返回函數(shù)的返回箭頭(->)之后立即編寫完整的函數(shù)類型來完成此操作:

// 定義個自增函數(shù)
func testIncrease(input:Int) -> Int {
    return input + 1
}
// 定義個自減函數(shù)
func testReduce(input:Int) -> Int {
    return input - 1
}
// 定義一個返回函數(shù)類型的函數(shù)
func testFunctionBack(backwards:Bool) -> (Int) -> Int {
    return backwards ? testReduce : testIncrease
}
  • 嵌套函數(shù)

在函數(shù)體內(nèi)定義的函數(shù)稱為嵌套函數(shù),嵌套函數(shù)對外界是隱藏的,但它們的封閉函數(shù)仍然可以調(diào)用它們。封閉函數(shù)也可以返回其嵌套函數(shù),以允許嵌套函數(shù)在另一個范圍內(nèi)使用:

func sumFunc() -> (Int...) -> Int {
    func sumInts(nums: Int...) -> Int {
        return nums.reduce(0) { (result, item) -> Int in
            result + item
        }
    }
    return sumInts(nums:)
}
print(sumFunc()(1, 2, 3, 4, 5))
  • 構(gòu)造函數(shù)和析構(gòu)函數(shù)
// 屬性
var name: String
// 構(gòu)造函數(shù)(初始化)
init(newName:String){
    self.name = newName
    print("My name is \(newName)")
}
// 析構(gòu)函數(shù)(反初始化,功能跟oc的dealloc一樣做善后)
deinit {
    name = ""
}
  • class與staitc關(guān)鍵字的區(qū)別與使用

    • static 可以在類、結(jié)構(gòu)體、枚舉、擴展中使用。而 class 只能在類中使用。
    • static 可以修飾存儲屬性,static 修飾的存儲屬性稱為靜態(tài)變量(常量)。而 class 不能修飾存儲屬性。
    • static 修飾的計算屬性不能被重寫。而 class 修飾的可以被重寫。
    • static 修飾的靜態(tài)方法不能被重寫。而 class 修飾的類方法可以被重寫。
    • class 修飾的計算屬性被重寫時,可以使用 static 讓其變?yōu)殪o態(tài)屬性。
    • class 修飾的類方法被重寫時,可以使用 static 讓方法變?yōu)殪o態(tài)方法。

閉包

閉包是swift中非常重要的一個知識點,類似于objective-c中的block。
閉包的本質(zhì)是代碼塊,是函數(shù)的升級版,函數(shù)是有名稱、可復用的代碼塊,閉包則是比函數(shù)更加靈活的匿名代碼塊。
(函數(shù)相當于一個特殊的閉包(有名字的閉包),或者說閉包是一個特殊的函數(shù)(帶有自動變量的匿名函數(shù)))

由上面括號內(nèi)語句, 可以歸納三種閉包形式:

  • 全局函數(shù):具名函數(shù),但不捕獲任何值
  • 嵌套函數(shù):在函數(shù)內(nèi)部嵌套定義具名函數(shù),可捕獲包含函數(shù)中的值
  • 閉包表達式:匿名函數(shù)類型實例,不具名的代碼塊,輕量級語法,可捕獲上下文的值

其中閉包表達式才是我們一般意義上說的閉包

Swift的閉包表達式具有干凈,清晰的風格,閉包的優(yōu)勢包括:

  • 從上下文中推斷參數(shù)和返回值類型
  • 單表達式閉包的隱式返回
  • 速記參數(shù)名稱
  • 尾隨閉包語法

閉包定義的類型

{ (參數(shù)1,參數(shù)2... )->返回值類型 in
     語句塊
}

閉包表達式以及簡化形式:

import UIKit
/// 起別名
typealias DDYTestClosureTypealias = (String, Bool) -> Void

class ClosureTest: NSObject {

    public class func testBasic() {
        testTypealias { (city: String, success: Bool) in
            print("\(city) \(success)") // Beijing true
        }
        testParams()
    }

    private class func testTypealias(_ closure: DDYTestClosureTypealias) {
        closure("Beijing", true);
    }

    private class func testParams() {
        let numbersArray = [1, 3, 5, 9, 7, 2, 8, 6, 0]

        // 參數(shù)加類型
        let sorted1 = numbersArray.sorted { (num1: Int, num2: Int) -> Bool in
            return num1 > num2 // 降序
        }
        // 參數(shù)省略類型(編譯器推斷類型)
        let sorted2 = numbersArray.sorted { num1, num2 in
            return num1 < num2 // 升序
        }
        // 省略參數(shù)名和類型,用$加數(shù)字引用每個參數(shù)
        let sorted3 = numbersArray.sorted {
            return $1 > $0
        }
        // 如果閉包只包含一行代碼,省略return都可以
        let sorted4 = numbersArray.sorted {
            $0 > $1
        }
        // 閉包還可以存儲在變量中,類似函數(shù)一樣調(diào)用
        let comparator = {(a: Int, b: Int) in a<b }
        let result = comparator(1, 2)
        print("\(sorted1)")
        print("\(sorted2)")
        print("\(sorted3)")
        print("\(sorted4)")
        print("\(result)")
        // [9, 8, 7, 6, 5, 3, 2, 1, 0]
        // [0, 1, 2, 3, 5, 6, 7, 8, 9]
        // [0, 1, 2, 3, 5, 6, 7, 8, 9]
        // [9, 8, 7, 6, 5, 3, 2, 1, 0]
        // true
    }
}

將操作符函數(shù)自動推導為函數(shù)類型

  • 尾隨閉包:當閉包表達式為函數(shù)最后一個參數(shù),可將其寫在括號后。

尾隨閉包用于需要將一個很長的閉包表達式作為最后一個參數(shù)傳遞給函數(shù)。也就是說如果按時的最后一個參數(shù)是閉包,那么在調(diào)用它的時候就可以把這個閉包寫在括號外面,并緊跟括號,函數(shù)的其他參數(shù)則仍然寫在括號之中

private class func testCloseClosure(paramStr: String, paramClosure: (String) -> Void) {
    paramClosure("輸出"+paramStr)
}
private class func testCloseClosurePrint() {
    // 普通調(diào)用
    testCloseClosure(paramStr: "1 普通調(diào)用", paramClosure: { (closureStr) in
    print(closureStr)
    })
    // 尾隨閉包
    testCloseClosure(paramStr: "2 尾隨閉包") { (closureStr) in
    print(closureStr)
    }
    // 輸出1 普通調(diào)用
    // 輸出2 尾隨閉包
}
  • 自動閉包:不接受任何參數(shù),直接返回表達式的值。允許延遲計算。
var cities = ["Beijing","Shanghai","New York", "Paris","London"]
print(cities.count)  //此時的城市數(shù)是5

let filter = { cities.removeLast() } //()->String 將閉包賦值給filter,此時還沒有執(zhí)行removeLast()

print(cities.count) //由于上一句并沒有執(zhí)行removeLast()此時的城市數(shù)還是5

print("Deleting \(filter())!") //執(zhí)行了filter的閉包。 顯示Deleting London!

print(cities.count) //此時的城市數(shù)是4, London被刪除掉了

函數(shù)類型與閉包的變量捕獲
函數(shù)類型和閉包可以捕獲其所在上下文的任何值:

  • 函數(shù)參數(shù)
  • 局部變量
  • 對象實例屬性
  • 全局變量
  • 類的類型屬性
//捕獲實例屬性
class Rectangle{
      var width = 0
      var length = 0
     
      func getComputHandler()-> ()->Int {
          return {
               return self.width*self.length //這個閉包就捕獲了實例屬性self.width和self.length
          }
      }
}

//捕獲參數(shù)或局部變量
func addHandler(step: Int)-> ()->Int{
        var sum = 0
      return{
          sum +=step  //這里捕獲了參數(shù)step和局部變量sum 
          return sum
      }
}

let addByTen = addHandler(10)

print(addByTen())  //顯示結(jié)果 10
print(addByTen())  //顯示結(jié)果 20
print(addByTen())  //顯示結(jié)果 30

如果捕獲值生存周期小于閉包對象(參數(shù)和局部變量),系統(tǒng)會將被捕獲的值封裝在一個臨時對象里,然后再閉包對象上創(chuàng)建一個對象指針,指向該臨時對象。

臨時對象和閉包對象之間是強引用關(guān)系,生存周期跟隨閉包對象。

起別名

// 光強檢測閉包起別名
typealias DDYQRBrightnessClosure = (_ brightnessValue: Double) -> Void

// 光強檢測數(shù)據(jù)閉包回調(diào)
public var brightnessClosure: DDYQRBrightnessClosure?

使用閉包需要注意內(nèi)存管理,當閉包為參數(shù)時如果以脫離函數(shù)則需要聲明為逃逸閉包(類型前加@escaping)

逃逸閉包

當一個閉包作為參數(shù)傳到一個函數(shù)中,但是該閉包要在函數(shù)返回之后才被執(zhí)行,于是就稱這樣的閉包為逃逸閉包。也就是說閉包逃離了函數(shù)的作用域。寫法是在這個閉包參數(shù)前加一個@escaping用來指明這個閉包是允許逃逸出該函數(shù)的。

//定義數(shù)組,里面的元素都是閉包類型的
    var callBackArray : [(Int)->Void] = []
    //定義一個接收閉包的函數(shù)
    private func testEscapingClosure() {
        testEscapingClosureChange()
        print("111: \(closureX)")
        callBackArray.first?(5)
        print("222: \(closureX)")
        let closure = callBackArray.first
        closure?(6)
        print("333: \(closureX)")
    }

    var closureX = 10
    private func testEscapingClosureChange() {
        testEscapingClosureCallBack { (closureParam) in
            self.closureX = self.closureX+closureParam
        }
    }
    private func testEscapingClosureCallBack(callBack:@escaping (Int)-> Void) {
        callBackArray.append(callBack)
    }

逃逸閉包實際應用

/// 相機權(quán)限
///
/// - Parameter closure: 閉包回調(diào)
public static func cameraAuth(_ closure: @escaping (Bool) -> Void) -> Void {
    let authStatus = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
    switch authStatus {
    case .notDetermined:
    AVCaptureDevice.requestAccess(for: AVMediaType.video) { (granted: Bool) in
        DispatchQueue.main.async {
            closure(granted)
        }
    }
        break
    case .authorized:
    DispatchQueue.main.async {
        closure(true)
        }
    break
    default: // case .restricted // case .denied
        DispatchQueue.main.async {
        closure(false)
    }
        break
    }
}

解決循環(huán)引用的三種方式

// 1、可以使用weak關(guān)鍵字將對象之間的聯(lián)系變?yōu)槿跻?weak var weakself = self

// 2、第一種方式的簡化
[weak self]

// 3、使用unowned解決
[unowned self]
// 但是該方法十分危險,要確保數(shù)據(jù)一定有值,否則會Crash

閉包資料
閉包資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學習記錄文檔,今天18年5月份再次想寫文章,發(fā)現(xiàn)簡書還為我保存起的...
    Jenaral閱讀 3,146評論 2 9
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young閱讀 4,197評論 1 10
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,674評論 1 32
  • 參考資源《swifter》https://github.com/iOS-Swift-Developers/Swif...
    柯浩然閱讀 1,536評論 0 6
  • 人生經(jīng)歷大苦難,大變局,可能會對性格產(chǎn)生不可估量的影響。這種影響不是你想拒絕就能拒絕的,而且彼時你也起不了拒絕的心...
    老誠少年閱讀 282評論 0 4

友情鏈接更多精彩內(nèi)容