Edited at

SwiftでKotlinのスコープ関数を作ってみた


スコープ関数

スコープ関数とは、関数を引数に取ることで、関数のスコープを変えることができる関数です。

Kotlinの標準ライブラリにある apply let run with also が当てはまります。

これを使うことで、1つのオブジェクトに対してたくさんの処理をしたいときに簡潔に記述できるようになります。

スコープ関数の使い方については以下の記事を参考にしてください。

Kotlin スコープ関数 用途まとめ


Swiftにはスコープ関数はない

今までKotlinをやってきて、今まさにSwiftをやっているのですが、Kotlinの let also を使えなくて、不便だと感じることがありました。

なので、SwiftのClosureを使って、let alsoと使えるようにしました。


ソースコード

import Foundation

// ------------------ let ------------------
protocol LetProtocol {}

extension LetProtocol {
func `let`(_ closure: (Self) -> Void) {
closure(self)
}
}

extension NSObject: LetProtocol {}

// ------------------ also ------------------
protocol AlsoProtocol {}

extension AlsoProtocol {
func also(_ closure: (Self) -> Void) -> Self {
closure(self)
return self
}
}

extension NSObject: ApplyProtocol {}

let は、自身を引数として受け取った関数を実行します。

Kotlinの let と若干違う点は、Kotlinのほうでは関数を実行後に任意の型を返しており、返り値を設定してない場合は返り値がUnitが返っている点です。

also は、自身を引数として受け取った関数を実行しているところまでは letと同じで、異なるところは自身を返しているところです。


letの使用例

UserDefaultsに値を保存するとき

// ------------------ Before ------------------ 

UserDefaults.standard.set("aaaaaaa", forKey: "key1")
UserDefaults.standard.set("bbbbbbb", forKey: "key2")

// ------------------ After ------------------
UserDefaults.standard.let { it in
// UserDefaultsのスコープ
it.set("aaaaaa", forKey: "key1")
it.set("bbbbbb", forKey: "key2")
}


alsoの使用例

コードでUILabelを作るとき

// ------------------ Before ------------------ 

let helloLabel = UILabel()
helloLabel.frame = CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0)
helloLabel.text = "Hello"
helloLabel.textColor = UIColor.red

// ------------------ After ------------------
let helloLabel = UILabel().also { it in
// UILabelのスコープ
it.frame = CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0)
it.text = "Hello"
it.textColor = UIColor.red
}

このUILabelをViewに追加するとき、わざわざhelloLabelのnamespaceを設定することなく、書くことができるようになります。

addSubview(UILabel().also { it in

it.frame = CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0)
it.text = "Hello"
it.textColor = UIColor.red
})


スコープ関数を使ったメリット


  • スコープを絞ることができた

  • 1つのオブジェクトに対する処理{}内でまとめられた

  • コードがすっきりした

  • namespaceを省略して書くこともできる