In Swift, if I'm inside of a closure, that is itself inside of another function, is there a way to exit out of the function itself?
Here's an example of what this might look like using closures from the GCDKit library.
func test() {
GCDQueue.Default.async {
print("Print me!")
return //Is there a statement that does this?
}.notify(.Main) {
print("Never print me.")
}
}
No there is not. Closures run in self-contained environments. For all you know, by the time that closure is executed, the thread on which test() was called is no longer executing the test() method.
Let's consider a simpler version that doesn't include any third-party libraries, extra queues, or other complexity. We'll just create a closure and immediately execute it.
func dothing(andPrint shouldPrint: Bool) {
let closure = {
guard shouldPrint else { return }
print("I printed!")
}
closure()
print("did it return?")
}
dothing(andPrint: false) // Prints "did it return?"
The return here exits the closure, not dothing. Since closure could be passed to some other function, or stored in a property and executed at some later time (possibly on a different queue as in your example), there's no way for the return to exit anything beyond itself. Consider if we were to refactor the creation of the closure into its own function:
func fetchClosure(andPrint shouldPrint: Bool) -> () -> Void {
return {
guard shouldPrint else { return }
print("I printed!")
}
}
func dothing(andPrint shouldPrint: Bool) {
let closure = fetchClosure(andPrint: shouldPrint)
closure()
print("did it return?")
}
dothing(andPrint: false) // Prints "did it return?"
It shouldn't be surprising this has the same behavior (otherwise this wouldn't be a simple refactor). Now imagine how it would (or even could) work if return behaved any other way.
Your example is just a much more complicated version of the same thing. return exits the closure.
Related
Is it possible to force a closure to be completed? In the same way that a function with a return value MUST always return, it would be ace if there was a way to force a closure to contain the syntax necessary to always complete.
For example, this code will not compile because the function does not always return a value:
func isTheEarthFlat(withUserIQ userIQ: Int) -> Bool {
if userIQ > 10 {
return false
}
}
In the exact same way, I would like to define a function with a closure, which will also not compile if the closure never returns. For example, the code below might never return a completionHandler:
func isTheEarthFlat(withUserIQ userIQ: Int, completionHandler: (Bool) -> Void) {
if userIQ > 10 {
completionHandler(false)
}
}
The code above compiles, but I was wondering if there is a keyword which enforces that the closure sends a completion handler in all cases. Maybe it has something to do with the Void in the above function?
No, there is no language construct that will result in a compiler error if you forget (or don't need) to call the completion handler under all possible conditions like a return statement.
It's an interesting idea that might make a useful enhancement to the language. Maybe as a required keyword somewhere in the parameter declaration.
There is no special keyword for what you want. But there is an interesting approach you can take into consideration, that won't compile:
func isTheEarthFlat(withUserIQ userIQ: Int, completionHandler: (Bool) -> Void) {
let result: Bool
defer {
completionHandler(result)
}
if userIQ > 10 {
result = false
}
}
that will do and is completionHandler is forced to be called:
func isTheEarthFlat(withUserIQ userIQ: Int, completionHandler: (Bool) -> Void) {
let result: Bool
defer {
completionHandler(result)
}
if userIQ > 10 {
result = false
} else {
result = true
}
}
Not sure it's a good pattern to use.
Here is an interesting technique I thought of. You define GuarenteedExecution and GuarenteedExecutionResult types.
A GuarenteedExecution is a wrapper around a closure, which is to be used in a context where the execution of the closure must be guaranteed.
The GuarenteedExecutionResult is the result of executing a GuarenteedExecution. The trick is to have a desired function, e.g. isTheEarthFlat, return a GuarenteedExecutionResult. The only way to obtain a GuarenteedExecutionResult instance is by calling execute(argument:) on a GuarenteedExecution. Effectively, the type checker features responsible for guaranteeing a return, are now being used to guarantee the execution of GuarenteedExecution.
struct GuarenteedExecutionResult<R> {
let result: R
fileprivate init(result: R) { self.result = result }
}
struct GuarenteedExecution<A, R> {
typealias Closure = (A) -> R
let closure: Closure
init(ofClosure closure: #escaping Closure) {
self.closure = closure
}
func execute(argument: A) -> GuarenteedExecutionResult<R> {
let result = closure(argument)
return GuarenteedExecutionResult(result: result)
}
}
Example usage, in a seperate file (so as to not have access to GuarenteedExecutionResult.init):
let guarenteedExecutionClosure = GuarenteedExecution(ofClosure: {
print("This must be called!")
})
func doSomething(guarenteedCallback: GuarenteedExecution<(), ()>)
-> GuarenteedExecutionResult<()> {
print("Did something")
return guarenteedCallback.execute(argument: ())
}
_ = doSomething(guarenteedCallback: guarenteedExecutionClosure)
I have a function set up to return a Promise<PFObject>. I would like to use this function in PromiseKit's when(fulfilled:) functionality, but whenever I try to do so, I get an error. Here is the function which returns the Promise<PFObject>:
func Query() -> Promise<PFObject>{
return Promise{ fulfill, reject in
let linkQueryy = PFUser.query()
linkQueryy?.findObjectsInBackground(block: { (objectss, error) in
if let objects = objectss{
for object in objects{
fulfill(object)
}
}
})
}
}
As you can see, the function returns the Promise upon fulfillment. Thus, I tried to set up a when statement in my viewDidLoad() as follows:
override func viewDidLoad() {
super.viewDidLoad()
when(fulfilled: Query()).then{
//do more asynch stuff
}
}
However, I get the error that xcode cannot "invoke 'when' with an argument list type of '(fulfilled: Promise<PFObject>)'". I do not know how to fix this as I thought I had it set up correctly. The when needs a promise, and I am giving it one so I am not sure what to do.
Try as follows :
when(fulfilled: [linkQueryy()] as! [Promise<Any>]).then { _ in
// do more asynch stuff
}
The parameter fulfilled: needs to be an iterable.
By the way, when(fulfilled:) is necessary only when you have many promises and need wait for all to complete successfully. But in your code, you need to wait for only one promise.
For a single promise, the better way is to form a chain as follows :
firstly {
linkQueryy()
}.then { _ -> Void in
// do more asynch stuff
}.catch { _ in
// error!
}
I want to make a function that fetches a record from CloudKit, if it encounters a temporary network error the function should retry.
func fetchRecord(withRecordID recordID: CKRecordID, returnBlock: (optError: ErrorType?) -> Void){
func internalReturnBlock(optError optError: ErrorType?){
if NSThread.isMainThread() {
returnBlock(optError: optError)
}
else{
dispatch_async(dispatch_get_main_queue(), {
returnBlock(optError: optError)
})
}
}
func internalWork(){
privateDB.fetchRecordWithID(recordID) { (optRecord, optError) in
if let error = optError{
// IF NETWORK ERROR RETRY
internalWork()
}
else{
internalReturnBlock(optError: nil)
}
}
}
internalWork()
}
Here I define such function (simplified), If the fetch encounters an error it retries by calling the nested function internalWork()
My question is what would be the difference between using nested functions or creating local closure variables?
For example, here I change the internalReturnBlock to a closure variable:
func fetchRecord2(withRecordID recordID: CKRecordID, returnBlock: (optError: ErrorType?) -> Void){
var internalReturnBlock = { (optError: NSError?) in
if NSThread.isMainThread() {
returnBlock(optError: optError)
}
else{
dispatch_async(dispatch_get_main_queue(), {
returnBlock(optError: optError)
})
}
}
func internalWork(){
privateDB.fetchRecordWithID(recordID) { (optRecord, optError) in
if let error = optError{
// IF NETWORK ERROR RETRY
internalWork()
}
else{
internalReturnBlock(nil)
}
}
}
internalWork()
}
What are the differences between using a nested function vs a variable block?
Any advantages or problems?
There is no difference in effect. One is a declared function with a name, the other is anonymous. But they are both functions. And a function is a closure in Swift, so they are both closures.
An anonymous function is permitted to use some abbreviations of form, such as the omission of return in a one-liner that returns a value. But none of those abbreviations makes any ultimate effective difference.
However, an anonymous function in Swift has one feature a declared function does not — a capture list. This can help avoid retain cycles.
f {
[unowned self] in
return self.name
}
Also, an anonymous function is defined after the declaration of the function that takes it as a parameter, so it can use terms that appear in that declaration:
f(param:String) {
return param
}
But if you are not using those features, then it doesn't matter which you use. They work identically.
I'm learning more about Swift and came across the defer statement recently, which seems really intriguing to me. However I don't really understand it's purpose. Coming from C++ I would have implemented the same functionality using deallocation function and as a matter of fact, as Swift is ARC, it can do the same.
Let's say FooData and BarData both work with data that needs to deallocated.
class FooData {
deinit {
print("FooData being deallocated")
}
}
class BarData {
}
func baz() -> Int {
var a = FooData()
var b = BarData()
defer { print("BarData being deallocated") }
/* sensitive operations that could throw at any time */
return 0
}
baz()
// BarData being deallocated
// FooData being deallocated
So what's the advantage of the defer approach over the deinit approach? Just thinking about using defer for anything besides resource cleanup makes my head hurt...
You are seeing as different but there are not, defer was introduced by Apple as a safe and easy way to handle the clean up before returning, but defer only works for scopes. So let me explain better, if you have some scope defined inside a function an the variable you have created exist only inside the scope you cannot access from the deinit, for example:
func resizeImage(url: NSURL) -> UIImage? {
// ...
let dataSize: Int = ...
let destData = UnsafeMutablePointer<UInt8>.alloc(dataSize)
defer {
destData.dealloc(dataSize)
}
var destBuffer = vImage_Buffer(data: destData, ...)
// scale the image from sourceBuffer to destBuffer
var error = vImageScale_ARGB8888(&sourceBuffer, &destBuffer, ...)
guard error == kvImageNoError
else { return nil }
// create a CGImage from the destBuffer
guard let destCGImage = vImageCreateCGImageFromBuffer(&destBuffer, &format, ...)
else { return nil }
// ...
}
In this case it doesn't make sense define the variable destData as global and we need to deallocate once we finish of work with it, so defer it's the choice.
I think deinit it can be used for more global scope, for example when you implement the Key-Value Observer using NSNotificationCenter or something else you need.
I hope this help you.
Using defer inside a method means that its work will be executed as the method is exiting.
override func viewDidLoad() {
super.viewDidLoad()
print("Step 1")
myFunc()
print("Step 5")
}
func myFunc() {
print("Step 2")
defer { print("Step 3") }
print("Step 4")
}
"Step 1", "Step 2", "Step 4", "Step 3", "Step 5" – steps 3 and 4 are switched because 3 is deferred until the myFunc() method ends, i.e. when it goes out of scope programmatically.
About deinit, this is used to run code before deinitialization. The deinit code is run automatically. Deinitializers are called automatically, just before instance deallocation takes place. You are not allowed to call a deinitializer yourself.
class Item {
init() {
print("init called")
}
deinit {
// Called whenever class stops existing.
print("deinit called")
}
}
// Create optional Item variable.
var i: Item? = Item()
// Set optional to nil to force deinit.
i = nil
In programming some functions always appear in pairs. For example, opening a connection and closing that connection, locking a mutex and unlocking a mutex, incrementing a counter, decrementing a counter, allocating memory, deallocating memory.
The pattern usually looks like this:
lock()
... do something ...
unlock()
The middle part can be complicated and long. There can be returns (e.g. for failed preconditions and Swift recommends this pattern with its guard). Sometimes it's very hard not to forget to include that unlock() in all execution paths.
One way to solve the situation nicely is using a helper function:
func doSomething() {
... do something with returns ...
}
lock()
doSomething()
unlock()
but that's not always possible, e.g. when you have several nested objects.
In C the same pattern was often solved with goto:
x = malloc(...);
y = malloc(...);
if (!precondition) {
goto end;
}
... some code ...
end:
free(y);
free(x);
Modern languages came with a better approach which in Swift is implemented using defer (you can also find defer in Go, for example).
lock()
defer {
unlock()
}
... some code ...
This approach has several benefits:
You can have the calls together, which increases readability and makes it very hard to forget the second call.
All returns, precondition checks, error handling will leave the code in correct state because unlock will be always called correctly. This is similar to finally in exception handling in Java (and other languages)
If you are asking about the difference from deinit, it works in a similar way. However defer can work in functions while deinit works only for classes.
Also note that you could reimplement defer using deinit but the usage would be more complicated and the behavior less predictable.
defer could be called conditionally what is impossible to implement with deinit
var i = 1
func foo()->Int {
if i == 1 {
defer {
i = 0
}
}
return i + 1
}
print("foo:", foo(), "i:", i)
Consider a database transaction. You want to close the connection when you're done, but you want to keep the object around to reinstate connections in the future:
stuct foo {
let db = Database()
func useDatabase() throws {
let connection = db.openConnection()
defer {
// close conenction, but keep db around for future use
connection.close
}
try connection.thisCanThrow()
}
}
This is just one example, but there are many like it. In particular, a lot of cases arise where you want to model the restricted lifespan of a state, without binding it tightly to an object's life time.
C++ heavily relies on RAII. Swift is certainly capable of adhering to the same paradigm, but it can also go beyond it with defer.
I first tried this solution to return a bool in the spot I want to return it. However, due to the parse.com function saveInBackgroundWithBlock() being a void return function, I got the error "Unexpected non-void return value in void function".
func saveObjectToParse(gameLocal: Game) -> Bool {
let game = PFObject(className:"Game")
game["sport"] = gameLocal.sport.rawValue
var saved = false
game.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if (success) {
print("Object has been saved.")
saved = true
return saved
} else {
print("parse error")
return saved
}
}
}
So, I tried moving the return statements out of the subfunction like this:
func saveObjectToParse(gameLocal: Game) -> Bool {
let game = PFObject(className:"Game")
game["sport"] = gameLocal.sport.rawValue
var saved = false
game.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if (success) {
print("Object has been saved.")
saved = true
} else {
print("parse error")
}
}
return saved
}
However, this returns saved before the saveInBackgroundWithBlock() block executes because it is a background process. Therefore, saved will never be true, even when it is intended to be. I have tried adding a boolean flag called done and tried waiting with a while(!done) loop, but this freezes the program on the loop and the background process never executes. How can I fix these problems?
I agree with restructuring not needing a bool returned, but if you really, really need this set up, you could save your object synchronously (so your code will wait) like so,
do {
try game.save()
} catch {
print(error)
}
Returning a value from a function but from another function doesn't make architectural sense. Nor is it possible.
You either will need to change your implementation and make both methods independent or think of using a semaphore.
http://www.g8production.com/post/76942348764/wait-for-blocks-execution-using-a-dispatch
What you are trying to do (create a helper function to wrap the Parse save function) makes perfect sense and can be easily accomplished.
You do not need to use semaphores and you certainly don't want to perform the operation synchronously. Instead, use a completion hander to let you know when the save has completed. For more information on completion handlers see this link
func saveObjectToParse(gameLocal: Game, completion: (gameSaved: Bool) -> Void) {
let game = PFObject(className:"Game")
game["sport"] = gameLocal.sport.rawValue
game.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
// Set the completion handler to be result of the Parse save operation
completion(gameSaved: success)
}
}
You may then call this function like so
saveObjectToParse(someGameObject) { (gameSaved: Bool) in
if gameSaved {
print("The game has been saved.")
} else {
print("Error while saving the game")
}
}
Using this technique, you could similarly propagate the entire callback of saveInBackgroundWithBlock through your function so you could inspect errors when they occur.
Edit: It looks like you may also be using your own custom class to represent the Game object. I would recommend looking into subclassing PFObject so you can easily and directly model your Parse classes. More details in the documentation