3

What happens if you never call the completion handler? Are there any side effects? I am assuming there might be a memory leak, but I cannot find any documentation.

func completeMe(completionHandler: @escaping (String?) -> Void) {
   return
}
jscs
  • 63,694
  • 13
  • 151
  • 195
Mocha
  • 2,035
  • 12
  • 29
  • @JoshCaswell please elaborate? In what situation would it be okay/worse to ignore a completion handler? – Mocha Jan 25 '19 at 22:10
  • @JoshCaswell I'm basing this on the fact that the app will continue running fine if the completion handler is never called. I am curious if the app will be affected in any way if many completion handlers are left dangling. – Mocha Jan 25 '19 at 22:13
  • @JoshCaswell What happens to the code that won't be run. Will it be waiting forever, or will it fall out of scope? – Mocha Jan 25 '19 at 22:22
  • Failing to call the completion handler is a violation of the contract you have with the method. Call it. End of story. – rmaddy Jan 25 '19 at 22:46

2 Answers2

5

Fundamentally, there's nothing special about a "completion handler". It's just a function.

If you have a function:

func f() {
    print("Hello, world")
}

and you don't call it, what happens then? Well, nothing happens.

Now, what are the implications of that? As rmaddy mentioned, if a function has a completion, the invocation of that completion is certainly expected by callers. It's unusual at best for a function to take a completion and the caller to not care whether the completion is ever run.*

Imagine the function is called by a view controller that starts an activity indicator before it calls, and then in the completion it stops the indicator. If the completion is never called, then the indicator never stops spinning.

Fundamentally, that's it. If the completion isn't called, its code doesn't run. The effects of that are completely dependent on what's going on in the code in and around the completion.


Okay, you mentioned memory... A lot of the time, a completion handler will be an anonymous function. In that case, there is an object created. But it's subject to the same memory management rules as any other object. There is no leak just because it is not called. If completeMe looks like this:

func completeMe(_ completionHandler: (String) -> Void) {
    completionHandler("Hello, world")
}

and you call it like this:

completeMe({ self.detailLabel.text = $0 })

Then the object created for the anonymous function doesn't live past when completeMe returns. If you store the anonymous function:

func completeMe(_ completionHandler: @escaping (String) -> Void) {
    self.handler = completionHandler
    // Do other things
}

Then the same thing happens as with any other object: the anonymous function lives until that property is set to another value (given also that nothing else has a reference to it).

And if you pass a named function in,

func takeAString(_ s: String) {
    print(s)
}

completeMe(takeAString)

the lifetime of takeAString is already the lifetime of the program; there's no memory management implications here.

If you pass an instance method in, the memory management is the same as if you had passed the instance itself in.


*Generally if failure is possible you would either a) have a second "failure" completion or b) the completion would signal failure via its argument.

jscs
  • 63,694
  • 13
  • 151
  • 195
3

Since the parameter is named completionHandler, your caller will assume that it will be executed, no matter what.

So, to answer your question, there won't be any inherent side effects, but it could be considered a bad practice.

Joshua Kaden
  • 1,210
  • 11
  • 16
  • So if a million blocks are waiting for a completionHandler, nothing happens? I was thinking these blocks(callers) have memory allocated for them. – Mocha Jan 25 '19 at 22:01
  • I think the completion handler will fall out of scope when the method returns – Joshua Kaden Jan 25 '19 at 22:05
  • Ah, I see. If possible do you know of documentation for this? I want to verify 100% before I give false information. – Mocha Jan 25 '19 at 22:06