I am looking to get the name of function in swift.
I basically want something like
__FUNCTION__
but from a different function e.g.
func do () {
code etc
}
func doStuff () {
var funcName = do().name
}
the above would be perfect.
Any ideas?
#function might be what you want.
print(#function)
class Log {
func info(_ info: String, funcName: String = #function) {}
}
In Swift 3 the right keyword is #function. You could pass a pointer to a String object which is used to store the function name. For example:
func myFunction(param1:Any, param2:Any, functionName: UnsafeMutablePointer<String>?) -> Any {
if functionName != nil {
functionName.pointee = #function
}
...
}
Usage:
var name:String
// You can always pass nil if you are not interested in retrieving the
// function name
let result = myFunction(1, 2, functionName: &name)
print(name)
Not the cleanest, but it works.
func dost () -> (name: String,String) {
return (__FUNCTION__,"")
}
func doStuff () {
var funcName = dost().name
}
You could aways just return the function name without the tuple.
Related
I tried to create a custom iterator which returns wrapper abcContainer over raw data class abc
// raw data class
class abc {
var name : String = "";
init( _ value : String) {
name = value;
}
}
// with container, only "name" is to be visible
class abcContainer {
private var _abc : abc;
init( _ obj : abc) {
_abc = obj;
}
// + extra methods here
func getName() -> String {
return _abc.name
}
}
The point would be that the dictionary would return instances of abcContainer instead of just the plain raw abc class.
I wanted to use the sequence protocol to make the conversion automatic, but I was not able to transform the [String:abc] into [String:abcContainer] automatically like this:
// the iterator is implemented just iterating the inner basic dict
// but wrapping the result value as abcContainer
class abcIterator : Sequence, IteratorProtocol {
private var __source : [String:abc]?;
var index = 0
var myIterator : DictionaryIterator<String, abc>;
init(_ ctxArray: [String:abc]) {
self.__source = ctxArray
index = 0;
myIterator = (__source?.makeIterator())!
}
func next() -> abcContainer? {
let nextItem = myIterator.next();
if(nextItem != nil) {
return abcContainer((nextItem?.value)!);
}
return nil;
}
}
// this was supposed to be the wrapper over the collection
class abcCollection : Sequence {
private var __source : [String:abc]?;
init(_ list: [String:abc]) {
self.__source = list
}
func makeIterator() -> abcIterator {
return abcIterator(self.__source!);
}
}
I'm probably missing something very basic here. When I try to use the collection like this:
var dict : [String:abc] = [String:abc]();
dict["abba"] = abc("John Smith");
for (key,value) in abcCollection(dict) {
print(key, value.getName());
}
I get error: Expression type "abcCollection" is ambiguous without more context
Does anyone have idea how to make it work? What is missing? I have a feeling that this answer has the information I need...
Swift 2 to 3 Migration for Swift Sequence Protocol
The problem in your original code is that abcCollection(dict)
returned a sequence of abcContainer objects, and those cannot
be assigned to a (key, value) tuple.
You can achieve your goal with
class abcCollection : Sequence {
private var __source : [String:abc]
init(_ list: [String:abc]) {
self.__source = list
}
public func makeIterator() -> AnyIterator<(AnyObject,abcContainer)> {
let mapped = self.__source.lazy.map {
($0.key as AnyObject, abcContainer($0.value))
}
return AnyIterator(mapped.makeIterator())
}
}
Making __source non-optional makes all the (optional) unwrappings
redundant, and lazy.map { ... } returns a lazily evaluated
sequence of key/value pairs which is then type-erased.
Ok, perhaps the answer was abcIterator was not necessary, you could have defined the iterator directly just like done in the linked answer like this:
class abcCollection : Sequence {
private var __source : [String:abc]?;
init(_ list: [String:abc]) {
self.__source = list
}
public func makeIterator() -> AnyIterator<(AnyObject,abcContainer)> {
var it = self.__source?.makeIterator();
return AnyIterator {
let n = it?.next();
if n == nil { return nil }
return (n?.key as AnyObject, abcContainer((n?.value)!))
}
}
}
After that, the custom collection returned wrapped objects correctly.
I want to be able to chain functions as seen below and choose between them. In this contrived example, I hardcoded "function_b", but in the ideal world, I'd like it to be random or even controlled by a server. I know that I can create the same effect in different ways, but I like the way this code reads, so I want to do it like this.
ExecutionManager("function_b").add("function_a") {
//some code
}.add("function_b") {
//more code
}.add("function_c") {
//other code
}
Your snipped of code does not make much sense to me. E.g. what should mean this part?
ExecutionManager("function_b")
You are just passing a string to the initializer of ExecutionManager. What should be the meaning of that?
Let's try
However if you want to be able to add a list of functions with this type
() -> ()
and then execute them (all of them or just some of them) you could define your ExecutionManager like this
class ExecutionManager {
typealias FunctionType = () -> ()
private var functions = [(String, FunctionType)]()
func add(funcName: String, function: FunctionType) -> ExecutionManager {
functions.append(funcName, function)
return self
}
func runAll() {
functions.forEach { $0.1() }
}
}
Now you can
ExecutionManager().add("sayHello") {
print("hello")
}.add("sum 1 + 1") {
let sum = 1 + 1
print(sum)
}.add("say goodbye") {
print("goodbye")
}.runAll()
The result is
hello
2
goodbye
Random
To run a only a function based on some logic look at this code. here I am generating a random index and the executing only one function
Extension
extension ExecutionManager {
func runRand() {
guard functions.isEmpty == false else { return }
let rand = Int(arc4random_uniform(UInt32(functions.count)))
functions[rand].1()
}
}
Example
ExecutionManager().add("sayHello") {
print("hello")
}.add("sum 1 + 1") {
let sum = 1 + 1
print(sum)
}.add("say goodbye") {
print("goodbye")
}.runRand()
Output
2
Update
With this version we remove the invocation of runRand at the end
#HyperZ Thanks for the hint.
import Foundation
class ExecutionManager {
typealias FunctionType = () -> ()
private var functions = [(String, FunctionType)]()
func add(funcName: String, last:Bool=false, function: FunctionType) -> ExecutionManager {
functions.append(funcName, function)
if last {
runRand()
}
return self
}
func runRand() {
guard functions.isEmpty == false else { return }
let rand = Int(arc4random_uniform(UInt32(functions.count)))
functions[rand].1()
}
}
Code
ExecutionManager().add("sayHello") {
print("hello")
}.add("sum 1 + 1") {
let sum = 1 + 1
print(sum)
}.add("say goodbye", last:true) {
print("goodbye")
}
Output
hello
I define the below list swift class, and try to call the sfAuthenticateUser from the viewcontroller. But the Xcode intellisense list the wrong parameter type other than the type i defined.
ERROR : Cannot convert value of type 'String' to expected argument type 'APISFAuthentication'
Xcode Version 7.1 (7B91b)
//View Controller method call as below
#IBAction func ActionNext(sender: AnyObject) {
let sss = APISFAuthentication.sfAuthenticateUser(<#T##APISFAuthentication#>)
}
// Class Definition as below
class APISFAuthentication {
init(x: Float, y: Float) {
}
func sfAuthenticateUser(userEmail: String) -> Bool {
let manager = AFHTTPRequestOperationManager()
let postData = ["grant_type":"password","client_id":APISessionInfo.SF_CLIENT_ID,"client_secret":APISessionInfo.SF_CLIENT_SECRET,"username":APISessionInfo.SF_GUEST_USER,"password":APISessionInfo.SF_GUEST_USER_PASSWORD]
manager.POST(APISessionInfo.SF_APP_URL,
parameters: postData,
success: { (operation, responseObject) in
print("JSON: " + responseObject.description)
},
failure: { (operation, error) in
print("Error: " + error.localizedDescription)
})
return true;
}
}
Please refer to the screen shot
The problem is that you try to call an instance function without having an actual instance at hand.
You either have to create an instance and call the method on that instance:
let instance = APISFAuthentication(...)
instance. sfAuthenticateUser(...)
or define the function as a class function:
class func sfAuthenticateUser(userEmail: String) -> Bool {
...
}
Explanation:
What Xcode offers you and what confuses you is the class offers the capability to get a reference to some of its instance functions by passing an instance to it:
class ABC {
func bla() -> String {
return ""
}
}
let instance = ABC()
let k = ABC.bla(instance) // k is of type () -> String
k now is the function bla. You can now call k via k() etc.
so i've created function and it does something, but i want it to do something else if the parameter type is different, for example:
func (parameter: unknownType){
if(typeof parameter == Int){
//do this
}else if(typeof parameter == String){
//do that
}
}
i've done this in javascript or other programming languages, but i don't know how to do this in swift
i've created function which takes 1 argument UITextField and centers it using constraints
now i want to center my button, but since button is not UITextField type it does not work, so is there a way i can tell function to do the same on UIButton??
Use Overload:
class Example
{
func method(a : String) -> NSString {
return a;
}
func method(a : UInt) -> NSString {
return "{\(a)}"
}
}
Example().method("Foo") // "Foo"
Example().method(123) // "{123}"
The equivalent of the Javascript code would be:
func doSomething(parameter: Any?) {
if let intValue = parameter as? Int {
// do something with the int
} else if let stringValue = parameter as? String {
// do something with the string
}
}
But be warned, this approach makes you loose the type safety which is one of most useful feature of Swift.
A better approach would be to declare a protocol that is implemented by all types that you want to allow to be passed to doSomething:
protocol MyProtocol {
func doSomething()
}
extension Int: MyProtocol {
func doSomething() {
print("I am an int")
}
}
extension String: MyProtocol {
func doSomething() {
print("I am a string")
}
}
func doSomething(parameter: MyProtocol) {
parameter.doSomething()
}
doSomething(1) // will print "I am an int"
doSomething("a") // will print "I am a string"
doSomething(14.0) // compiler error as Double does not conform to MyProtocol
It can
Sample code:
func temFunc(obj:AnyObject){
if let intValue = obj as? Int{
print(intValue)
}else if let str = obj as? String{
print(str)
}
}
You can make use of Any and downcasting:
func foo(bar: Any){
switch(bar) {
case let a as String:
/* do something with String instance 'a' */
print("The bar is a String, bar = " + a)
case let a as Int:
/* do something with Int instance 'a' */
print("The bar is an Int, bar = \(a)")
case _ : print("The bar is neither an Int nor a String, bar = \(bar)")
}
}
/* Example */
var myString = "Hello"
var myInt = 1
var myDouble = 1.5
foo(myString) // The bar is a String, bar = Hello
foo(myInt) // The bar is an Int, bar = 1
foo(myDouble) // The bar is neither an Int nor a String, bar = 1.5
Check this solution:
https://stackoverflow.com/a/25528882/256738
You can pass an object AnyObject and check the class in order to know what kind of object it is.
UPDATE
Good point #Vojtech Vrbka
Here an example:
let x : AnyObject = "abc"
switch x {
case is String: println("I'm a string")
case is Array: println("I'm an Array")
// Other cases
default: println("Unknown")
}
am studying with a tutorial for a game app and there is a line of code that i didn't understood it looks like it's of type tuple
this is my code:
var algorithmResult = algorithm(value: value)
func rowCheck(#value: Int) -> (location: String, pattern: String)? {
var acceptableFinds = ["011", "101", "110"]
var findFunc = [checkTop, checkBottom, checkMiddleAcross, checkRight, checkMiddleDown, checkLeft, checkDiagLeftRight, checkDiagRightLeft]
for algorithm in findFunc {
var algorithmResult = algorithm(value: value)
if (find(acceptableFinds, algorithmResult.pattern) != nil) {
return algorithmResult
}
}
return nil
}
In:
var algorithmResult = algorithm(value: value)
algorithm represents one element in the findFunc array (as defined in for algorithm in findFunc).
From the names, I'm guessing each of those elements is a function. Those functions are passed value and the result of the function is stored in algorithmResult.
Here's a similar example. Create two functions:
func add(operand : Int) -> Int {
return operand + operand
}
func multiply(operand : Int) -> Int {
return operand * operand
}
Store them in an array:
let funcs = [add, multiply]
Call them in a loop:
for function in funcs {
let x = function(5)
print(x)
}
This prints:
10
25
It applies each function from findFunc array to the value, which was passed to rowCheck function.