NSKeyedUnarchiveFromDataに代わるカスタム値変換の実装について
主題
macOS 10.14 MojaveからDeprecateされた、NSKeyedUnarchiveFromDataに代わるカスタム値変換の実装について述べる。
背景
筆者が開発しているアプリの1つでは、テーブルのソート状態の保存にCocoa-Bindingsを用いている。ソート状態の保存の際、NSKeyedUnarchiveFromDataという値変換を用いてきたが、これはmacOS 10.14 MojaveからDeprecateされている。
本稿では、カスタム値変換の実装を通じて、この問題に対処する手順を述べる。
手順
-
カスタム値変換の実装
NSSecureUnarchiveFromDataTransformer
を継承するカスタム値変換を実装する。ファイル名はMyTransformer.swift
とする。
NSSecureUnarchiveFromDataTransformer
は、そのままではテーブルのソート状態(NSSortDescriptor)を扱えない。よってカスタム値変換は、テーブルのソートに応用するケースでは必須である。
各コードの説明は、コメントを参照されたい。// // MyTransformer.swift // SecureTransformer // // Created by 桃源老師 on 2020/12/03. // import Cocoa class MyTransformer: NSSecureUnarchiveFromDataTransformer { /* 値の逆変換ができるかどうかを規定するメソッド。(必須) できないのでfalse */ override class func allowsReverseTransformation() -> Bool { return false } /* 変換されたオブジェクトのクラスを規定するメソッド。(必須) NSArrayを返すので、NSArray.self (ObjC的には[NSArray class]) */ override class func transformedValueClass() -> AnyClass { return NSArray.self } /* NSSecureUnarchiveFromDataTransformerが扱える型を規定するクラス変数。 NSSortDescriptorを扱えるように拡張する。 */ override class var allowedTopLevelClasses: [AnyClass] { return [NSArray.self, NSSortDescriptor.self] } // 値の変換メソッド。(必須) override func transformedValue(_ value: Any?) -> Any? { // valueがnilであること=ソート状態未設定を考慮。 if let nonNilValue = value { // Data型かどうかをチェック guard let data = nonNilValue as? Data else { fatalError("Wrong data type: value must be a Data object; received \(type(of: nonNilValue))") } /* 以前アーカイブされた値(=UserDefaultsに保存された ソート状態)のデコードを行う。例外を投げるのでtryを つける。 */ let object = try? NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSArray.self, NSSortDescriptor.self], from: data) /* デコードされたデータが、[NSSortDescriptor]型かを チェック */ guard let sortDescriptors = object as? [NSSortDescriptor] else { fatalError("Failed to unarchive a [NSSortDescriptor] object!") } /* デコードされたデータに`allowEvaluation()`を設定。 デコード時点では、Evaluationは許可されていない。 Evaluation不許可だと、それが原因でクラッシュする。 */ for descriptor in sortDescriptors { descriptor.allowEvaluation() } return sortDescriptors } return value } } // NSValueTransformerNameへの"MyTransformer"の登録 extension NSValueTransformerName { static let myTransformerName = NSValueTransformerName(rawValue: "MyTransformer") }
-
ValueTransformerへの登録
カスタム値変換のValueTransformerへの登録は、アプリのごく初期状態で行う必要がある。よって、本稿ではAppDelegateのイニシャライザで行う。// // AppDelegate.swift // SecureTransformer // // Created by 桃源老師 on 2020/12/03. // import Cocoa @main class AppDelegate: NSObject, NSApplicationDelegate { /* カスタム値変換のValueTransformerへの登録をAppDelegateのイニシャライザで行う。 */ override init() { super.init() ValueTransformer.setValueTransformer( MyTransformer(), forName: .myTransformerName ) } func applicationDidFinishLaunching(_ aNotification: Notification) { // Insert code here to initialize your application } func applicationWillTerminate(_ aNotification: Notification) { // Insert code here to tear down your application } }
-
ArrayControllerの設定
Main.storyboard上で、ArrayControllerのSort Descriptorsに、カスタム値変換のクラス名を入力する。
以上。
この投稿へのトラックバック
トラックバックはありません。
- トラックバック URL
この投稿へのコメント