Swift Scope Functions


Swift Scope Functions

在 Kotlin 中我們經常用 apply, also, let, run 之類的好用的 Scope Functions

// kotlin file
class Cat(){
    var name = ""
}

fun main(args : Array<String>){
    val cat = Cat()
    cat.apply {
        this.name = "喵的名字"
    }
}

但是 在 Swift 中卻沒有類似的解決方案

例如 每當我們要初始化 table view 我們會這樣寫

// in swift file ViewController 
tableview.delegate = self
tableview.dataSource = self
tableview.reloadData()

但吃過 kotlin 方便的我們很下意識的寫下

// in swift file ViewController 
tableview?.apply {
    $0.delegate = self
    $0.dataSource = self
    $0.reloadData()
}

此時當然馬上噴錯啊

為了讓我們可以更懶惰的寫扣 我們寫出下面swift

// swift file
import Foundation

protocol ScopeFunc {}

extension ScopeFunc {
    @discardableResult
    func also(block: (Self) -> ()) -> Self {
        block(self)
        return self
    }
    
    @discardableResult
    func apply(block: (Self) -> ()) -> Self {
        block(self)
        return self
    }
    
    @discardableResult
    func `let`<R>(block: (Self) -> R) -> R? {
        return block(self)
    }
    
    @discardableResult
    func run<R>(block: (Self) -> R) -> R? {
        return block(self)
    }
}

extension Optional where Wrapped: ScopeFunc { }

extension NSObject: ScopeFunc {}
extension Array: ScopeFunc {}
extension String: ScopeFunc {}
extension String.SubSequence: ScopeFunc {}
extension Int: ScopeFunc {}
extension Float: ScopeFunc {}
extension Double: ScopeFunc {}
extension Bool: ScopeFunc {}

這樣我們就可以開心的用 apply 初始化了

// in swift file ViewController 
tableview?.apply {
    $0.delegate = self
    $0.dataSource = self
    $0.reloadData()
}

咦!! 你說我剛上面 ScopeFunc 裡面的 applyalso 寫的一樣, letrun 寫的也一樣

對啊~ 讓我們看看 Scope Functions 文件 一開始有寫到

Basically, these functions do the same: execute a block of code on an object. What’s different is how this object becomes available inside the block and what is the result of the whole expression.

可以得知 Scope Function 其實主要目的是提高可讀性 因此我才寫了一樣的方法不一樣的名稱

不對啊你說 因為在 kotlin 的 let, also 裡面用是用 itapply, run 用的是 this 但這樣寫都只能用 $0 相當於 kotlin 的 it 啊, 那 this

對喔會這樣寫是因為在 swift 中 lambda 裡面使用 self 會呼叫到外層的 class 實體, 所以我才使用 $0

當然可能有高手可以克服這個問題 反正我是沒辦法


WRITTEN BY
Aki

熱愛寫code的開發者,專注於 Android 手機 Native App 開發,對於 IOS 也有涉略。閒暇之餘也學習 JavaScript 等前端框架