如何确定哪个对象/类正在调用全局Swift函数?

时间:2015-02-10 17:18:15

标签: swift

使用此代码:

func externalFunc() {
    println("How can I know which object/class is calling me?")
}

class Test {
    func callExternalFunc() {
        externalFunc()
    }
}

在Objective-C运行时objc_msgSend passes two hidden parameters中我们发送的每条消息。他们是自我 _cmd 。 (Source

在上面的示例中,有没有办法知道谁在调用externalFunc

4 个答案:

答案 0 :(得分:17)

我不确定是否有办法自动获取此信息,但如果您向函数添加String类型的默认参数并将其设置为#function,则可以获取此信息。

例如......

func externalFunc(callingFunctionName: String = #function) {
    println("Calling Function: \(callingFunctionName)")
}

然后你可以在没有添加默认参数的情况下调用它...

let test = Test()
test.callExternalFunc()

它将打印以下内容......

"Calling Function: callExternalFunc()"

答案 1 :(得分:7)

如果您愿意修改方法签名,可以执行以下操作:

func externalFunc(file: String = #file, line: Int = #line) {
    println("calling File:\(file) from Line:\(line)")
}

来自apple的swift blog

  

Swift借用D语言的一个聪明的功能:这些标识符   (__FILE__& __LINE__)扩展到调用者的位置   在默认参数列表中进行评估。

请注意, __ FILE __ __ LINE __ 已在Swift 2.2中弃用,并已在Swift 3中删除。它们被 #file 取代,和 #line

答案 2 :(得分:1)

这是我在github上找到的一个很棒的实用工具类:

https://github.com/nurun/swiftcallstacktrace

像这样使用:

let callingMethodInfo = CallStackAnalyser.getCallingClassAndMethodInScope(false)

if let callingMethodInfo = callingMethodInfo {
   NSLog("class: %@", callingMethodInfo.0)
   NSLog("method: %@", callingMethodInfo.1)
}

答案 3 :(得分:-1)

在您的问题中,您提到了self_cmd

可以在Swift中以与Obj-C相同的方式访问

self(这是合乎逻辑的)。

_cmd(当前方法的选择器)无法访问。没有理由可以访问它,Swift没有在Obj-C上下文之外使用选择器(在纯Swift中你不能动态调用选择器)。唯一的用例是打印当前函数的名称以进行调试。使用__FUNCTION__宏可以在Obj-C(或C)中实现相同的效果。在Swift中也可以实现同样的目标:

func getCurrentFunctionName(functionName: StaticString = #function) -> String {   
    return String(functionName)
}

func externalFunc() {
    print("Function name: \(getCurrentFunctionName())") // prints "externalFunc"
}

请注意,在您的示例中,externalFunc函数,而不是方法。即使在Obj-C中,self_cmd也不可用。

如果你想知道谁调用了你的方法(我真的认为你想知道它用于调试目的),那么你可以检查你的调用栈:

func externalFunc() {
    let stackSymbols = NSThread.callStackSymbols()
    stackSymbols.forEach {
        let components = $0.stringByReplacingOccurrencesOfString(
            "\\s+",
            withString: " ",
            options: .RegularExpressionSearch,
            range: nil
        ).componentsSeparatedByString(" ")

        let name = components[3] 
        let demangledName = _stdlib_demangleName(name)    
        print("\(demangledName)")
    }
}

打印(对于我的项目名为SwiftTest):

SwiftTest.externalFunc () -> ()
SwiftTest.Test.callExternalFunc () -> ()
main
start
0x0