passing a function along with an inout parameter - swift

the constructor is receiving two parameters.
a) a function whose type is a function receiving an inout params (so it can change the params)
b) passing your params object, expecting the function passed will be able to modify the object
then trigger the apply method, so your passed function can change the passed params.
If there's a solution with passing params in a closure, that'd work too.
class Test {
var params: Any?
var myFunc: (inout params: Any?) -> () = { (inout params: Any?) in return } //default value
//constructor receving a function and a address to inout params object
init(myFunc: (inout params: Any?) -> (), inout params: Any?) {
self.myFunc = myFunc
self.params = params
}
//call the passed function (extern) and pass the address of given params
func apply() {
self.myFunc(params: &self.params)
}
}
func extern(inout params: Any?) {
var a = params as [String: Int]
a["factor"] = 11
}
var p: Any = ["factor": 10]
var test = Test(myFunc: extern, params: &p)
test.apply() //p["factor"] should be 11 now here
p["factor"] as [String: Int]
My second attempt using closures
//Utility
class Test {
var closure: () -> Any
var myFunc: (message: String, closure: () -> Any) -> () = { (message: String, closure: () -> Any) in return }
init(myFunc: (message: String, closure: () -> Any) -> (), closure: () -> Any) {
self.myFunc = myFunc
self.closure = closure
}
func apply(message: String) {
self.myFunc(message: message, closure: self.closure)
}
}
//users of the utility
func extern(message: String, closure: () -> Any) {
println(message)
var name = closure() as [String: String]
name["name"] = "Doe"
}
var name: Any = ["name": "John"]
var test = Test(myFunc: extern, closure: {name})
test.apply("hello ")
name //it's still John here
3rd attempt using AnyObject and closures and of course it works but still need your opinion guys for a best strategy.
//Utility
class Test {
var closure: () -> AnyObject
var myFunc: (message: String, closure: () -> AnyObject) -> () = { (message: String, closure: () -> AnyObject) in return }
init(myFunc: (message: String, closure: () -> AnyObject) -> (), closure: () -> AnyObject) {
self.myFunc = myFunc
self.closure = closure
}
func apply(message: String) {
self.myFunc(message: message, closure: self.closure)
}
}
//users of the utility
func extern(message: String, closure: () -> AnyObject) {
println(message)
var name: Name = closure() as Name
name.name = "Doe"
}
class Name {
var name = "John"
}
var name = Name()
var test = Test(myFunc: extern, closure: {name})
test.apply("hello ")
name //it's changed here

It seems like you're trying to reinvent closures here. One point of closures is that they can capture references to the values around them. This should do what you're describing above, and lets you keep using proper types for your variables, rather than falling back on Any:
class Test {
var myFunc: () -> Void = { }
init(myFunc: () -> Void) {
self.myFunc = myFunc
}
func apply() {
self.myFunc()
}
}
func extern(inout dict: [String: Int]) {
dict["factor"] = 11
}
var p = ["factor": 10]
let test = Test {
extern(&p)
}
test.apply() // p["factor"] is now 11 here
println(p)
// ["factor": 11]

Related

In Swift is it possible to write a function that receives another function and its parameters to later execute it when appropriate?

Let’s say I have this function
func executeFunction<Value>(_ function: (Any...) -> Value, params: Any...) -> Value {
//some pre processing before the function is executed
return function(params)
}
And I want it to be able to receive any type of function with any number of parameters with just the condition of it to return something.
Like, ie:
func greetUser(_ user: String) -> String {
return "Hello \(user)"
}
executeFunction(greetUser, params: "John Doe")
Is there a way to achieve this?
Nevermind! I found how.
Turns out I needed to specify the arguments of the function and the type of the argument params as T.
func executeFunction<Value, T>(_ function: (T) -> Value, params: T = () as! T) -> Value {
//some pre processing before the function is executed
return function(params)
}
This way I was able to invoke the executeFunction with three different functions each having different number of parameters.
func greetUser(_ user: String) -> String {
return "Hello \(user)"
}
func add(_ num1: Int, to num2: Int) -> Int {
return num1 + num2
}
let string = executeFunction(greetUser, params: "John Doe") // -> "Hello John Doe"
let result = executeFunction(add, params: (1,2)) // -> 3
let hello = executeFunction(sayHello) // -> "Hello"

Understand swift Dictionary syntax

I work with legacy code and i find following code:
let actions = [PrinterReportType.z: {
printer.printZReport($0)
DeviceFabric.lifehubTerminal().reconciliation()
}, .x: printer.printXReport, .openSession: printer.openSession}]
"Actions" is declared like this:
let actions: [PrinterReportsModel.PrinterReportType : ((String?) -> ()) -> ()]
Key is enum value, but i can't figure out what is value here.
I have new enum type of PrinterReportsModel.PrinterReportType, and i simply want to add new value to that dictionary. I suppose this is some kind of function. So, i want to declare that function, add it here, but i can't figure out how. And i can't figure out wha type is - ((String?) -> ()) -> ()
String is a collection of characters.
String? means the same as Optional<String>, so it is either Optional.none or Optional.some(String).
(String?) -> () is a function that takes a String? and returns nothing (() also called Void, the zero-element tuple). Let's call this as a String?-consumer: it takes a String? and does something with it. Maybe it just throws the String? away. Maybe it prints it. Maybe it stores the String? in a variable or a database or sends it over the network.
You could define a String?-consumer closure like this:
let action: (String?) -> () = { (_ s: String?) -> () in
print(s ?? "(none)")
}
(I'm fully specifying the types above, but you could omit some of the types and let the compiler infer them.)
You could define a String?-consumer function like this:
func test(_ s: String?) -> () { print(s ?? "(none)" }
And pass it around like this:
let action: (String?) -> () = test
You could define a String?-consumer method in a class (or struct) like this:
class MyObject {
func test(_ s: String?) -> () { print(s ?? "(none)") }
}
And pass it around like this:
let myObject = MyObject()
let action: (String?) -> () = myObject.test
((String?) -> ()) -> () is a function that takes a String?-consumer and returns nothing. You can think of this as a String?-consumer-consumer. Maybe it throws the String?-consumer away. Maybe it stores the String?-consumer in a variable for later. Maybe it calls the String?-consumer once, or ten times, or once for each element in some array of strings. Maybe it schedules a call to the String?-consumer every second until the program exits.
You could define a String?-consumer-consumer closure like this:
let action: ((String?) -> ()) -> () = { (_ sc: (String?) -> ()) -> () in
sc("hello")
sc(nil)
sc("world")
}
You could call the closure like this:
action({ (_ s: String?) -> () in print(s ?? "(none)")}
Or like this:
let printString: (String?) -> () = { print($0) }
action(printString)
You could define a String?-consumer-consumer function like this:
func test(_ sc: (String?) -> ()) -> () {
sc("hello")
sc(nil)
sc("world")
}
And pass it around like this:
let action: ((String?) -> ()) -> () = test
You could define a String?-consumer-consumer method in a class (or struct) like this:
class MyObject {
func test(_ sc: (String?) -> ()) -> () {
sc("hello")
sc(nil)
sc("world")
}
}
And pass it around like this:
let myObject = MyObject()
let action: ((String?) -> ()) -> () = myObject.test

Swift: Issue with closure arguments

Here is a function:
func foo(completion: (jsonData: String) -> ()) {
}
In Swift 3, you can't have argument labels. Therefore, this is the code:
func foo(completion: (String) -> ()) {
}
The issue with this, is that when I call the function it looks like this:
foo(completion: { _ in
})
So, if I want to see the value of jsonData, I can't because it's an underscore. How would I solve this issue?
It's working:
func foo(completion: (String) -> ()) {
completion("Hi")
}
foo { jsonData in
print(jsonData) // Output: Hi
}

Function with optional completion block in Swift [duplicate]

This question already has answers here:
Can swift closures be set to a default value when used as a parameter in a function?
(4 answers)
Closed 6 years ago.
When I create a function, I can make a parameter optional by giving it a default value, like this:
func foo(bar: String = "foobar") {}
I want to do the same (make it optional) with a completion block. I have tried the following:
func foo(completionBlock: (foo: String) -> () = () -> ())
func foo(completionBlock: (foo: String) -> () = (foo: String) -> ())
func foo(completionBlock: (foo: String) -> () = ((foo: String) -> ()))
func foo(completionBlock: (foo: String) -> () = ((foo: String) in))
func foo(completionBlock: (foo: String) -> () = {(foo: String) in})
How can I do this?
EDIT: This is/was a duplicate question, sorry for that. However, I couldn't find the solution in the original question. So nathan's answer is the best one
If you want to default to nil:
func foo(completionBlock: ((String) -> ())? = nil) {
}
If your default completion block is very simple, you can put it right in the function's definition:
// A default completion block that is simple enough to fit on one line
func foo(completionBlock: (String) -> () = { result in print(result) }) {
// ...
}
// A default completion block that does nothing
func foo(completionBlock: (String) -> () = {} ) {
// ...
}
If your default completion block is more complex, you can define it as a separate function:
func defaultCompletion(result: String) {
// ...
}
func foo(completionBlock: ((String) -> ()) = defaultCompletion) {
}
In Swift 3:
func foo(completionBlock: (String) -> () = { _ in }) {}

Array of functions in Swift

How can I store an array of functions to callback later in an array like in JavaScript? Any and AnyObject type cannot hold functions with different types of method signatures.
You can use an enum to put various functions into the Array and then extract the functions with a switch.
enum MyFuncs {
case Arity0 ( Void -> Void )
case Arity2 ( (Int, String) -> Void)
}
func someFunc(n:Int, S:String) { }
func boringFunc() {}
var funcs = Array<MyFuncs>()
funcs.append(MyFuncs.Arity0(boringFunc))
funcs.append( MyFuncs.Arity2(someFunc))
for f in funcs {
switch f {
case let .Arity0(f):
f() // call the function with no arguments
case let .Arity2(f):
f(2,"fred") // call the function with two args
}
}
Note: this answer is for Swift versions 1.0 and lower.
Functions that have different parameters and return types are of a different type so they can't be stored in an array together. They also don't conform to the Any or AnyObject protocols.
If you have functions with the same parameters though you can work around that. Even though the functions below return a tuple of Double and an Int, they can both be defined as () -> Any function types.
func func1 () -> Int {
return 1
}
func func2 () -> (Double, Double){
return (2, 3)
}
var a: () -> Int = func1
var b: () -> (Double, Double) = func2
var arr: Array< () -> Any> = [a, b]
Below is an example with both an array and a dictionary. Tested and working in Xcode 6.1 (6A1046a). Note that functions from dictionaries must first be unwrapped.
This technique does however fall apart when the functions have different parameter or return types, for the reasons explained by connor in his answer.
class MyViewController: UIViewController
{
let arrayOfFunctions = [function1, function2]
let dictionaryOfFunctions = [
"function1": function1,
"function2": function2
]
func function1() {
NSLog("function1")
}
func function2() {
NSLog("function2")
}
override func viewDidLoad()
{
let fn1 = arrayOfFunctions[0]
fn1(self)()
let fn2 = dictionaryOfFunctions["function2"]
fn2!(self)()
}
}
As of Swift 1.1, all function types conform to Any, so you can hold functions in an Any array.
func foo (str: String) -> Int {
return 1
}
func bar () -> (Double, Double){
return (2, 3)
}
var a: Any = foo
var b: Any = bar
var arr: Any = [a, b]
A simpler approach to call stored function in array on demand , to use parameters a simple workaround is to make dict args and use it inside the function.
var args = [ "a" : 1, "b" : 2 ]
var requestQueue : [() -> Void] = []
func a() -> Void {
let param = args["a"]
print(param!)
}
func b() -> Void {
let param = args["b"]
print(param!)
}
requestQueue.append(a)
requestQueue.append(b)
for item in requestQueue {
item() //calling the functions
}