Swift Tips 007 - Using `#function` for UserDefaults key consistency

每天了解一点不一样的 Swift 小知识

代码截图

小笔记

这段代码在说什么

这段代码为 UserDefaults 进行了扩展,并为其增加了一个名称为 onboardingCompleted,类型为 BOOL 的计算属性,用于获取 UserDefaults 里是键名为 onboardingCompleted 的值

#function 是什么

#function 是 Swift 编译器为我们提供的一个编译符号,它的作用是描述包含这个符号的方法名称,除了 #function,以外常用的几个编译符号还有 #column#line#file

符号 类型 描述
#file String 包含这个符号的文件的路径
#line Int 符号出现处的行号
#column Int 符号出现处的列
#function String 包含这个符号的方法名字

在 Swift 3.0 之前,#function 的写法是 __FUNCTION__

这些编译符号怎么用?

可以简单的将这些编译符号理解为一个变量,所以怎么使用变量就怎么使用这些编译符号吧。

代码截图里展示了如果在方法里面使用编译符号,下面的代码将展示如何在方法定义里使用编译符号。

这里假设我们要打印出某个方法的相关信息,例如它所在的文件名称,调用方名称,当前行数等。

func printLog<T>(message: T,
file: String = #file,
method: String = #function,
line: Int = #line)
{
print("\((file as NSString).lastPathComponent)[\(line)], \(method): \(message)")
}

那么它的输出结果就会是这样的

// Test.swift
func method() {
//...
printLog("这是一条输出")
//...
}
// 输出:
// Test.swift[62], method(): 这是一条输出

这样做的好处是什么

说好处之前,我们先想想,如果不用 #function 的话,我们会怎样从 UserDefaults 里取 key 值呢?八成你的代码会如下所示:

extension UserDefaults {
var onboardingCompleted: Bool {
get { return bool(forKey:"onboardingCompleted") }
set { set(newValue, forKey: "onboardingCompleted") }
}
}

在这种状况下,我们要自己手动保证 gettersetter 里面 key 值的一致,这就增加了出错的概率。

通过图片里的方式,即使用 #function 作为 key 的话,就很好的保证了 gettersetter 里 key 值的一致问题,我们只需要关心方法名是否为我们需要的 key 即可。