Swift function alias - swift

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:"")
}

Related

swift - is it possible to create a keypath to a method?

Is it possible to create a keypath referencing a method? all examples are paths to variables.
I'm trying this:
class MyClass {
init() {
let myKeypath = \MyClass.handleMainAction
...
}
func handleMainAction() {...}
}
but it does not compile saying Key path cannot refer to instance method 'handleMainAction()
KeyPaths are for properties. However, you can do effectively the same thing. Because functions are first class types in swift, you can create a reference to handleMainAction and pass it around:
//: Playground - noun: a place where people can play
import UIKit
import XCTest
import PlaygroundSupport
class MyClass {
var bar = 0
private func handleMainAction() -> Int {
bar = bar + 1
return bar
}
func getMyMainAction() -> ()->Int {
return self.handleMainAction
}
}
class AnotherClass {
func runSomeoneElsesBarFunc(passedFunction:() -> Int) {
let result = passedFunction()
print("What I got was \(result)")
}
}
let myInst = MyClass()
let anotherInst = AnotherClass()
let barFunc = myInst.getMyMainAction()
anotherInst.runSomeoneElsesBarFunc(passedFunction: barFunc)
anotherInst.runSomeoneElsesBarFunc(passedFunction: barFunc)
anotherInst.runSomeoneElsesBarFunc(passedFunction: barFunc)
This will work fine, and you can pass "barFunc" to any other class or method and it can be used.
You can use MyClass.handleMainAction as an indirect reference. It gives you a block that take the class instance as the input parameter, and returns corresponding instance method.
let ref = MyClass.handleMainAction //a block that returns the instance method
let myInstance = MyClass()
let instanceMethod = ref(myInstance)
instanceMethod() //invoke the instance method
The point is you can pass around / store the method reference just like what you did with a key path. You just need to supply the actual instance when you need to invoke the method.

custom console log in swift [duplicate]

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)
}
}

Swift: How to add a class method in 'String" extension

I want to add a class function into extension:
extension String {
class func test () {
}
}
I get the error: Class methods are only allowed within classes; use 'static' to declare a static method
Or how should i call " String.test()"
But for NSString
extension NSString {
class func aaa () {
}
}
no errors.
If i add static keyword:
extension String {
static func aaa () {
self.stringByAppendingString("Hello")
}
}
Got: Expression resolves to an unused function,
So how should i add a class function also want to use self. method.
EDIT: This works!
extension String {
static func aaa (path:String) -> String {
return path.stringByAppendingString("Hello")
}
}
but about #lan's answer:
mutating func bbb(path: String) {
self += "world"
}
When i type it appears like this:
String.bbb(&<#String#>)
String.bbb(&"nihao")
Cannot invoke 'bbb' with an argument list of type '(String)'
Class and static functions are not called on an instance of a class/struct, but on the class/struct itself, so you can't just append a string to a class.
Apple Documentation:
Within the body of a type method, the implicit self property refers to
the type itself, rather than an instance of that type.
You can, however, append a string to a variable instance of a String using the mutating keyword:
extension String {
mutating func aaa() {
self += "hello"
}
}
let foo = "a"
foo.aaa() // ERROR: Immutable value of type 'String' only has mutating members named 'aaa'
var bar = "b"
bar.aaa() // "bhello"
If you are trying to use a pointer to a string as a parameter, you can use the inout keyword to alter the inputed string:
extension String {
static func aaa(inout path: String) {
path += "Hello"
}
}
var foo = "someText"
String.aaa(&foo)
foo //someTextHello
While correct, it's somewhat atypical to see a mutating member added to a String extension as shown in Ian's answer. Strings (and value types in general) are meant to be immutable so the only way to use a mutating method is to declare instances var at the call site. Most of the time in your code you should be using let constants.
As such, it is much more common to extend structs to return new instances. So this is typical:
extension String {
func appending(_ string: String) -> String {
return self + string
}
}
and then at the call site:
let hello = "Hello, "
let helloWorld = hello.appending("World!")
You'll note of course that I'm not using static at all. That's because appending(_:) needs to use the current instance value of the String we're appending to, and class/static do not refer to instances and therefore do not have values.
"Within the body of a type method, the implicit self property refers to the type itself, rather than an instance of that type."
Thus when you extend a type by adding a type method you can only call other type methods through self. If you want to call an instance method you need to create an instance and call a method on that.

Swift: determine what object called a function?

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 to determine which object/class is calling a global Swift function?

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