iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 7
0
自我挑戰組

IOS app開發介紹系列 第 7

IOS app開發介紹 - IOS一些重要的概念與機制(3. Closure)

  • 分享至 

  • xImage
  •  

Closure特性:

1.在stack中被建立,運作於heap裡面
2.所有在closure裡面用到的物件會自動被保留
3.是一個物件
4.通常用來做callback函式

範例程式碼:

func test(data: Int, callback: @escaping (Bool) -> ()) {
        callback(true)
}

test(data: 1) {
        (result) -> Void in
        if result {
            print("success")
        }
}

Note:
@escaping其實只有在程式執行會跳脫function的sequential的執行流程時才需要用到,例如:
EX1(非同步下載資料):

 func test(callback: @escaping (Bool) -> ()) {
     downloadData { //非同步,跳脫原本function的sequential執行流程
         (result) -> Void in
         callback(result)
     }
 }

EX2(非同步執行):

 func test(callback: @escaping (Bool) -> ()) {
     DispatchQueue.global.async { //非同步,跳脫原本function的sequential執行流程
         (result) -> Void in
         callback(result)
     }
 }

以下分成三個方面來了解Closures:

1.三種形式
2.表達式簡化方法
3.優點

三種形式:

1. 全域函數(Global functions)有自己的名稱且不capture any values
2. 內嵌函數(Nested functions)有自己的名稱且能從自己被定義的function內capture any values
3. Closure表達式沒有自己的名字且從自己被定義的context範圍內capture values

Note:

Capture values指的是能夠存取及保留所用到的變數reference,即便那個變數定義在closure之外
以官方的例子來說明:
一個產生針對input加固定數字的function

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

makeIncrementer是一個裡面包含nested function(即incrementer)的function

以func incrementer()這個nested function為主來看,先記住runningTotalamount都定義在func incrementer()以外
現在我們來產生一個固定針對input加10的function:
let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen這個function block內定義的變數沒有包含runningTotalamount,仍就只有:

   func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }

但是因為Closure能保留並存取用到的變數runningTotalamount,所以incrementByTen這個function來對input加上10

如果我們現在創另外一個incrementer來對input加7:
let incrementBySeven = makeIncrementer(forIncrement: 7)
incrementBySeven一樣能使用變數runningTotalamount,且變數runningTotalamount是新的一份,不會和incrementByTen共用變數runningTotalamount,所以就能夠來進行加7,而不是加10。

表達式簡化方法:

1. 根據context推斷參數和回傳值型態
2. 從單一表達式中中暗含回傳值
3. 參數名稱簡化
4. closure為最後一個參數的簡化表達式

優點:

1.簡化function語法,省去function名稱,或更多
ex:  A + B
   用function: 
   funcAdd(a: Int,b: Int) -> Bool {
	   return a > b
   }
   assert(funcAdd(a:a,b:b), "error, a can not larger than b")
   
   用closure:
   assert(a > b, "error, a can not larger than b")
2.用來定義常用的行為,讓常用的行為變成像是語言提供的語法

例如: 判斷數值是否為奇數
A)全部使用function:

    funcTest1(arr: [Int]) -> Void {
		for item in arr {
			if funcIsOdd(val: item) {
				print("\(item)")
			}
		}
	 }	
	 funcTest2(arr: [Int]) -> Void {
		for item in arr {
			if funcIsEven(val: item) {
				print("\(item)")
			}
		}
	 }			 
	 funcIsOdd(val: Int) -> Bool {
	 	return val % 2 != 0 
	 }
	 funcIsEven(val: Int) -> Bool {
		return  val % 2 == 0
	 }
	 let a = [1,2,3,4]
	 funcTest1(arr: a)
	 funcTest2(arr: a)
   

B) 使用Closure

funcTest(arr: [Int], closure: (val: Int) -> Bool) -> Void {
    for item in arr {
        if closure(val: item) {
            print("\(item)")
        }
    }
}
let a = [1, 2, 3]
let isOdd = { $0%2 == 1} //note:isOdd就像是語言提供的基本語法,讓我們找出array中的數字是否為奇數
let isEven = { $0%2 == 0} //note:isEven就像是語言提供的基本語法,讓我們找出array中的數字是否偶數
funcTest(arr: a, isOdd)
funcTest(arr: a, isEven)

	

ref:
https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E6%95%99%E5%AE%A4/%E7%B0%A1%E6%98%93%E8%AA%AA%E6%98%8Eswift-4-closures-77351c3bf775
https://airspeedvelocity.net/2014/06/28/extending-the-swift-language-is-cool-but-be-careful/

官方說明:
https://docs.swift.org/swift-book/LanguageGuide/Closures.html


上一篇
IOS app開發介紹 - IOS一些重要的概念與機制(2.記憶體管理 )
下一篇
IOS app開發介紹 - IOS一些重要的概念與機制(4. Multi-threads)
系列文
IOS app開發介紹22
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言