Closure declaration in swift 2.0 - ios

In swift 2.0, what is the correct closure declaration? I've seen examples done like below, but it doesn't seem to work for me.
In SomeClass:
var successBlock: (Bool) -> () = { _ in }
and it would be called like this:
self.successBlock(true)
Then in SomeOtherClass:
let someClass = SomeClass
someClass.successBlock {
success in
//code here
}
Bit this gives me an error: (_) -> is not convertible to Bool
I've tried googling around a bit but with no luck...
Is there a syntax change with swift 2.0 or is it me?

If you're trying to set the successBlock, you should do it with an = sign:
someClass.successBlock = { success in
// code here
}
EDIT: You mentioned that you only want your other class to "listen", but what does "listen" mean? If you want to listen to every time the closure gets called with some value and do something depending on it, you may want to have an array of closures instead:
var successBlocks : [Bool -> Void] = []
which you can invoke like this:
let value = true
successBlocks.forEach{ $0(value) }
When you want to listen to invocations, you can do this:
someClass.successBlocks.append( { success in
// do the stuff
} )
which won't override any other closures already in the array, so probably that's what you wanted to do.

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.

Swift Closures - How to pass a parameter and have no return value

In the following code, I’m trying to create a closure that is passed a single parameter that will be used in the closure, where no value is returned:
The code is called from another Swift class in my app via runit()
Cannot invoke value of type ‘(CheckerOperation) -> ()’ with argument
list ‘(CheckerOperation)’ at the line
“runTimerProcess(runitProcess(customOperation))
I don’t understand how to invoke when the closure will not be returning a value.
(CheckerOperation is just a custom NSOperation class)
class Checker {
var queue = NSOperationQueue()
let customOperation : CheckerOperation = CheckerOperation()
var runitProcess: (CheckerOperation) -> () = {op in
NSOperationQueue.mainQueue().addOperationWithBlock({
let operationQueue = NSOperationQueue.mainQueue()
operationQueue.addOperation(op)
})
}
func runTimerProcess(closureblock: ClosureBlock){
let queue = dispatch_queue_create(“myqueue”, DISPATCH_QUEUE_SERIAL)
dispatch_async(queue,closureblock)
}
func runit(){
runTimerProcess(runitProcess(customOperation))
}
}
You're mixing two core syntaxes: (1) computed properties, and (2) functions/methods.
Computed properties cannot accept arguments. For your case, you should be simply defining a function with an argument op with a type of CheckerOperation. I say this because you don't appear to need to return or check a value on runitProcess which is really what a computed property is intended for.
Use this:
func runitProcess(op: CheckerOperation) {
NSOperationQueue.mainQueue().addOperationWithBlock({
let operationQueue = NSOperationQueue.mainQueue()
operationQueue.addOperation(op)
}

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

Initialiser Inheritance confusion

I am trying to build some mocking infrastructure, I want to be able to return a stubbed value and count the times the value was accessed. I have something simple like this:
class BasicMock<T> {
var callsCount = 0
private let backing: T
var result: T {
callsCount++
return backing
}
init(result: T) {
self.backing = result
}
}
class MockTimeDefinitionSerialiser: BasicMock<[String: [AnyObject]]>, TimeDefinitionSerialiserProtocol {
func serialiseTravelTime(travelTime: JSSTravelTime) -> [String: AnyObject] {
return result
}
}
However trying to build it:
let mockTimeDefinitionSerialiser = MockTimeDefinitionSerialiser(result: ["": ""])
Emits the error 'MockTimeDefinitionSerialiser' cannot be constructed because it has no accessible initialisers
My interpretation of the Swift docs is that I should automatically inherit the initialiser as I have set all stored properties.
What am I doing wrong?
Please remove any unnecessary code when asking a question. I was able to reduce your problem to this:
class Base<T> {
init(t: T) {}
}
class Sub: Base<Int> {}
Sub(t: 0) // error: 'Sub' cannot be constructed because it has no accessible initialisers
It seems like even though you specified the T in the subclass, the compiler cannot infer what the initialiser uses for T. I couldn't find a way to get the initialiser to be inherited, you'd have to use a workaround:
class Sub: Base<Int> {
override init(t: Int) {
super.init(t: t)
}
}

Block conversion in swift from Objective-c

How to convert following block from Objective-C to Swift. Am using Objective-C files in Swift using bridge header. But small confusion in block conversion
Objective-C Block:
+ (void) while:(id)obj name:(void(^)(type*))callback;
Sample output:
[Sub while:keeper viewControllerChanged:^(NSString* newNickname) {
NSLog(#"\nVC2- Now screen is in: %#", newNickname);
}];
How to convert this in swift ?
EDIT:
Swift block error is
Sub.while(obj: AnyObject!, viewControllerChanged: ((String!) -> Void)!)
When you define :
class func while1(obj:AnyObject, callback name:((newNickname:NSString?) -> Void)) {
}
And when call function :
self.while1(self) { (newNickname) -> Void in
print("\nVC2- Now screen is in:" + "\(newNickname)")
}
EDIT :
Okay, Then you just want to call it from swift..right..? Then use this statement :
ClassName.while1(obj as AnyObject) { (nickName:String!) -> Void in
print(nickName)
}
But first make sure that in your definition statement "type" indicates for what DataType, so please define there actual DataType
+ (void)while:(id)obj name:(void(^)(type*))callback;
to --> For example :
+ (void)while1:(id)obj name:(void(^)(NSString *))callback;
And one more thing to note that while in built in keyword, please do not use it if possible.
You can call like this:
YourClassName.while2(Yourparameter , name: {(nickName : String) -> Void in
})
I hope this help.
I'm not sure if you are asking how to write blocks in swift or if I'm not completely getting your question. But if it's the first then...
(void(^)(type*))callback
becomes
callback: (param:type*)->(returnType*)
i.e.
func doSomething(callback:((number:Int)->()))
is called like
doSomething(callback:{number in
print("\(number)")
})

Resources