In Swift, you can weak-ify references to self
in escaping closures, and then you need to deal with the case that the reference is gone when the block is called. Last month, Benoit Pasquier and Chris Downie presented different takes on the problem. That discussion was excellent. It prompted me to take some more time to revisit this problem systematically, and I took away a couple of notes for future-me.
Continue reading …
Today I learned that you can cancel a delayed dispatch_block_t
with the new dispatch_block_cancel
(available since OS X 10.10/iOS 8.0). Thanks Matt for the post – here’s a Swift example:
let work = dispatch_block_create(0) { print("Hello!") }
# Execute after 10s
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(10 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue(), work)
dispatch_block_cancel(work)
# Will never print "Hello!"
Note: canceling doesn’t work if the block is being executed.
If I knew that this API existed, I might not have used the very cumbersome approach from below in Move!.
Super-Weird Legacy Version of a Cancelable Delayed Block
For historic purposes, here’s an adaptation of the cancelable dispatch block you may find on the internet that I once have adapted for Swift:
typealias CancelableDispatchBlock = (cancel: Bool) -> Void
func dispatch(
cancelableBlock block: dispatch_block_t,
atDate date: NSDate
) -> CancelableDispatchBlock? {
// Use two pointers for the same block handle to make
// the block reference itself.
var cancelableBlock: CancelableDispatchBlock? = nil
let delayBlock: CancelableDispatchBlock = { cancel in
if !cancel {
dispatch_async(dispatch_get_main_queue(), block)
}
cancelableBlock = nil
}
cancelableBlock = delayBlock
let interval = Int64(date.timeIntervalSinceNow)
let delay = interval * Int64(NSEC_PER_SEC)
dispatch_after(dispatch_walltime(nil, delay), dispatch_get_main_queue()) {
guard let cancelableBlock = cancelableBlock else { return }
cancelableBlock(cancel: false)
}
return cancelableBlock
}
func cancelBlock(block: CancelableDispatchBlock?) {
guard let block = block else { return }
block(cancel: true)
}
The trick is this: the delayed block delayBlock: CancelableDispatchBlock
captures its context where a reference to cancelableBlock
is included – but not set yet. Then you make the reference point to the delayBlock
itself.
The actual canceling is a fake, though. The block is still called. It aborts early if the cancel
parameter is true
, though.
Currying is a very useful and interesting thing. It means that you can write functions in parts. If you don’t provide all parts at once, you won’t get the “real” result but a closure that accepts the missing parameters. Like this, with spacing added to reveal how the nested closure maps to the chain of return types:
Continue reading …
Found this little gem in a library called NextGrowingTextView
, shortened to make the point clear with less code. It’s a collection of block-based event handlers in a little class:
Continue reading …
Something short and sweet I want to share with you because I love how it reads: restoringSelection
is a function that takes a block and performs whatever the block does while restoring the current selection in a table view (here: NSTableView
). Here’s the implementation. The resulting code from above reads so much nicer than querying selection()
first and restoring it afterwards. It communicates very clearly that some state from before will be preserved (or restored).
Continue reading …
In a recent post, I wasn’t too fond of inline helper functions. Similar things can be accomplished with blocks instead of functions, as both are closures that capture their contexts. Blocks don’t even have to have a name. Inner functions and blocks share the same semantics. Found in Little Bites of Cocoa #180:
Continue reading …
In Swift, you can define functions within functions. These are often referred to as helpers. Rob Napier brought this to my attention recently. Like any other closure, helper functions capture variables from their surrounding context if needed. This way you don’t have to pass them along as parameters.
Continue reading …
As I’m exploring the use of block based API, which means to assign closures or functions handles to properties or pass them around as parameters to other functions, I found a few benefits and drawbacks in comparison to protocol-based object interactions. Here’s a breakdown of criteria for blocks and delegates.
Continue reading …
Reflecting on a recent change of the Word Counter’s file monitoring module, I think I re-discovered a commonly advised pattern in my code: to separate state from state changes. There’s an object that knows how to handle files based on extension: plain text files’s words are counted differently than Word or Scrivener files. Call it Registry
. Previously, this was set up once and didn’t change. Now I wanted to make this configurable so users can add custom plain text extensions. This means changing that object’s state.
Continue reading …
I don’t like the way I tend to create view controller event handlers. They are almost always just a sink for methods which have nothing in common conceptually but are tied together because of the view’s capabilities. So I began experimenting. Closures can encapsulate changes. This works well with callbacks for Repositories which fetch entities from your data store. Instead of returning them, you can pass them forward:
Continue reading …