web-dev-qa-db-ja.com

NSKeyedUnarchiver unarchivedObject(ofClass:from :)による配列のアーカイブ解除

Swift 4.2にアップグレードしてから、NSKeyedUnarchiverおよびNSKeyedArchiverメソッドの多くが廃止され、データをアーカイブ解除するためにtypeメソッドstatic func unarchivedObject<DecodedObjectType>(ofClass: DecodedObjectType.Type, from: Data) -> DecodedObjectType?を使用する必要があることがわかりました。

NSObjectサブクラスである、オーダーメイドクラスWidgetDataの配列を正常にアーカイブできました。

private static func archiveWidgetDataArray(widgetDataArray : [WidgetData]) -> NSData {

    guard let data = try? NSKeyedArchiver.archivedData(withRootObject: widgetDataArray as Array, requiringSecureCoding: false) as NSData
        else { fatalError("Can't encode data") }

    return data

}

このデータは、このデータをアーカイブ解除しようとすると発生します。

static func loadWidgetDataArray() -> [WidgetData]? {

    if isKeyPresentInUserDefaults(key: USER_DEFAULTS_KEY_WIDGET_DATA) {

        if let unarchivedObject = UserDefaults.standard.object(forKey: USER_DEFAULTS_KEY_WIDGET_DATA) as? Data {

            //THIS FUNCTION HAS NOW BEEN DEPRECATED:
            //return NSKeyedUnarchiver.unarchiveObject(with: unarchivedObject as Data) as? [WidgetData]

            guard let nsArray = try? NSKeyedUnarchiver.unarchivedObject(ofClass: NSArray.self, from: unarchivedObject as Data) else {
                fatalError("loadWidgetDataArray - Can't encode data")
            }

            guard let array = nsArray as? Array<WidgetData> else {
                fatalError("loadWidgetDataArray - Can't get Array")
            }

            return array

        }

    }

    return nil

}

ただし、Array.selfの代わりにNSArray.selfを使用することは許可されていないため、これは失敗します。何が間違っているのですか?これを修正してアレイをアーカイブ解除するにはどうすればよいですか?

9
Geoff H

unarchiveTopLevelObjectWithData(_:)を使用して、archivedData(withRootObject:requiringSecureCoding:)によってアーカイブされたデータをアーカイブ解除できます。 (これはまだ非推奨ではないと思います。)

ただし、コードを表示する前に、次のことを改善する必要があります。

  • NSDataの使用を避け、代わりにDataを使用してください

  • 使用を避ける try?デバッグに役立つエラー情報を破棄します

  • 不要なキャストをすべて削除する


これを試して:

private static func archiveWidgetDataArray(widgetDataArray : [WidgetData]) -> Data {
    do {
        let data = try NSKeyedArchiver.archivedData(withRootObject: widgetDataArray, requiringSecureCoding: false)

        return data
    } catch {
        fatalError("Can't encode data: \(error)")
    }

}

static func loadWidgetDataArray() -> [WidgetData]? {
    guard
        isKeyPresentInUserDefaults(key: USER_DEFAULTS_KEY_WIDGET_DATA), //<- Do you really need this line?
        let unarchivedObject = UserDefaults.standard.data(forKey: USER_DEFAULTS_KEY_WIDGET_DATA)
    else {
        return nil
    }
    do {
        guard let array = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(unarchivedObject) as? [WidgetData] else {
            fatalError("loadWidgetDataArray - Can't get Array")
        }
        return array
    } catch {
        fatalError("loadWidgetDataArray - Can't encode data: \(error)")
    }
}

ただし、新しいアプリを作成する場合は、Codableの使用を検討する必要があります。

19
OOPer
_unarchiveTopLevelObjectWithData(_:) 
_

廃止されました。したがって、安全なコーディングなしでデータをアーカイブ解除するには、次のことが必要です。

  1. init(forReadingFrom: Data)NSKeyedUnarchiverを作成します
  2. 作成されたアンアーカイバのrequiresSecureCodingをfalseに設定します。
  3. decodeObject(of: [AnyClass]?, forKey: String) -> Any?を呼び出してオブジェクトを取得し、適切なクラスとNSKeyedArchiveRootObjectKeyasキーを使用するだけです。
6
Maciej S
 if #available(iOS 12.0, *) {
        guard let unarchivedFavorites = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(favoritesData!)
            else {
                return
        }
        self.channelFavorites = unarchivedFavorites as! [ChannelFavorite]
    } else {
        if let unarchivedFavorites = NSKeyedUnarchiver.unarchiveObject(with: favoritesData!) as? [ChannelFavorite] {
            self.channelFavorites = unarchivedFavorites
        }

//データの達成

 if #available(iOS 12.0, *) {
            // use iOS 12-only feature
            do {
                let data = try NSKeyedArchiver.archivedData(withRootObject: channelFavorites, requiringSecureCoding: false)
                UserDefaults.standard.set(data, forKey: "channelFavorites")
            } catch {
                return
            }
        } else {
            // handle older versions
            let data = NSKeyedArchiver.archivedData(withRootObject: channelFavorites)
            UserDefaults.standard.set(data, forKey: "channelFavorites")
        }

これは私が私のコードを更新し、私のために働いている方法です

3
user1828845

あなたはおそらくこれを探しています:

if let widgetsData = UserDefaults.standard.data(forKey: USER_DEFAULTS_KEY_WIDGET_DATA) {
        if let widgets = (try? NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSArray.self, WidgetData.self], from: widgetsData)) as? [WidgetData] {
            // your code
        }
    }
1
Hopreeeenjust