With this code:
func externalFunc() {
println("How can I know which object/class is calling me?")
}
class Test {
func callExternalFunc() {
externalFunc()
}
}
In the Objective-C runtime objc_msgSend passes two hidden parameters to every message we send. They are self and _cmd. (Source)
In the above example, is there any way to know who is calling externalFunc?
I'm not sure if there is a way to obtain this automatically, but you can get this info if you add a default param of type String to the function and set it to #function.
For example...
func externalFunc(callingFunctionName: String = #function) {
println("Calling Function: \(callingFunctionName)")
}
Then you would call it without the added default param...
let test = Test()
test.callExternalFunc()
And it would print the following...
"Calling Function: callExternalFunc()"
If you are willing to modify the method signature you could do something like below:
func externalFunc(file: String = #file, line: Int = #line) {
print("calling File:\(file) from Line:\(line)")
}
From apple's swift blog
Swift borrows a clever feature from the D language: these identifiers
(__FILE__ & __LINE__ ) expand to the location of the caller when
evaluated in a default argument list.
Note that __FILE__ and __LINE__ have been depreciated in Swift 2.2 and have been removed in Swift 3. They are replaced by #file, and #line.
Here's a great utility class I found on github:
https://github.com/nurun/swiftcallstacktrace
Use like this:
let callingMethodInfo = CallStackAnalyser.getCallingClassAndMethodInScope(false)
if let callingMethodInfo = callingMethodInfo {
NSLog("class: %#", callingMethodInfo.0)
NSLog("method: %#", callingMethodInfo.1)
}
In your question you are mentioning self and _cmd.
self is accessible in Swift exactly in the same way as in Obj-C (which is logical).
_cmd (selector of the current method) is not accessible. There is no reason for it to be accessible, Swift doesn't use selectors outside Obj-C contexts (in pure Swift you cannot call selectors dynamically). The only use case for it is to print the name of the current function for debugging purposes. The same can be achieved in Obj-C (or C) using __FUNCTION__ macro. The same can be achieved in Swift:
func getCurrentFunctionName(functionName: StaticString = #function) -> String {
return String(functionName)
}
func externalFunc() {
print("Function name: \(getCurrentFunctionName())") // prints "externalFunc"
}
Note that in your example externalFunc is a function, not a method. Even in Obj-C neither self or _cmd wouldn't be available for it.
If you want to know who has called your method (and I really suppose you want to know it for debugging purposes), then you can inspect your call stack:
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)")
}
}
which prints (for my project called SwiftTest):
SwiftTest.externalFunc () -> ()
SwiftTest.Test.callExternalFunc () -> ()
main
start
0x0
Related
I am writing some Swift code and I would like to know the class of the object that called the function. I don't want to pass in any parameters. From within the function I want to be able to know who called it.
Any suggestion?
If you want to do that using Swift, you can do this:
func debug(file: String = #file, line: Int = #line, function: String = #function) -> String {
return "\(file):\(line) : \(function)"
}
To access the underlying class of a method from within itself, use the dynamicType property:
self.dynamicType
If you want to know the origin of the original call, you can use NSThread to return debugging information about the stack:
NSThread.callStackSymbols()
This method returns a descriptive array of values that you're used to seeing when exceptions are thrown. The strings represent a backtrace of all current activity on your call stack.
I don't want to be presumptuous, but it seems to me that outside of debugging, there isn't a good reason, conceptually, at least, to know the origin of a specific method call for any and every function. If you need to retrieve the class Type of the last method call on the stack, why not implement an interface that lets you access this information through a straightforward route?
You can use following template to know from which file, line number in file, and function this someFunction is called:
func someFunction(file: String = #file, line: Int = #line, function: String = #function)
{
NSLog("\(file.lastPathComponent):\(line) : \(function)")
}
Swift:
Add a (sender: Anyobject) as parameter to that function, and then print the sender (the function caller) like this:
func yourFunc(sender: AnyObject){
print(sender)
}
Or add a symbolic breakpoint with a po thread to see the stack trace of the caller of the method
The final way, use the follow protocol:
protocol PrefixPrint {
func formatPrint(_ text: String, function: String, line: Int) -> Void
}
extension PrefixPrint {
#inline(__always)
func formatPrint(_ text: String, function: String = #function, line: Int = #line) {
#if DEBUG
print("\(self).\(function).\(line): \(text)")
#endif
}
}
Console like: FootBall.VNSocketManager.init().44: xx
Joining together a couple of answers and comments:
func function(file: String = #file) {
if let url = URL(string: file) {
let className = url.deletingPathExtension().lastPathComponent
print(className)
}
}
I am trying to create a generic function that can take an optional argument.
Here's what I have so far:
func somethingGeneric<T>(input: T?) {
if (input != nil) {
print(input!);
}
}
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(nil) // Errors!
It works with a String as shown, but not with nil.
Using it with nil gives the following two errors:
error: cannot invoke 'somethingGeneric' with an argument list of type '(_?)'
note: expected an argument list of type '(T?)'
What am I doing wrong and how should I correctly declare/use this function? Also, I want to keep the usage of the function as simple as possible (I don't want do something like nil as String?).
I guess the compiler can't figure out what T is just from nil.
The following works just fine though for example:
somethingGeneric(Optional<String>.None)
I believe you've overcomplicated the problem by requiring the ability to pass untyped nil (which doesn't really exist; even nil has a type). While the approach in your answer seems to work, it allows for the creation of ?? types due to Optional promotion. You often get lucky and that works, but I've seen it blow up in really frustrating ways and the wrong function is called. The problem is that String can be implicitly promoted to String? and String? can be implicitly promoted to String??. When ?? shows up implicitly, confusion almost always follows.
As MartinR points out, your approach is not very intuitive about which version gets called. UnsafePointer is also NilLiteralConvertible. So it's tricky to reason about which function will be called. "Tricky to reason about" makes it a likely source of confusing bugs.
The only time your problem exists is when you pass a literal nil. As #Valentin notes, if you pass a variable that happens to be nil, there is no issue; you don't need a special case. Why force the caller to pass an untyped nil? Just have the caller pass nothing.
I'm assuming that somethingGeneric does something actually interesting in the case that it is passed nil. If that's not the case; if the code you're showing is indicative of the real function (i.e. everything is wrapping in an if (input != nil) check), then this is a non-issue. Just don't call somethingGeneric(nil); it's a provable no-op. Just delete the line of code. But I'll assume there's some "other work."
func somethingGeneric<T>(input: T?) {
somethingGeneric() // Call the base form
if (input != nil) {
print(input!);
}
}
func somethingGeneric() {
// Things you do either way
}
somethingGeneric(input: "Hello, World!") // Hello, World!
somethingGeneric() // Nothing
Good question and answer. I have an Swift 4 update to contribute:
var str: String? = "Hello, playground"
var list: Array<String>? = ["Hello", "Coder256"]
func somethingGeneric<T>(_ input: T?) {
if (input != nil) {
print(input!);
}
}
func somethingGeneric(_ input: ExpressibleByNilLiteral?) {}
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(nil) // *nothing printed*
somethingGeneric(nil as String?) // *nothing printed*
somethingGeneric(str) // Hello, playground
str = nil
somethingGeneric(str) // *nothing printed*
somethingGeneric(list) // ["Hello", "Coder256"]
list = nil
somethingGeneric(list) // *nothing printed*
I figured it out:
func somethingGeneric<T>(input: T?) {
if (input != nil) {
print(input!);
}
}
func somethingGeneric(input: NilLiteralConvertible?) {}
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(nil) // *nothing printed*
somethingGeneric(nil as String?) // *nothing printed*
I think that you will never call somethingGeneric(nil) but mostly somethingGeneric(value) or somethingGeneric(function()) for which the compiler has enough info not to be stucked trying to guess the type:
func somethingGeneric<T>(input: T?) {
if let input = input {
print(input);
}
}
func neverString() -> String? {
return nil
}
let a: String? = nil
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(a) // Nothing and no error
somethingGeneric(neverString()) // Nothing and no error
Also, I would use the if let syntax instead of if(value != nil).
Here is the solution I came up with that compiles on Swift 5, as many of the solutions here did not compile for me. It might be considered hacky as I use a stored variable to help things along. I was unable to come up with a Swift 5 version of the nil parameters that resolve to type T.
class MyClass {
func somethingGeneric<T>(input: T?) {
if let input = input {
print(input)
}
}
func somethingGeneric() {
somethingGeneric(Object.Nil)
}
}
final class Object {
static var Nil: Object? //this should never be set
}
Actually there is a way to do this, inspired by Alamofire's internal code.
You do not have to install Alamofire to use this solution.
Usage
Your problematic method definition
func someMethod<SomeGenericOptionalCodableType: Codable>(with someParam: SomeGenericOptionalCodableType? = nil) {
// your awesome code goes here
}
What works ✅
// invoke `someMethod` correctly
let someGoodParam1 = Alamofire.Empty.value
someMethod(with: someGoodParam1)
I think it is possible to use Alamofire.Empty.value as a default value in someMethod definition as a parameter.
What does not work ❌
// invoke `someMethod` incorrectly
let someBadParam1: Codable? = nil
let someBadParam2 = nil
someMethod(with: someBadParam1)
someMethod(with: someBadParam2)
Solution definition (source)
/// Type representing an empty value. Use `Empty.value` to get the static instance.
public struct Empty: Codable {
/// Static `Empty` instance used for all `Empty` responses.
public static let value = Empty()
}
If I have a class like this:
class Example {
var emptyBlock: (Void -> Void)?
var string: String = "Here's some string"
func someFunction() {
let string = self.string
print(string)
}
}
And I assign at some point:
let variable: Void -> Void = exampleInstance.someFunction
exampleInstance.emptyBlock = variable
Do I have a retain cycle because variable captures exampleInstance from someFunction and variable is retained by exampleInstance? Or is there some sort of magic that makes this not a problem?
I made a quick test and I believe I've confirmed that they are in fact strongly captured as suspected. I'll post my findings for anyone else who has this question:
Take this class, and breakpoint in deinit:
class Example {
var emptyBlock: (Void -> Void)?
var string: String = "Here's some string"
func someFunction() {
let string = self.string
print(string)
}
deinit {
print("I was deinitialized") // Breakpoint Here
}
}
Then run these two examples of code:
Reference Cycle
Will not hit breakpoint because can't deinitialize:
let exampleInstance = Example()
let variable = exampleInstance.someFunction
exampleInstance.emptyBlock = variable
Non-Reference Cycle
Will hit breakpoint because weekly capturing:
let exampleInstance = Example()
let variable: Void -> Void = { [weak exampleInstance] in exampleInstance?.someFunction() }
exampleInstance.emptyBlock = variable
Because it hits the breakpoint when we weak capture, we can safely conclude that without that it is strongly captured as if a closure.
This should be considered when using this tool since we don't get the same obviousness of capture we do when declaring a closure. There's no explicit warnings to call self to remind us, and there's no weak declarations within their scope.
Guide
I also found a reference in the guide:
Global functions are closures that have a name and do not capture any values.
Nested functions are closures that have a name and can capture values from their enclosing function.
Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.
Yes, there's a retain cycle. Assigning something to a local variable and then assigning it to something else is the same as assigning it directly. So that code is equivalent to
exampleInstance.emptyBlock = exampleInstance.someFunction
and exampleInstance.someFunction is just syntactic sugar for
{ x in exampleInstance.someFunction(x) }
I am writing some Swift code and I would like to know the class of the object that called the function. I don't want to pass in any parameters. From within the function I want to be able to know who called it.
Any suggestion?
If you want to do that using Swift, you can do this:
func debug(file: String = #file, line: Int = #line, function: String = #function) -> String {
return "\(file):\(line) : \(function)"
}
To access the underlying class of a method from within itself, use the dynamicType property:
self.dynamicType
If you want to know the origin of the original call, you can use NSThread to return debugging information about the stack:
NSThread.callStackSymbols()
This method returns a descriptive array of values that you're used to seeing when exceptions are thrown. The strings represent a backtrace of all current activity on your call stack.
I don't want to be presumptuous, but it seems to me that outside of debugging, there isn't a good reason, conceptually, at least, to know the origin of a specific method call for any and every function. If you need to retrieve the class Type of the last method call on the stack, why not implement an interface that lets you access this information through a straightforward route?
You can use following template to know from which file, line number in file, and function this someFunction is called:
func someFunction(file: String = #file, line: Int = #line, function: String = #function)
{
NSLog("\(file.lastPathComponent):\(line) : \(function)")
}
Swift:
Add a (sender: Anyobject) as parameter to that function, and then print the sender (the function caller) like this:
func yourFunc(sender: AnyObject){
print(sender)
}
Or add a symbolic breakpoint with a po thread to see the stack trace of the caller of the method
The final way, use the follow protocol:
protocol PrefixPrint {
func formatPrint(_ text: String, function: String, line: Int) -> Void
}
extension PrefixPrint {
#inline(__always)
func formatPrint(_ text: String, function: String = #function, line: Int = #line) {
#if DEBUG
print("\(self).\(function).\(line): \(text)")
#endif
}
}
Console like: FootBall.VNSocketManager.init().44: xx
Joining together a couple of answers and comments:
func function(file: String = #file) {
if let url = URL(string: file) {
let className = url.deletingPathExtension().lastPathComponent
print(className)
}
}
How can I create an alias for a function in swift?
For example
I want to call
LocalizedString("key")
and it should call
NSLocalizedString("key", comment:"")
I saw typealias command but it looks like it works only for types.
Functions are named closures, so you can just assign a function to a variable:
let LocalizedString = NSLocalizedString
You can create pseudo-aliases for class/struct methods as well. Each method is actually a static (class) curried function, taking a class instance as its first parameter. So given a class:
class MyClass {
var data: Int
init(data: Int) {
self.data = data
}
func test() {
println("\(data)")
}
}
you can assign the test method to a variable:
let test = MyClass.test
and then invoke it as:
var instance = MyClass(data: 10)
test(instance)()
UPDATE
I've just realized that I missed one important detail in your question: you want to hide the comment parameter. And my proposed solution doesn't allow that, whereas #rintaro's solution does.
However I use a different approach for that: I create a String extension implementing a computed property:
extension String {
var localized: String {
return NSLocalizedString(self, comment: "")
}
}
and then I can just call it on any string variable or literal:
var string = "test_resource"
string.localized
"another_resource".localized
The shortest one is:
let LocalizedString = { NSLocalizedString($0, comment:"") }
But, it's actually a new function. Just wrapping NSLocalizedString.
Maybe you can use undocumented #transparent attribute. It inlines function call. see this topic on Developer Forum.
#transparent LocalizedString(key:String) -> String {
return LocalizedString(key, comment:"")
}
But it's not recommended. Moreover, as long as my tests, all of following codes eventually emit exact the same LLVM IR code with -O optimization.
script1: with #transparent
import Foundation
#transparent func LocalizedString(key:String) -> String {
return LocalizedString(key, comment:"")
}
println(LocalizedString("key"))
script2: without #transparent
import Foundation
func LocalizedString(key:String) -> String {
return LocalizedString(key, comment:"")
}
println(LocalizedString("key"))
script3: Direct NSLocalizedString call
import Foundation
func LocalizedString(key:String) -> String {
return LocalizedString(key, comment:"")
}
println(NSLocalizedString("key", comment:""))
All of above are inlined to perform direct NSLocalizedString call.
But, the following code emits different:
script4: Closure wrapping
import Foundation
let LocalizedString = { NSLocalizedString($0, comment:"") }
println(NSLocalizedString("key", comment:""))
It's also inlined, but additional refcount instruction to LocalizedString is inserted.
So, as a conclusion, you should simply use this:
func LocalizedString(key:String) -> String {
return LocalizedString(key, comment:"")
}