💊

NSKeyedUnarchiver.unarchivedObjectで[Int]などの配列を解凍するときのエラー対策

2023/03/05に公開

Xcode 14.2 iOS 16.3.1


[Int] を含むデータを

func archivedData(withRootObject object: Any, requiringSecureCoding requiresSecureCoding: Bool) throws -> Data

でアーカイブしたものを、アンアーカイブで取り出す時、

static func unarchivedObject(ofClasses classes: [AnyClass], from data: Data) throws -> Any?

を使うが、このとき classes の指定に NSArray.self , NSNumber.self を含むことが必要となる。ここは解凍時に解釈に使用するクラスを指定するものである。

モデル

class A: NSObject, NSSecureCoding {
	var b: [Int] = [1, 2, 3]
	
	override init() {
		super.init()
	}
	
	required init(coder aDecoder: NSCoder) {
		b = aDecoder.decodeObject(forKey: "b") as? [Int] ?? []
		super.init()
	}	
	
	func encode(with aCoder: NSCoder) {
		aCoder.encode(b, forKey: "b")
	}	
	
	static var supportsSecureCoding: Bool {
		true
	}	
}

処理部(対策後)

例によってファイルに書き込んですぐに取り出す。

let a = A() //モデルデータ
let fileURL = ファイルのURL
do {
	let data = try NSKeyedArchiver.archivedData(withRootObject: a, requiringSecureCoding: true)
	try data.write(to: fileURL)
} catch let e {
	print(e)
}
if let data = try? Data(contentsOf: fileURL) {
	do {
		let unarchived = try NSKeyedUnarchiver.unarchivedObject(
			ofClasses: [A.self, NSArray.self, NSNumber.self], 
			from: data) as? A
	} catch let e {
		print(e)
	}
}		

エラー文

NSArray.self , NSNumber.self を指定しなかった時のエラー文を記事の検索のために載せる。

Error Domain=NSCocoaErrorDomain Code=xxxx "value for key 'b' was of unexpected class 'NSArray' (アドレス) [/System/Library/Frameworks/CoreFoundation.framework].
Allowed classes are:
 {(
    "'TEST_StoreData.A' (アドレス) [/private/var/containers/Bundle/Application/アプリの番号/TEST_StoreData.app]"
)}"

bのキーで取り出した値はNSArrayという想定しないものである

想定しているのは以下である。
'TEST_StoreData.A'

と言っている。よって、想定に NSArray.self を加える。 NSNumber.self も同様のエラーが出るので同様に加える。加えた結果が上の「処理部(対策後)」である。

Discussion