The curious case of NSFileCoordinator in Swift

965 Views Asked by At

It seems that NSFileCoordinator, despite being a pretty important class, has not been given any Swiftification. It has not been given any async alternative; you have to provide a completion handler. Moreover, it takes an NSErrorPointer rather than being marked throws, and the pointee cannot be referred to inside the completion handler:

let url = URL(fileURLWithPath: "fakepath")
var error: NSError?
NSFileCoordinator().coordinate(readingItemAt: url, error: &error) { url in
    let theError = error
    print(theError as Any)
}

This results in an error: "Simultaneous accesses to error, but modification requires exclusive access."

If I can't access the error from inside the block, what use is it? How am I supposed to access it? Surely not after the block; the completion handler is called asynchronously (because we have to wait until coordinated access is possible), so after the block, the error will always be nil even if there was in fact an error.

(I notice that Apple's own example code skirts this issue by never checking the value of its error variable at all.)

1

There are 1 best solutions below

3
matt On

Apparently this method is even weirder than I thought. According to the docs, if there is an error, the completion handler is never called. Thus, checking error for a non-nil value after the completion handler might actually be somewhat useful.

Moreover, the docs also say that you are expected to set a separate "sentinel" value to indicate failure initially and then set it to indicate success within the completion handler. So the canonical architecture would be:

let url = URL(fileURLWithPath: "fakepath")
var failure = true
var error: NSError?
NSFileCoordinator().coordinate(readingItemAt: url, error: &error) { url in
    failure = false
}
if failure {
    print(error as Any)
}

I've never actually seen this architecture used, but that appears to be what you're supposed to do.