简体   繁体   中英

How to save a Array with (Multiple Types) in NSUserDefaults

This is pretty simple but can't seem to find the correct information to solve saving an array like this in User Defaults.

It says it's not a property that NSUser Defaults Excepts.

Code:

    var notificationList: [(type: String,imageName: String, text: String, date: String, seen: Bool)] = [(type: "Default",imageName: "ClearPartioned", text: "", date: "", seen: true)]


    if (UserDefaults.standard.object(forKey: "notificationList")) == nil { // first time launching

        print("making notification list")

        UserDefaults.standard.set(notificationList, forKey: "notificationList")
        UserDefaults.standard.synchronize()

        print("\(notificationList)")

    } else {

        print("getting saved array")

        notificationList = (UserDefaults.standard.object(forKey: "notificationList") as! [(type: String, imageName: String, text: String, date: String, seen: Bool)])

        print("\(notificationList)")
    }

在此处输入图片说明

Update:

This is closer but gives error found in this question here . These are the closet answers I have been able to find and there either out dated or crash the system.

Code:

    if (UserDefaults.standard.object(forKey: "notificationList")) == nil { // first time launching

        print("making notification list")

        let encodedData = NSKeyedArchiver.archivedData(withRootObject: notificationList)
        UserDefaults.standard.set(encodedData, forKey: "notificationList")
        UserDefaults.standard.synchronize()

    } else {

        print("getting saved array")

        notificationList = (UserDefaults.standard.object(forKey: "notificationList") as! [(type: String, imageName: String, text: String, date: String, seen: Bool)])

        print("\(notificationList)")
    }

Update 2: This is best answer implementation From Dhiru

Code:

  if (UserDefaults.standard.object(forKey: "notificationList")) == nil { // first time launching
        print("making notification list")

        let notificationData = NSKeyedArchiver.archivedData(withRootObject: notificationList)
        UserDefaults.standard.set(notificationData, forKey: "notificationList")
        UserDefaults.standard.synchronize()

    } else {

        print("getting saved array")

        let decodedData  = UserDefaults.standard.object(forKey: "notificationList") as! Data
        let notificationList = NSKeyedUnarchiver.unarchiveObject(with: decodedData) as AnyObject

        print("\(notificationList)")
    }

Its giving me an error that crashes system

   *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x1c011f380'
   libc++abi.dylib: terminating with uncaught exception of type NSException

Im sure this code would fix it but this is horribly implemented with multiple errors below because I have no clue how to use this code.

Code:

   func (coder aDecoder: NSCoder) {
        if let notificationList = aDecoder.decodeObjectForKey("notificationList") {
            self.notificationList = notificationList
        }
    }

    func encodeWithCoder(aCoder: NSCoder) {
        if let notificationList = notificationList {
            aCoder.encodeObject(notificationList, forKey: "notificationList")
        }
    }

You have to store your Object in form of Data Convert into data using NSKeyedArchiver.archivedData(withRootObject:)

Convert back to Object using NSKeyedUnarchiver.unarchiveObject(with:)

Saving Data for UserDefaults

let notificationData = NSKeyedArchiver.archivedData(withRootObject: notificationList)
UserDefaults.standard.set(notificationData, forKey: "notificationList")

Retrive Data from User UserDefaults

let decodedData  = UserDefaults.standard.object(forKey: "notificationList") as! Data
let notificationList = NSKeyedUnarchiver.unarchiveObject(with: decodedData) as! AnyObject

This is how I actually save a Custom Object created in the app in Swift 4 .

First, we create 3 protocols for our purpose of saving the custom object in UserDefaults . The logic behind is to convert the Custom Object into a normalized Dictionary/Array form.

This can be applied to any kind of Object which you have created.

The 3 protocols are:

  1. Decoder (Used to decode the dictionary into custom object)
  2. Encoder (Used to encode the custom object into dictionary)
  3. UserDefaultsProtocol (Used to save, delete, update & retrieve the custom object from UserDefault )

Decoder Protocol

protocol Decoder {
    associatedtype T
    static func decode(dictionary: [String: Any]) -> T
}

Encoder Protocol

protocol Encoder {
    func encode() -> [String: Any]
}

UserDefaultsProtocol

protocol UserDefaultsDelegate: class {
    associatedtype T
    func saveToUserDefaults()
    static func removeFromUserDefaults()
    static func retrieveFromUserDefaults() -> T?
}

As per your question, NotificationList Object would look like this

class NotificationList {
    var type: String = ""
    var imageName: String = ""
    var text: String = ""
    var date: String = ""
    var seen: Bool = false
}

Now, you need to confirm all the 3 mentioned protocols to NotificationList . (Swift Best Practice: Use of Extensions & Protocols)

class NotificationList {
    private struct Constants {
        static let RootKey = "notification_list"
        static let TypeKey = "type"
        static let ImageNameKey = "image_name"
        static let TextKey = "text"
        static let DateKey = "date"
        static let SeenKey = "seen"
    }

    var type: String = ""
    var imageName: String = ""
    var text: String = ""
    var date: String = ""
    var seen: Bool = false

    typealias T = NotificationList
}

extension NotificationList: Encoder {
    func encode() -> [String : Any] {
        return [
            Constants.TypeKey: type,
            Constants.ImageNameKey: imageName,
            Constants.TextKey: text,
            Constants.DateKey: date,
            Constants.SeenKey: seen
        ]
    }
}

extension NotificationList: Decoder {
    static func decode(dictionary: [String: Any]) -> NotificationList {
        let type = dictionary[Constants.TypeKey] as! String
        let imageName = dictionary[Constants.ImageNameKey] as! String
        let text = dictionary[Constants.TextKey] as! String
        let date = dictionary[Constants.DateKey] as! String
        let seen = dictionary[Constants.SeenKey] as! Bool

        let notificationList = NotificationList()
        notificationList.type = type
        notificationList.imageName = imageName
        notificationList.text = text
        notificationList.date = date
        notificationList.seen = seen
        return notificationList
    }
}

extension NotificationList: UserDefaultsDelegate {

    func saveToUserDefaults() {
        UserDefaults.standard.setValue(encode(), forKey: Constants.RootKey)
    }

    static func retrieveFromUserDefaults() -> NotificationList? {
        guard let encodedNotificationList = UserDefaults.standard.dictionary(forKey: Constants.RootKey) else {
            return nil
        }
        return NotificationList.decode(dictionary: encodedNotificationList)
    }

    static func removeFromUserDefaults() {
        UserDefaults.standard.removeObject(forKey: Constants.RootKey)
    }
}

How to save NotificationList to UserDefaults?

var notificationList = NotificationList()
notificationList.type = "Default"
notificationList.imageName = "ClearPartioned"
notificationList.text = ""
notificationList.date = ""
notificationList.seen = true

Save to UserDefaults

notificationList.saveToUserDefaults()

Retrieve from UserDefaults

if let notificationList = NotificationList.retrieveFromUserDefaults() {
      // You will get the instance of notification list saved in UserDefaults
}

HOW TO SAVE ARRAY OF NOTIFICATION LIST?

Say notificationLists contains the array of notificationList objects.

var notificationListsArray = [[String: Any]]()

notificationLists.forEach {
     notificationListsArray.append($0.encode())
}

Save that array of dictionary to UserDefaults

UserDefaults.standard.setValue(notificationListsArray, forValue: "notificationLists")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM