Help us understand the problem. What is going on with this article?

Core Dataのtransformableな属性をセキュアに実装する

Core Dataのエンティティが持つ属性 (attribute) の型は整数、文字列、日付などいくつかの決まったものしかとることができませんが、Transformableを指定することで任意の型を NSData に変換して保存することができるようになっています。このとき保存したい型と NSData の変換を担うのがvalue transformerです。

Core Dataのtransformableを利用しているプロジェクトをXcode 12でビルドしたときに、以下のような警告が出るようになりました。

warning: Misconfigured Property: <NSManagedObjectのサブクラス>.<プロパティ> is using a nil or insecure value transformer. Please switch to NSSecureUnarchiveFromDataTransformerName or a custom NSValueTransformer subclass of NSSecureUnarchiveFromDataTransformer

これは、これまでのvalue transformerが NSCoding を使ったものであるため非推奨になっており、 NSSecureCoding をベースとした NSSecureUnarchiveFromDataTransformer に置き換える必要があるということです。

今回この警告の対応のために調べた、 NSSecureUnarchiveFromDataTransformer を使ってtransformableな属性をセキュアに実装する方法をまとめました。

カスタムクラスが不要なパターン

NSSecureUnarchiveFromDataTransformer が扱える型は allowedTopLevelClasses で規定されていて、以下の通りです。

NSArray, NSDictionary, NSSet, NSString, NSNumber, NSDate, NSData, NSURL, NSUUID, NSNull

これらの型の組み合わせで表現できるもの、例えば文字列の配列 [String] の属性であれば、モデルエディタでTransformerの欄に NSSecureUnarchiveFromDataTransformerName を指定するだけでOKです。

カスタムクラスが必要なパターン

上に挙げた型以外の NSSecureCoding に準拠した標準の型(UIColor など)や、NSSecureCoding に準拠した独自の型を使う場合は、 NSSecureUnarchiveFromDataTransformer を継承したカスタムクラスを実装する必要があります。

// Core Dataで利用するために @objc が必要です
@objc final class SecureValueTransformer: NSSecureUnarchiveFromDataTransformer {

    // クラス名をvalue transformerのnameとします
    static let name = NSValueTransformerName(rawValue: String(describing: SecureValueTransformer.self))

    // superが返すクラスの配列に追加する形で使用するクラスを指定します
    override static var allowedTopLevelClasses: [AnyClass] {
        super.allowedTopLevelClasses + [
            UIColor.self,
            NSTimeZone.self,
            CustomTypeA.self,
            CustomTypeB.self,
        ]
    }

    // value transformerを登録する処理です。Core Data Stackの初期化前に呼びます。
    public static func register() {
        let transformer = SecureValueTransformer()
        ValueTransformer.setValueTransformer(transformer, forName: name)
    }

}

モデルエディタではTransformerの欄に name で指定したクラス名を入力します。

最後にCore Data Stackの初期化前に以下を実行して、value transformerを登録します。

SecureValueTransformer.register()

参考リンク

gonsee
カレンダーシェアアプリ「TimeTree」のiOSアプリを開発しています。個人では「陣痛時計」、「ごみの日アラーム」というアプリをリリースしています。Perfumeエバンジェリスト。
https://simplebeep.net/iphone-apps
jubileeworks
「毎日に、新しい"なくてはならない"を創る」を経営理念に掲げ、共有カレンダーサービス TimeTree の開発・運営をしています。
https://timetreeapp.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした