Swift: how to optionally pass function as parameter and invoke the function? - ios

How can you optionally pass in a function to another function? Concretely, assume functionA accepts as a parameter functionB. If functionB is not nil, how can you execute functionB inside of functionA?

Hard to see what's hard about this, so maybe this isn't what you mean, as it seems so trivially obvious; but anyway, here goes:
func optionalFunctionExpecter(f:(()->())?) {
f?()
}
Here's how to call it with an actual function:
func g() {
println("okay")
}
optionalFunctionExpecter(g)
Or, calling it with an actual anonymous function:
optionalFunctionExpecter { println("okay2") }
Here's how to call it with nil:
optionalFunctionExpecter(nil)
Observe that in my implementation of optionalFunctionExpecter, when called with nil, nothing will happen: we won't call f, we won't crash, we won't do anything. If you need to know that nil was passed, you can readily find out: just ask, in optionalFunctionExpecter, whether f == nil and proceed on that basis as desired. For more flexibility, we could rewrite like this:
func optionalFunctionExpecter(f:(()->())?) {
if let f = f {
f()
} else {
// ... nil was passed, respond to that fact ...
}
}

Related

Swift: How to deal with method overloads where only the return type differs and the result is discardable?

this is my first question and I hope you guys can help me out.
Lets assume I've written a Framework in Swift that does stuff purely with native Swift Types. This is our interface:
class Foo {
#discardableResult
public func perform(query: String) -> [String: Any]? {
return [:]
}
}
Note that our result is discardable.
I would now like to support other Libraries optionally. I know we have Codable and stuff but lets assume that I want to support SwiftyJSON optionally by creating an extension that only compiles when SwiftyJSON can be imported.
#if canImport(SwiftyJSON)
import SwiftyJSON
extension Foo {
#discardableResult
func perform(query: String) -> JSON? {
// Call internal func => cast JSON => return JSON
return JSON()
}
}
#endif
Without SwiftyJSON (can not import) this compiles:
let bar = Foo().perform(query: "")
With SwiftyJSON it does not because its ambiguous.
Return type has to be explicitly defined like:
let baz: [String: Any]? = Foo().perform(query: "")
// or
let bar: JSON? = Foo().perform(query: "")
For calls where I want the result thats fine.
BUT: Since we have a discardableResult calls like
Foo().perform(query: "")
will always be ambiguous.
The following calls work but are not very nice imho.
Foo().perform(query: "") as JSON?
Foo().perform(query: "") as [String: Any]?
What is the best way to deal with this problem? Should the method just not be overloaded and have a different name instead? Or am I overlooking something that makes the calls non ambiguous in a nice way?
Edit:
A comment suggested to remove discardableResult. I really do not wanna do that since that would lead to a lot of calls that look like this:
_ = Foo().perform(query: "")
The more I think about the problem it occurs to me that there might just not be a good solution for this..
Actually, removing #discardableResult wouldn't work, and _ = Foo().perform(query: "") wouldn't compile, it would still have the same ambiguity: it's not that the compiler is being nitpicky, but it has literally no way of knowing which of your two functions to call!
It might be interesting to think about what behavior you'd expect from this line, and why.
You seem to want to have a function based on an existing function which:
Returns a different type;
Has the same name and parameters;
Has a discardable result.
Unfortunately, it looks like it's a classic "pick any two" type of scenario…
Well, let's do just that! Let's see what happens if we stop insisting on any one of the three conditions.
Let me use a simpler example:
#discardableResult func doSomething() -> String {
return "a"
}
#discardableResult func doSomething() -> Int {
return 1
}
doSomething() // won't compile
let x:String
x = doSomething() // "a"
We have a function overloaded with two return types (String and Int), and we see that we cannot discard its result as it would result in unresolvable ambiguity.
1. Single return type: use an enum with a payload
Let's eliminate the first condition, and try using a single return type. This is possible:
enum ReturnType {
case text(_ payload:String)
case number(_ payload:Int)
}
#discardableResult func doSomething() -> ReturnType {
if ... // some condition
{
return .text("a")
} else {
return .number(1)
}
}
doSomething() // works
let x = doSomething() // ReturnType.text("a") or ReturnType.number(1)
Here we cannot (easily) extend the functionality via extensions; rather, we'd need to touch the enum and function code with all the possible options every time we want to add a new return type. (Of course advanced APIs can also be created that help third parties easily write extensions… If it's worth the effort.)
We would also need a way to determine which return type to choose: it can be a function parameter, or a value stored elsewhere, etc. Here's an example with a parameter:
#discardableResult func doSomething(useText:Bool = false) -> ReturnType {
if useText {
return .text("a")
} else {
return .number(1)
}
}
doSomething() // works
doSomething(useText:true) // works
let x = doSomething() // ReturnType.number(1)
let x2 = doSomething(useText:false) // ReturnType.number(1)
let x3 = doSomething(useText:true) // ReturnType.text("a")
Note: Here, we lose the convenience of having the compiler infer the type from the call site; since the type is now an opaque wrapper, it's no longer the compiler's business to make sure that the wrapped type is correct. This may be a high cost for simply maintaining "result discardability," but then it may also allow us to abstract away some details, only unwrapping the "payload" when needed, which can have its own benefits.
2. Change the name or parameters of the function
This is quite easy:
#discardableResult func doSomething() -> String {
return "a"
}
#discardableResult func doSomethingElse() -> Int {
return 1
}
doSomething() // works
doSomethingElse() // works
let x = doSomething() // "a"
let y = doSomethingElse() // 1
We can also use this in an extension. All we lose is the shared name.
Changing the parameters is also possible but it would be pretty silly in this already-silly example:
#discardableResult func doSomething() -> String {
return "a"
}
#discardableResult func doSomething(thinkOfAnyNumber:Int) -> Int {
return 1
}
doSomething() // "a"
doSomething(thinkOfAnyNumber:42) // 1
Note: I'd obviously only do this if the additional parameters actually make sense.
Note 2: The parameter configuration is different between the two functions, not the parameter values like in the previous case.
3. Do not make the result discardable
Note that simply removing the #discardableResult attribute won't make it impossible to try to discard the result: you'll still be able to try the _ = assignment, or simply ignore the function result (and the compiler warning). Both will ultimately fail to compile, so it will be up to the user of the API to avoid doing either.
Hopefully, your function does some other things (side effects) than provide a return value: in that case, there may be little use in discarding the result of a function that does nothing but provide that result, and one may probably be better off not calling it in the first place.
If the side effects are identical between the two overloaded functions, you can factor them out into a single function:
func doTheActualWork() {
// ...
}
func doSomething() -> String {
doTheActualWork()
return "a"
}
func doSomething() -> Int {
doTheActualWork()
return 1
}
doSomething() // won't compile
doTheActualWork() // use this instead
let z:String = doSomething() // "a"
Note that this can also be done via extensions as long as they re-use existing functions and only overload them with different signatures and/or return types.
Now if the side effects (i.e. doTheActualWork() implementations) are also different in the two cases… Then I give up. But that can be handled as well.
Well, this is what I've been able to gather on this interesting problem. Now I may be dead wrong, and there may be something better out there… We'll find out soon enough.

Return a completable in RxSwift without using a create block

I have a Completable being returned from a simple function.
This is not an async call, so I just need to return a succcessful completion or error depending on a conditional (using Rx here so I can tie into other Rx usages):
func exampleFunc() -> Completable {
if successful {
return Completable.just() // What to do here???
} else {
return Completable.error(SomeErrorType.someError)
}
}
The error case works pretty easily, but am having a block on how to just return a successful completable (without needing to .create() it).
I was thinking I just need to use Completable's .just() or .never(), but just is requiring a parameter, and never doesn't seem to trigger the completion event.
.empty() is the operator I was looking for!
Turns out, I had mixed up the implementations of .never() and .empty() in my head!
.never() emits no items and does NOT terminate
.empty() emits no items but does terminates normally
So, the example code above works like this:
func exampleFunc() -> Completable {
if successful {
return Completable.empty()
} else {
return Completable.error(SomeErrorType.someError)
}
}
Here is the documentation on empty/throw/never operators.
I would be more inclined to do the following:
func example() throws {
// do something
if !successful {
throw SomeErrorType.someError
}
}
Then in order to tie it into other Rx code, I would just use map as in:
myObservable.map { try example() }
But then, mapping over a Completable doesn't work because map's closure only gets called on next events. :-(
I tend to avoid Completable for this very reason, it doesn't seem to play well with other observables. I prefer to use Observable<Void> and send an empty event before the completed...
Something like this:
let chain = Observable<Void>.just()
let foo = chain.map { try example() }
foo.subscribe { event in print(event) }

Factory in Swift using Generic Types

I'm trying to achieve the following in Swift - I want to pass in a type to a generic "get" function, and based on that type and the parameter, use different repositories to get back a class.
I recognize this is a bit strange to do in this way, but it would save me a lot of time and allow me to more properly refactor something later.
Here is the code but it compile errors on the Foo1Repository and Foo2Repository lines "Cannot convert the type of Foo1Repository to T".
Basically Foo1Repository should return a Foo1, which inherits from BaseEntity of course (and the same is true for Foo2)
class func Get<T: BaseEntity>(id: Int) -> T
{
if (T is Foo1) {
return Foo1Repository.Get(id)
}
else if (T == Foo2) {
return Foo2Repository.Get(id)
}
return T()
}
I was hoping to invoke this function by doing:
let foo = FactoryClass.Get<Foo1>(1)
I understand immediately you would ask "why not just call the appropriate repository, i.e."
let foo = Foo1Repository.Get(1)
and you're all set! No need for some weird factory pattern here.
Let's just say at the moment I need to try to do it above without a lot of refactoring of some code I inherited. I'll get back to planning a proper refactor later.
So I've tried a combination of things but still can't seem to get past the compiler errors. Is something like this possible, or do I need to just bite the bullet and go a different route? Thanks so much!
So I figured it out! I wanted to share the answer so others can see how to do this. Hopefully it will help.
func Get<T: BaseEntity>(id: Int) -> T
{
if (T.self == Foo1.self) {
return Foo1Repository.Get() as! T
}
else if (T.self == Foo2.self) {
return Foo2Repository.Get() as! T
}
...
return T()
}
So you can see, the whole as! T at the end was key. Also == instead of is for type checks.

Swift - Method chaining

I'd like to implement method chaining in my swift code, likely to Alamofire methods. For example, if I have to use my function like below
getListForID(12).Success {
// Success block
}. Failure {
// Failure block
}
How would I create the function getListForID?
To expand on the great points #dasblinkenlight and #Sulthan have made – here's a small example of how you could achieve your request function to take a success and failure closure, in the convenient syntax that you want.
First, you'll have to define a new class to represent the 'result handler'. This is what your success and failure functions will pass around, allowing you to add multiple trailing closures to make up your completion block logic. You'll want it to look something like this:
class ResultHandler {
typealias SuccessClosure = RequestHandler.Output->Void
typealias FailureClosure = Void->Void
// the success and failure callback arrays
private var _successes = [SuccessClosure]()
private var _failures = [FailureClosure]()
/// Invoke all the stored callbacks with a given callback result
func invokeCallbacks(result:RequestHandler.Result) {
switch result {
case .Success(let output): _successes.forEach{$0(output)}
case .Failure: _failures.forEach{$0()}
}
}
// remove all callbacks – could call this from within invokeCallbacks
// depending on the re-usability of the class
func removeAllCallbacks() {
_successes.removeAll()
_failures.removeAll()
}
/// appends a new success callback to the result handler's successes array
func success(closure:SuccessClosure) -> Self {
_successes.append(closure)
return self
}
/// appends a new failure callback to the result handler's failures array
func failure(closure:FailureClosure) -> Self {
_failures.append(closure)
return self
}
}
This will allow you to define multiple success or failure closures to be executed on completion. If you don't actually need the capacity for multiple closures, then you can simplify the class down by stripping out the arrays – and just keeping track of the last added success and failure completion blocks instead.
Now all you have to do is define a function that generates a new ResultHandler instance and then does a given asynchronous request, with the invokeCallbacks method being invoked upon completion:
func doRequest(input:Input) -> ResultHandler {
let resultHandler = ResultHandler()
doSomethingAsynchronous(resultHandler.invokeCallbacks)
return resultHandler
}
Now you can call it like this:
doRequest(input).success {result in
print("success, with:", result)
}.failure {
print("fail :(")
}
The only thing to note is your doSomethingAsynchronous function will have to dispatch its completion block back to the main thread, to ensure thread safety.
Full project (with added example on usage): https://github.com/hamishknight/Callback-Closure-Chaining
In order to understand what is going on, it would help to rewrite your code without the "convenience" syntax, which lets you omit parentheses when a closure is the last parameter of a function:
getListForID(12)
.Success( { /* Success block */ } )
.Failure( { /* Failure block */ } )
This makes the structure of the code behind this API more clear:
The return value of getListForID must be an object
The object must have two function called Success and Failure*
Both Success and Failure need to take a single parameter of closure type
Both Success and Failure need to return self
* The object could have only Success function, and return a different object with a single Failure function, but then you wouldn't be able to re-order the Success and Failure handlers, or drop Success handler altogether.

Is there a way to reference instance function when calling SequenceType.forEach?

Consider type Foo:
class Foo {
var isBaz: Bool {
return false
}
func bar() {
print("some boring print")
}
}
Now let's say I want to iterate through a collection of class instances and call some function on each of them:
let someFoos: [Foo] = [Foo(), Foo(), Foo()]
someFoos.forEach { $0.bar() }
This syntax is quite compact, but it feels a bit awkward. Also, it cannot be used everywhere. For example, in an if statement condition:
if someFoos.contains { $0.isBaz } {
// compiler error: statement cannot begin with a closure expression
}
if someFoos.contains($0.isBaz) {
// compiler error: anonymous closure argument not contained in a closure
}
if someFoos.contains({ $0.isBaz }) {
// this is correct, but requires extra pair of parentheses
}
Ideally, it would be nice to write something like
someFoos.forEach(Foo.bar)
but as of Swift 2.1 this is not a correct syntax. Such way of referencing the function would be similar to the following:
func bar2(foo: Foo) -> Void {
print("some boring print")
}
someFoos.forEach(bar2)
Is there a better way to reference instance function? How do you prefer to write such expressions?
There are two different problems here. The trailing closure syntax
can be used when calling a function and the last parameter is a closure,
so
let b1 = someFoos.contains({ $0.isBaz })
let b2 = someFoos.contains { $0.isBaz }
are fully equivalent. However, the trailing closure syntax can be problematic in the condition of an if-statement:
if someFoos.contains({ $0.isBaz }) { } // OK
if someFoos.contains { $0.isBaz } { } // Compiler error
if (someFoos.contains { $0.isBaz }) { } // OK, as noted by R Menke
We can only speculate why the second one does not work. It could be that the compiler
takes the first { as the start of the if-body. Perhaps this will
change in a future version of Swift but probably it is not worth
the effort.
The other problem is about curried functions.
someFoos.forEach(bar2)
compiles because bar2 has the type Foo -> Void, and that is exactly
what the forEach() method expects. Foo.bar, on the other hand,
is a curried function (see http://oleb.net/blog/2014/07/swift-instance-methods-curried-functions/) which takes the instance as the first
argument. It has the type Foo -> () -> (). So
Foo.bar(someFoo)
is a closure with type () -> (), and
Foo.bar(someFoo)()
calls the bar method on the someFoo instance.
(Note: The following is not meant as an actual recommendation,
but only as a demonstration about curried functions and fun
with closures!)
To pass Foo.bar directly as an argument to forEach() we need to
"swap" the order of the parameters. Haskell has a "flip" function for that purpose,
and it is also possible in Swift (see e.g. How to write a flip method in Swift?):
func flip<A, B, C>(f: A -> B ->C) -> B -> A ->C {
return { b in { a in f(a)(b) } }
}
Then flip(Foo.bar) has the type () -> Foo -> (), so
the void argument of the bar method can be applied
flip(Foo.bar)()
to get a Foo -> () closure, and
flip(Foo.bar)()(someFoo)
calls the bar method on the someFoo instance.
And now we can call
someFoos.forEach (flip(Foo.bar)())
without using a closure expression { .. } !!
If isBaz were a method instead of a property
func isBaz() -> Bool { return false }
then you
could do the same in the if-expression:
if someFoos.contains(flip(Foo.isBaz)()) {
// ...
}
Again, this is only meant as a demonstration. Also properties
are not curried functions, so this cannot be done with
your isBaz property.
The $0 syntax is there to help you create a shortcut, but if you don't like it you can use the more complete form:
someFoos.forEach { thisFoo in thisFoo.bar() }

Resources