Image Capture CoreはApple PlatformでUSB接続されたカメラやスキャナと通信するためのフレームワークです。OSに標準で入っています。
macOS 10.6以降で使用可能で古くからあるフレームワークです。iOSでもiOS 13.0で導入され、MFI(Made For iPhone)が不要にも関わらず、USB接続された対応デバイスと通信できる便利なフレームワークです。対応しているデバイスがカメラやスキャナなので限られたデバイスではありますが、PTPを使った通信が可能です。
ブロック系のAPIが追加される
Image Capture Coreですが、macOS 10.6で導入される前、Image Capture APIという同等の機能を持った別のフレームワークを置き換える形で登場しました。Image Capture APIはC言語のインターフェイスでした。
Image Capture CoreはObjective-Cのクラスとして提供されます。長い間、放置されてきたのですが、macOS 10.15でてこ入れがありました。
Image Capture Coreは非同期APIで、デバイスからの応答をデリゲートで受け取るという設計になっていました。そこに、デバイスからの応答やイベントをブロックで受け取るAPIが追加されました。このとき、同時にサブスレッドからコマンドを送信しても問題が起きないようになりました。
デリゲートを使ったAPIだけが提供されていた時代のImage Capture Coreはスレッドセーフではなく、メインスレッドで使用する必要がありました。(ドキュメントとしては書かれていないのですが)
ここ最近よく変更される
Image Capture Coreは長い間変化がなかったのですが、ここ最近、OSがアップデートされるたびに、問題が起きます。デリゲートのAPIはDeprecatedになっているわけではなく、ブロック系のAPI共に正式にサポートされているのですが、Image Capture Coreの内部実装の変更の影響を大きく受けます。
内部のコードを見ることはできませんが、動かなくなる度にデバッガで観察していると、CFRunLoopを使った非同期からDispatch (GCD) を使った非同期処理への移行を行っているようです。
デリゲート系のAPIを使っていて、CFRunLoop系であることを前提にした処理を書いていると色々と問題が起きます。
Dispatch+ブロック系のAPIに移行するべき
ブロック系のAPIを使って、専用のDispatchQueue上で通信を行い、同期制御にはDispatch Semaphoreを使うコードへと移行すると、内部実装の変化の影響を受けづらく、処理が安定します。
デリゲート系のAPIを使っている場合はブロック系のAPIに移行した方が良いようです。