カスタム属性・関数ビルダー
要するに@_functionBuilderってのをstruct先頭につければ、@BlockAdderって属性を作ることができる。closureを引数に取る関数の引数にカスタム属性を付与すれば、不思議が起こる。
buildBlockというヘンテコ関数が定義できちゃう訳だ。
// Swift5.1 functionality test, ViewBuilder
// 関数ビルダー、DSL
@_functionBuilder public struct BlockAdder {
public static func buildBlock(_ a: Int) -> Int {
return a
}
public static func buildBlock(_ a: Int, _ b: Int) -> Int {
return a + b
}
public static func buildBlock(_ a: Int, _ b: Int, _ c: Int) -> Int {
return a + b + c
}
public static func buildBlock(_ a: Int, _ b: Int, _ c: Int, _ d: Int) -> Int
{
return a + b + c + d
}
}
func blockAdd(@BlockAdder block: () -> Int) -> Int {
return block()
}
let one = blockAdd {
1
} // 1
let three = blockAdd {
1 // SwiftUIのサンプルではTextに対応するところ
2
} // 3 (1 + 2)
let six = blockAdd { 1; 2; 3 } // 6
let ten = blockAdd { 1; 2; 3; 4 } // 10 (1 + 2 + 3 + 4)
print(one)
print(three)
print(six)
print(ten)
print(blockAdd { 1; 4 })
SwiftUIの魔法を実現する仕組み (Custom Attributes, Function Builder)
カスタム属性・Property Wrapper
今度のカスタム属性は、構造体定義の先頭に付与する。すると構造体のプロパティーを監視する事ができる。
@propertyWrapper
struct AlterableOnce<T> { // インスタンス生成後、一回だけ初期化可能な変数。
private var value: T
private var setFlag = false
init(wrappedValue v: T) { // counterを初期化するメソッド
value = v
}
var wrappedValue: T {
get { value }
set {
if setFlag { print("already set"); return }
value = newValue
setFlag = true
}
}
}
// @AlterableOnce<Int>(wrappedValue: 10) Global変数へは不可
var counter: Int
counter = 20
print(counter)
struct A {
@AlterableOnce(wrappedValue: 1) //Makeshift属性付き変数counterはset時にprintし...
var counter: Int
}
var a = A()
print(a.counter)
a.counter = 2
print(a.counter)
a.counter = 3
print(a.counter)
// 20
// 1
// 2
// already set
// 2
こいつの出典は、詳解Swift第5版、Chapter15
プロパティーではなく、Global変数にカスタム属性を付与したら、現時点では未サポートと警告。将来サポートなのか?
someキーワード
メソッド戻値をGenericsにしたい場合、型パラメータ付きプロトコルにしたい場合に-> some P
とする。
以下のコードはTerminal.Appでは動かず、Playgroundで可能。Bug?
protocol Animal {
func say()
}
class Dog: Animal {
func say() {
print("bark bark")
}
}
class Bird: Animal {
func say() {
print("sing sing")
}
}
// ジェネリクス関数、引数に型パラメーターを記述できるが、戻り値には出来ない。
func say<A: Animal>(_ animal: A) {
animal.say()
}
// 関数戻値にAnimal準拠の何かを返したい
// func makeAnimal<A: Animal>() -> A {
// if xxx then
// return Dog()
// else
// return Cat()
// }
say(Dog()) // bark bark
// makeAnimal().say() // bark bark
func makeAnimal1() -> some Animal {
return Dog()
}
func makeAnimal2() -> some Animal {
return Bird()
}
makeAnimal1().say() // bark bark
makeAnimal2().say() // sing sing
Swift 5.1 に導入される Opaque Result Type とは何か
そして、不透明戻値型とはsome付きのProtocol型の事。
identifiableプロトコルって?
以下のコードも残念ながらTerminal.Appで動作せず。
struct User: Identifiable {
var id: UUID = UUID()
var firstName: String
var lastName: String
}
let a = User(firstName: "OK", lastName: "NG")
print(a.id)
プロパティーidはIntでもコンパイル可能。どういう事?