Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
9
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

@gonsee

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()

参考リンク

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
9
Help us understand the problem. What are the problem?