UTIを参照したい時はUniformTypeIdentifiersフレームワークを使おう

Drag&Dropなどを実装していると、外部のアプリケーションへ登録したオブジェクトを引き渡すことがあるため、UTIの登録が必要になります。これまでは`CoreServices`や`MobileCoreServices`を利用していましたが、iOS14, macOS11.0以降は [UniformTypeIdentifiers](https://developer.apple.com/documentation/uniformtypeidentifiers/)の利用が推奨されています。

# UniformTypeIdentifiersの使い方
例えばiOSでのD&Dの実装では以下のように使います。

```swift
import UniformTypeIdentifiers

func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {

    let object = dataStore.object(at: indexPath)
    let data = object.title.data(using: .utf8)
    let itemProvider = NSItemProvider()

    // ここ
    itemProvider.registerDataRepresentation(forTypeIdentifier: UTType.plainText.identifier, visibility: .all) { (completion) in
        completion(data, nil)
        return nil
    }

    return [UIDragItem(itemProvider: itemProvider)]
}

```

# 以前は何を使っていた？
iOS13以前は`CoreServices`や`MobileCoreServices`などが使われていました。

例えば先ほどのコードを`MobileCoreServices`を使って書いてみると以下のようになります。

```swift
import MobileCoreServices

func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {

    let object = dataStore.object(at: indexPath)
    let data = object.title.data(using: .utf8)
    let itemProvider = NSItemProvider()

    // kUTTypePlainText as Stringとなっている
    itemProvider.registerDataRepresentation(forTypeIdentifier: kUTTypePlainText as String, visibility: .all) { (completion) in
        completion(data, nil)
        return nil
    }

    return [UIDragItem(itemProvider: itemProvider)]
}

```

# `UniformTypeIdentifiers`になって変わったことは？
`kUTTypePlainText`のような、以前のフレームワークで参照できたkUTTypeは`CFString`で宣言されていました。
これに対して`UniformTypeIdentifiers`フレームワークでは[UTType](https://developer.apple.com/documentation/uniformtypeidentifiers/uttype)というstructが定義されており、その下に[plainText](https://developer.apple.com/documentation/uniformtypeidentifiers/uttype/3551548-plaintext)などの[システム定義のUTType](https://developer.apple.com/documentation/uniformtypeidentifiers/system_declared_uniform_type_identifiers)がたくさん定義されています。

私は昔のApple開発環境に詳しくないため変更理由の正確な推察が出来ませんが、なんとなく「レガシーな仕組みを刷新したかったのかな」と推測しています。お詳しい方いらっしゃたらコメントで教えていただけると助かります。

# 古いフレームワークでの値と等価なのか？
機能テストを少し書いてみました。このテストがパスしたため、等価と言えます。

```swift
import XCTest
import CoreServices
import UniformTypeIdentifiers

class UTIFunctionTests: XCTestCase {

    func testPlainText() throws {
        XCTAssertEqual(kUTTypePlainText as String, UTType.plainText.identifier)
    }

}
```

# どこに移行に関する情報が書いてあるのか？
## フォーラム
フォーラムでAppleのデベロッパーが回答している投稿を見つけました。

https://developer.apple.com/forums/thread/651819

> Hi yetanotherme! This API has been marked API_TO_BE_DEPRECATED because we've introduced an Objective-C and Swift replacement API, the UniformTypeIdentifiers framework.
>
> (Posted 10 months ago by Frameworks Engineer , UTI deprecated?, Developer Forums, https://developer.apple.com/forums/thread/651819, viewed: 2021/05/17)

上記の引用文で書かれているように、`CoreServices`と`MobileCoreServices`は`API_TO_BE_DEPRECATED`としてマークされており、将来的に非推奨にされるようです。

## WWDC
こちらのセッションの後半でUniformTypeIdentifiersフレームワークへの置き換えについて話があります。

https://developer.apple.com/videos/play/tech-talks/10696


# まとめ
UTIに関して、AppleはiOS14とmacOS11以降で利用可能な`UniformTypeIdentifiers`フレームワークを提供しました。古いフレームワークは将来的に非推奨になることが決まっているため、利用可能な場合は新しいフレームワークを使いましょう。