学习 swift 中的 dynamicCallable 关键字 - 知乎

265 阅读2分钟

这里每天分享一个 iOS 的新知识,快来关注我吧

@dynamicCallable

@dynamicCallable 是 Swift 5.0 中新增的一个属性,它可以让 structenumprotocolclass也拥有像函数一样可以被调用的能力。

我们都知道 swift 在和 C 语言、OC 交互的时候很容易,但是和其他语言交互就不那么容易了,这个特性其目的就是为了使 Swift 代码能和类似 PythonJavaScriptPerlRuby 等动态语言之间交互。

@dynamicCallable 的使用

structclass 添加 @dynamicCallable 属性:

@dynamicCallable
struct Math {
    func dynamicallyCall(withArguments args: [Int]) -> Int {
        print(args)
        // 实现调用逻辑
        return 0
    }
    
    func dynamicallyCall(withKeywordArguments args: KeyValuePairs<String, Int>) -> Double {
        print(args)
        // 实现调用逻辑
        return 0
    }
}

标记 @dynamicCallable 之后,dynamicallyCall(withArguments:) 方法和 dynamicallyCall(withKeywordArguments:) 方法至少实现其中一个,或者两个都实现。

之后就可以像调用函数一样调用 Math:

let m = Math()
let result1 = m(1, 2) 
let result2 = m(a: 1, b: 2) 

当执行 m(1, 2) 方法时会调用 m 的 dynamicallyCall(withArguments:) 方法,打印 [1, 2]。

当执行 m(a: 1, b: 2) 方法时会调用 m 的 dynamicallyCall(withKeywordArguments:) 方法,打印 ["a": 1, "b": 2]。

dynamicCallable 的原理

@dynamicCallable 原理是 Swift 编译器会将调用转换成对应的 dynamicallyCall 方法的调用。

当调用 m(1, 2) 时,编译器底层会转换成:

m.dynamicallyCall(withArguments: [1, 2])

当调用 m(a: 1, b: 2) 时,编译器底层会转换成:

m.dynamicallyCall(withKeywordArguments: ["a": 1, "b": 2])

因此我们只需要实现对应的 dynamicallyCall 方法即可拦截所有调用。

dynamicCallable 的用途

@dynamicCallable 使得 structclass 可以像函数一样被调用,一些使用场景包括:

  • 创建自定义操作符(运算符重载)

  • 方法的动态调用,可以做一些特殊情况的保底逻辑

  • 实现函数式编程

  • 结合 @dynamicMemberLookup 关键字可以和其他动态语言交互

总体来说,@dynamicCallable 为 Swift 增加了表达能力,使语法更加灵活。

本文同步自微信公众号 “iOS新知”,每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!