Swift: how to convert argument to argument name string? - swift

In order to do logging nicely, I want to know how to convert argument to argument name string In Swift.
I already know Logging Method signature using swift.
I want to know how to log function argument as it is , following its value?
PS: I want to create a Util method helping logging.
func printMore(objName: Any){
print("objName: \(objName)")
}
the print("objName:..., I want the 'objName' injected automatically.
Suck as conditions:
let foo = "Sark"
print("foo: \(foo)")
PPS: It is about Swift runtime. After I alloc some memory, I create some objects, how to get them through runtime instead of hard coding.

Hm, if you called next method inside your function, it shows method declaration with all parameters:
func testFunction(param1: String, param2: String) {
print(#function)
}
testFunction(param1:param2:)

Write C .
U have to release it youself
object.description

Related

Swift - Ambiguous reference to member '==' error

I've done some searching and can't seem to find a solution for my below issue. I'm fairly new to swift so working through some issues. I have the below function which is just a stub containing the signature of the function and a return value just to get it to compile.
The test code is what I've been given, I did not write this and unfortunately cannot alter it.
My issues is that when I run it, it says that the test that calls this function has an "Ambiguous call to member '=='". I cannot alter the test code. Whatever the issue is must be in my function signature i'm assuming but could use some help.
Function That I am writing (That I assume contains the issue):
func contains(target: StringOrInt, compare: Character ) -> Bool {
return false
} // contains
Test that calls the function (I'm not allowed to edit this and did not write it):
func test_contains_cons_2_strings_3() {
let list1 = MyList.cons("foo", MyList.cons("bar", MyList.empty))
assertEquals(testName: "test_contains_cons_2_strings_3",
expected: true,
received: list1.contains(target: "bar", compare: ==))//Error is on this line '=='
} // test_contains_cons_2_strings_3
Error:
main.swift:807:67: error: ambiguous reference to member '=='
received: list1.contains(target: "foo", compare: ==))
Also note that "StringOrInt" is a protocol that I've defined that acts as an extension on both Int and String. This is done because the test code (Which i did not write and cannot edit) passes both strings and ints to this same variable and function.
Thanks advance for any help, I really appreciate it!
I think you want to compare two strings by passing "==" operator and return a Boolean value.If so you can use the below method,
func myList(_ compare:((String, String) -> Bool)) -> Bool {
return compare("foo","bar")
}
myList(==)
I was able to figure this out using the below. I implemented an enum of generic type and the nan extension on that enum. I then used this generic type within the contains function to represent multiple types instead of StringOrInt. Thanks everyone for the comments and the help.
enum implemented:
indirect enum my_list<A> {
case cons(A, my_list<A>)
case empty
}
I then implemented in extension for this enum "extension my_list" and placed the contains function within the extension.
contains function signature/stub:
func contains(target: A, compare:((A, A) -> Bool))
-> Bool {
return true
}// contains

Swift compiler cannot distinguish two initializers

Basically, I have a class called UserData and multiple initializers for it. In particular, I have a copy initializer which looks like:
init (_ origin: UserData){
// copy over everything
}
And another initializer which is used when I need to read the data from a file:
convenience init (Read _: Bool) {
// read stuff and call another initializer
}
Then I always got a compiler error saying cannot convert Bool to UserData whenever I tried to do var something = UserData(true).
I tried adding label, but compiler said extroneous label since there is only one parameter. I could make a workaround by adding another random parameter to the second initializer. But why is the compiler always trying to interpret the call to something does not match the type while there is another that matches the type?
Swift has no problem distinguishing two initializers with one parameter. The error is because of how the second one is defined. It should be:
convenience init (_ read: Bool) {
// read stuff and call another initializer
}

Swift 3 first parameter names

In Swift 2, it appears that the first parameter name is not always required when calling a function. Now in Swift 3, the first parameter name is required when calling the function. For example:
func frobnicate(runcible: String) {
print("Frobnicate: \(runcible)")
}
Swift 2.2 allowed the function to be called by simply typing:
Frobnicate("Station")
Swift 3 seems to be requiring that we use the first parameter names of methods such as:
Frobnicate(runcible:"Station")
Is this the case with Swift 3 for all functions and methods or just certain situations?
Yes, this is right. Swift is fixing a language inconsistency this way (this was always required for initializers).
If you don't want to use the external parameter name, just remove it explicitly:
func frobnicate(_ runcible: String) {
print("Frobnicate: \(runcible)")
}
You can read the full rationale in Swift Evolution 0046
You can read The Swift Programming Language (Swift 3) in i-Book. Also you can check this out in WWDC 2016: What's New in Swift
In Swift 3, by default, functions use their parameter names as labels for their arguments. Write a custom argument label before the parameter name, or write _ to use no argument label.
fun greet(_ person: String, on day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")
or
// This also works with Swift 2
fun addThreeNumber(_ first: Int, _ second: Int, _ third: Int) {
print(first+second+third)
}
addThreeNumber(1, 2, 3)
Exactly. In Swift 3.0, it's mandatory to write parameter names for all the parameters (including the first parameter). Parameter name is the one which is used inside the function implementation body.
func frobnicate(runcible: String) {
print("Frobnicate: \(runcible)")
}
By default, the external parameter label is same as the parameter name, if you don't specify any parameter label explicitly. Parameter label is the one which is used to pass the arguments while calling the function. If you need, for better clarity purpose, you can also specify external parameter labels explicitly. Example below-
func frobnicate(runcibleExternalLabel runcible: String) {
print("Frobnicate: \(runcible)")
}
If you want to skip the external parameter label while calling the function, just prepend a "_" before the parameter name.
func frobnicate(_ runcible: String) {
print("Frobnicate: \(runcible)")
}
Yes Swift 3 requires you to send First Parameter Label.
Please refer Swift 3 changes
The reason you want labels for parameters is so other code can supply parameters in any order.
Without labels, when you call the function the parameters are anonymous and you cannot be certain if you have supplied them in the wrong order.
Place labels in front of the parameters and code tools can do a much better job at catching errors us humans put in.
The underscore is just a way to cope with the transition from legacy code; method names including an Implicit first parameter. You should change any underscores that migration adds to your code to an explicit parameter label. You know it makes sense.

AudioToolbox, C-function pointers, and Swift

I'm working, tentatively, with the AudioToolbox API using Swift 2.0 and Xcode 7b6. The API uses a lot of c-language constructs, including function pointers. This is my first time working with commands like withUnsafeMutablePointer and unsafeBitCast. I am looking for a reality check to make sure that I am not way off base in what I am doing.
For example, to open a file stream, you use the following function:
func AudioFileStreamOpen(
_ inClientData: UnsafeMutablePointer<Void>
, _ inPropertyListenerProc: AudioFileStream_PropertyListenerProc
, _ inPacketsProc: AudioFileStream_PacketsProc
, _ inFileTypeHint: AudioFileTypeID
, _ outAudioFileStream: UnsafeMutablePointer<AudioFileStreamID>) -> OSStatus
Just the type signature of the function makes me start to sweat.
At any rate, the inClientData parameter needs to be an UnsafeMutablePointer<Void>, and the pointer will point to an instance of the same class I am working in. In other words, it needs to be a pointer to self. My approach is to call the function using withUnsafeMutablePointer like this:
var proxy = self
let status = withUnsafeMutablePointer(&proxy) {
AudioFileStreamOpen($0, AudioFileStreamPropertyListener
, AudioFileStreamPacketsListener, 0, &audioFileStreamID)
}
My first question is whether or not I'm using withUnsafeMutablePointer correctly here. I wasn't sure how to get a pointer to self - just writing &self doesn't work, because self is immutable. So I declared proxy as a variable and passed a reference to that, instead. I don't know if this will work or not, but it was the best idea I came up with.
Next, AudioFileStreamPropertyListener and AudioFileStreamPacketsListener are C callback functions. They each get passed the pointer to self that I created using withUnsafeMutablePointer in AudioFileStreamOpen. The pointer is passed in as an UnsafeMutablePointer<Void>, and I need to cast it back to the type of my class (AudioFileStream). To do that, I believe I need to use unsafeBitCast. For example, here is AudioFileStreamPropertyListener:
let AudioFileStreamPropertyListener: AudioFileStream_PropertyListenerProc
= { inClientData, inAudioFileStreamID, inPropertyID, ioFlags in
let audioFileStream = unsafeBitCast(inClientData, AudioFileStream.self)
audioFileStream.didChangeProperty(inPropertyID, flags: ioFlags)
}
That compiles fine, but again I'm not sure if I'm using unsafeBitCast correctly, or if that is even the correct function to be using in this kind of situation. So, is unsafeBitCast the correct way to take an UnsafeMutablePointer<Void> and cast it to a type that you can actually use inside of a C function pointer?
It's interesting that the inClientData "context" param is bridged as UnsafeMutablePointer, since I doubt the AudioToolbox APIs will modify your data. It seems it would be more appropriate if they'd used COpaquePointer. Might want to file a bug.
I think your use of withUnsafeMutablePointer is wrong. The pointer ($0) will be the address of the variable proxy, not the address of your instance. (You could say $0.memory = [a new instance] to change it out for a different instance, for example. This is a bit confusing because its type is UnsafeMutablePointer<MyClass> — and in Swift, the class type is itself a pointer/reference type.)
I was going to recommend you use Unmanaged / COpaquePointer, but I tested it, and realized this does exactly the same thing as unsafeAddressOf(self)!
These are equivalent:
let data = UnsafeMutablePointer<Void>(Unmanaged.passUnretained(self).toOpaque())
let data = unsafeAddressOf(self)
And these are equivalent:
let obj = Unmanaged<MyClass>.fromOpaque(COpaquePointer(data)).takeUnretainedValue()
let obj = unsafeBitCast(data, MyClass.self)
While the Unmanaged approach makes logical sense, I think you can see why it might be prefereable to use unsafeAddressOf/unsafeBitCast :-)
Or, you might consider an extension on Unmanaged for your own convenience:
extension Unmanaged
{
func toVoidPointer() -> UnsafeMutablePointer<Void> {
return UnsafeMutablePointer<Void>(toOpaque())
}
static func fromVoidPointer(value: UnsafeMutablePointer<Void>) -> Unmanaged<Instance> {
return fromOpaque(COpaquePointer(value))
}
}
Then you can use:
let data = Unmanaged.passUnretained(self).toVoidPointer()
let obj = Unmanaged<MyClass>.fromVoidPointer(data).takeUnretainedValue()
Of course, you will need to ensure that your object is being retained for the duration that you expect it to be valid in callbacks. You could use passRetained, but I would recommend having your top-level controller hold onto it.
See some related discussion at https://forums.developer.apple.com/thread/5134#15725.

Getting a function's return type in Swift

I realize that reflection isn't fully supported (yet) in Swift, but reflection run time methods are (apparently) supported. I'm trying to get the return type of a function at run time. Here's my example
let s:Selector = "willAnimateRotation"
var m:Method = class_getInstanceMethod(object_getClass(self), s)
let returnType = method_copyReturnType(m)
println("method: \(m); returnType: \(returnType)")
free(returnType)
Here's an example of my willAnimateRotation method, currently returning String:
private func willAnimateRotation() -> String {
return "abc"
}
The output of this does not seem to vary depending on the return type of the selector. E.g., with String or Void return type for the selector, I get the following output:
method: 0x0000000000000000; returnType: 0x0000000000000000
Thoughts?
ALSO: I'm actually not really trying to do this in Swift. I'm bridging an Objective-C class to Swift, and am getting the same results there, when the Objective-C code attempts to determine the return type of a Swift selector. That is, my end-goal in this case happens to be to use Objective-C to get the return type of a Swift selector.
OK. I've figured this out. The problem comes with my use of the "private" keyword. If you drop that and just use:
func willAnimateRotation() -> String {
return "abc"
}
The sample code above works fine.
In Swift you indicate the function’s return type with the return arrow -> (a hyphen followed by a right angle bracket), which is followed by the name of the type to return.