ひ to り go と

Swift 4 の URL は -[NSURL fileReferenceURL] に非対応 

MacDev

-[NSURL fileReferencceURL] を使用すると AppleScript でいうところの alias みたいな1、ファイルの場所に依存しない特別な URL を取得できる。

NSURL* url = [NSURL fileURLWithPath: @"/Applications/"]; //1
url.fileReferenceURL //2
Code
1: file:///Applications/
2: file:///.file/id=3534367.8613694728/
Result

これを Swift で使うのが今回の話。

Swift から呼ぶと

Swift で同じ内容を書いてみる。まず期待を裏切られるのは URL に対して「fileRe」まで入力しても補完されないことだ。...どうやらこの機能は NSURL にしか用意されていないらしい。

まあ焦ることもない。NSString の機能を使いたいときと同じように as NSURL してから呼べばすべて解決するだろう。

import Foundation

let url = URL(fileURLWithPath: "/Applications/") //1
let fileReferenceUrl = (url as NSURL).fileReferenceURL() //2
Code
1: file:///Applications/
2: Optional(file:///Applications/)
Result

プロパティ扱いになっていないようで () が必要なのが気持ち悪いくらいか。クラッシュせずに動くし、解決!

...してない。これよく見ると普通の URL じゃないか!

変換できない

調べてみると、どうやら fileReferenceURL というのは一瞬でも Swift の URL に変換したら通常の URL に変化してしまうらしい。普通に呼んだだけなのに失敗した理由は何かというと、このメソッドは NSURL のものであるけれど Swift 上では返り値の型が URL? なのでそこで変換されてしまったということか。 

Workaround

対処法は、 Swift による変換が入らないようにすることだ。以下のように as NSURL? をつけるのが正解。似てるけど as? NSURL はダメだから注意しよう。

let url = URL(fileURLWithPath: "/Applications/") //1
if let fileReferenceUrl = (url as NSURL).fileReferenceURL() as NSURL? {
    fileReferenceUrl //2
}
if let fileReferenceUrl = (url as NSURL).fileReferenceURL() as? NSURL {
    fileReferenceUrl //3
}
Code
1: file:///Applications/
2: file:///.file/id=3534367.8613694728/
3: file:///Applications/
Result

Swift の URL が対応しないのは目をつぶるにしても、せめて型が NSURL? になるように修正してほしいものである...

保存するなら

Apple の説明によると、この fileReferenceURL は特定のタイミングで無効になる値らしい。保存するなら Bookmark Data を作成する必要があるそうだ。

A file reference URL's path should never be persistently stored, because it is not valid across system restarts or remounts of volumes. If you need to store a persistent reference to a file system object, use a bookmark instead. You can create a bookmark by calling bookmarkData(options:includingResourceValuesForKeys:relativeTo:).


  1. よく調べずに書いたが本当? ↩︎

Share

リンクも共有もお気軽に。記事を書くモチベーションの向上に役立てます。

© 2005-2019 zumuya