やらかしたので反省文
iOS10.3にてファイルシステムが HFS+からAPFSに強制変換されましたが
濁点など含むファイル名にてfopenなどの下位関数にアクセスする際
Stringなどからconst char* への変換は
UTF8String ではなく fileSystemRepresentation を使いましょう。
ざくっと調べた
検証コードを整えるのが面倒なので結果だけ
合成された普通のもの NFC : "だ" 3080 (1文字は1文字)
正規化分解NFD : "だ" 305F 3099 (濁点分割して検索なんかも楽しそうよね)
HFS+でもAPFSでもファイル名は正規化分割NFDされて保存される (前からそう)
HFS+では分割されていてもいなくても(NFD,NFC)同じNFDファイル名にアクセスできる、おそらくどこかでうまく処理してくれていたのだろう
APFSではfopenなどの下位関数はNFCそのままにアクセスされる、変換処理してくれない (ここが問題)
よってAPFSではNFC,NFDのファイル名が2つできたり、NFC名でアクセスした際ファイルが無いなどの問題が起こる
(これでNFCなファイルが出来るとbackupなんかでも問題起きたりするとか)
NSFileManagerなどの上位関数でのファイル処理は問題ない
(objc的に書いているけれども)swiftも問題は同じ
対処としては、ファイル名などは普通StringなりURLなりで持っていると思われ、
fopenなどの低位関数にてアクセスする際のファイル名は const char* に変換することになると思われるので、
このStringなりからconst char*への変換をUTF8StringではなくfileSystemRepresentation (これはファイルシステムに対応してNFDなりの処理をしてくれる)で行う。
CFStringNormalize((CFMutableStringRef)なにか, kCFStringNormalizationFormD);
でもNFD変換できるが、ここは素直にファイル系のAPIに従おう。
NSURLのメソッドなのでNSStringとかからなら
[[NSURL fileURLWithPath:self] fileSystemRepresentation];
てのでもよい。(相対パスからだと少し注意)
ファイルシステムとAPIの問題で、今までうまく処理していてくれただけに、バグと判断したくもなるヨナ。
ざくっとなので内容に関しては自分で確認してね。
追記
NFCなファイル名は存在するべきではないし、
ファイルのcreate/writeには上記に気をつけていれば問題ないがreadの場合、
NSFileManagerなどの上位関数ではNFCなファイル名のものは無いものとして処理される。
fileExistsAtPathなどではfalse
だがcontentsOfDirectoryAtPathではNFCなままリストアップされて返ってくる。
上位関数レベルで見ると、あるらしいけれどアクセスできないってファイルになるという。
そんなの作らなければいいのだけれど、windowsのiTunes転送だと、NFCなファイル名なまま作成されてしまう恐ろしい罠が。(あ、もうapple自身がやっちゃてるならバグよね)