Swift如何打印修改结构体属性的所属文件或类名称
实现方案
这里提供两种常用实现方式,你可以根据自己的业务场景选择:
方案1:调用侧零侵入(推荐)
利用Swift的属性观察器+线程调用栈解析,不需要修改任何现有赋值代码,只需要调整People结构体的属性定义即可:
import Foundation struct People { var name: String = "" { didSet { // 取第2位调用栈符号(第0位是当前didSet本身) guard Thread.callStackSymbols.count >= 2 else { print("Unknown edited People") return } let stackInfo = Thread.callStackSymbols[1] // 解析调用方类名 let pattern = #"[^ ]+ +[^ ]+ +([^\.]+)\."# if let regex = try? NSRegularExpression(pattern: pattern), let match = regex.firstMatch(in: stackInfo, range: NSRange(stackInfo.startIndex..., in: stackInfo)), let range = Range(match.range(at: 1), in: stackInfo) { let callerName = String(stackInfo[range]) print("\(callerName) edited People") return } // 解析失败时回退输出默认值 print("Unknown edited People") } } }
之后你在任意位置赋值people.name = "Tom"都会自动输出对应调用方的类名。
方案2:精度更高的属性包装器方案
如果需要更精准的自定义输出内容,避免调用栈解析的偶发误差,可以用属性包装器实现:
首先定义属性包装器:
@propertyWrapper struct EditLog<T> { private var storedValue: T var wrappedValue: T { get { storedValue } set { // 直接赋值时默认取文件名作为调用方标识 let fileName = (#file as NSString).lastPathComponent.replacingOccurrences(of: ".swift", with: "") print("\(fileName) edited People") storedValue = newValue } } init(wrappedValue: T) { self.storedValue = wrappedValue } /// 传入调用方实例精准输出类名 mutating func set(_ value: T, caller: Any) { storedValue = value let callerName = String(describing: type(of: caller)) print("\(callerName) edited People") } }
调整People结构体定义:
struct People { @EditLog var name: String = "" }
使用方式:
// 在ClassA.swift中调用时 var people = People() // 方式1:直接赋值,自动输出文件名 people.name = "Tom" // 方式2:传入self,精确输出类名 people.$name.set("Tom", caller: self)
内容的提问来源于stack exchange,提问作者Steven Jiang
相关产品推荐
相关产品推荐

