File Reference URLs Don’t Work in Swift 3
In Swift 3.0 (i.e. Xcode 8.0 or Xcode 8.1 beta 1), a call to
fileReferenceURL
does not give a file reference URL anymore... this codeimport Foundation let string = "file:///Users/admin" if let url = NSURL(string: string) { if let ref = url.fileReferenceURL() { print ("ref = (ref)") } }prints
ref = file:///Users/admin/while it should have been printing
ref = file:///.file/id=6571367.437879/as it did, correctly, in Swift 2.2 (and before) in Xcode 7.3.1 for example.
Via Charles Srstka:
.fileReferenceURL
doesn’t exist onURL
. It does exist onNSURL
, but thanks to the bridging magic it returns aURL
, which the ObjC-Swift bridge turns into a normal file path URL.
Frédéric Blondiau has some workarounds, but these are distasteful to me because they rely on the internal details of both NSURLFileResourceIdentifierKey
and file reference URLs.
It seems like the proper short-term solution would be to write some Objective-C code to return an object that is not bridged to URL
. This could probably be the actual NSURL
typed as id
. Or, if you’re going to use an opaque token anyway, another option would be to store bookmark data. I assume that would be slower, though.
Update (2018-09-08): Christian Tietze:
Swift 4.1 has a simpler mechanism to ensure you get a
NSURL
instead of aURL
– the only type that supports file reference URLs as of September 2018, still.if let fileRefURL = (url as NSURL).fileReferenceURL() as NSURL? { print(fileRefURL) }Try that in the Swift 4.1 REPL to see that it works. Whew.
I do understand that there may be reasons to remove
fileReferenceURL
fromURL
and leave it onNSURL
, but when you do invoke it onNSURL
, I think it should at least return anotherNSURL
object that works as expected instead of bridging to Swift’sURL
struct that, for some reason, won’t work.
Update (2019-01-08): Jens Ayton:
No, wait! It actually crashes when you bridge the file reference
NSURL
toURL
.
3 Comments RSS · Twitter
This issue came up on the mailing list today and Tony Parker posted this great explanation why the Foundation team decided to not support reference URLs for URL (a value type):
"Basically: if struct URL could be a reference, then almost all of its methods/functions needed to be marked as ‘throws’, including all of the path manipulation stuff, because all of them touch the file system and touching the file system has the possibility of introducing all kinds of errors. This made the API very cumbersome. In order to dramatically simplify the API, we decided that struct URL should not hold references. If references were still important, they should just be another type. For now, that other type is NSURL." (Source: https://lists.swift.org/pipermail/swift-corelibs-dev/Week-of-Mon-20161205/001052.html)
@Ole Thanks for the link. The problem is that you can’t actually use file references as NSURL from Swift.