Swift 中的 #function 到底是什么?

| Swift , iOS

 

内容概览

  • 前言
  • 在文件最顶层中的含义及用法
  • 在变量/属性中的含义及用法
  • 在函数/方法中的含义及用法
  • 注意事项
  • 总结

 

前言

 

最近和同事在 Swift 中调用 ObjC 运行时方法的时候提起了 #function 这个字面量表达式。

然而,我发现大家好像对于这个字面量表达式的理解并不全面,当然也包括我自己。

查看了官方文档后,发现其含义可以概括为:

The name of the declaration in which it appears.

后续还有一段详细的解释:

Inside a function, the value of #function is the name of that function, inside a method it is the name of that method, inside a property getter or setter it is the name of that property, inside special members like init or subscript it is the name of that keyword, and at the top level of a file it is the name of the current module.

然而,我在看完之后还是想实际输出这些值,以确认自己的理解是到位的。

所以,现在就来总结一下 #function 这个字面量表达式的含义以及用法。

 

在文件最顶层中的含义及用法(不在任何函数、类型中)

print(#function, #line) // TestFunction

当前项目/模块的名称是 TestFunction,此时 #function 确实是模块的名称。

 

在变量/属性中的含义及用法

在自由的变量中(不隶属于任何类型)

var testVar: Int {
    get {
        print(#function, #line) // testVar
        return 0
    }
    set {
        print(#function, #line) // testVar
    }
}

let value = testVar
testVar = 1

可以看到,此时 #function 是该变量的名称。

在属性中

class TestClass {
    var testVar: Int {
        get {
            print(#function, #line) // testVar
            return 0
        }
        set {
            print(#function, #line) // testVar
        }
    }
}

let value1 = cls.testVar
cls.testVar = value1

可以看到,此时 #function 是该属性的名称。

 

在函数/方法中的含义及用法

 

在自由的函数中(不隶属于任何类型)

func testFunction(arg: Int) {
    print(#function, #line) // testFunction(arg:)
}

testFunction(arg: 1)

func testFunction1(_ arg: Int) {
    print(#function, #line) // testFunction1(_:)
}

testFunction1(1)

可以看到,此时 #function 是该方法的名称。请注意 testFunctiontestFunction1 的区别,前者有参数标签,而后者省略了参数标签。所以,#function 输出的值也不同。

作为函数的默认参数

func testFunction2(functionName: String = #function) {
    print(functionName, #line) // TestFunction
}

testFunction2()

可以看到,此时 #function 是模块的名称(testFunction2() 是在当前文件的最顶层调用的)。

在方法中

class TestClass {
    init(value: Int) {
        testVar = value
        print(#function, #line) // init()
    }

    subscript(index: Int) -> Self {
        print(#function, #line) // subscript(_:)
        return self
    }

    func testFunction(arg: Int) {
        print(#function, #line) // testFunction(arg:)
    }
}

let cls = TestClass()
_ = cls[0]
cls.testFunction(arg: 1)

可以看到,此时 #function 是该方法的名称。

但是,请注意 subscript(index: Int) -> Self 中的 #function 并没有 index 参数标签,这一点和普通的函数/方法有所区别。

 

注意事项

可能有朋友会将 #function 作为一些 ObjC 方法的参数。此时,大家一定要小心!

通过上图,我们可以发现 #function 其实是有具体类型的,而且它的类型是 String
这也可以解释为何 #function 可以作为 func testFunction2(functionName: String = #function) 中的默认参数。

那么,这会有什么问题呢?

我们知道,Swift 中的很多基础类型都是值类型(Int, Float, Double, Bool, String, enum, struct, Array, Dictionary, Set)。String 是值类型。
所以,它和 NSString 有本质上的不同!因为 NSString 是引用类型,而且它的基类是 NSObject

大多数时候,编译器会帮我们自动桥接 StringNSString。但是,我们一定要注意桥接是在何时发生的,桥接有没有可能并没有按我们预期的方式工作。

 

总结

 

在使用 Swift 与 ObjC 进行混编时,编译器帮我们做了很多事情。这样,我们就可以专注于业务,而不是语言之间的细节。
然而,我们还是要当心可能存在的概念混淆,以及自动发生的桥接操作。

不得不说,bug 往往就在一念之间~ 😆

 

参考内容:
Swift - Expressions

 

觉得不错?点个赞呗~

本文链接:Swift 中的 #function 到底是什么?

转载声明:本站文章如无特别说明,皆为原创。转载请注明:Ficow Shen's Blog

评论区(期待你的留言)