How to save an array of custom struct to NSUserDefault with swift?

前端 未结 3 1342
情歌与酒
情歌与酒 2020-12-17 03:32

I have an custom struct called \'News\' that I want to append into the array to NSUserDefault. But it\'s showing error \"Type \'News\' does not conform to protocol \'AnyObje

相关标签:
3条回答
  • 2020-12-17 04:21

    NSUserDefaults can only save a very small set of types: NSData, NSString, NSNumber, NSDate, NSArray containing only these types, or NSDictionary containing only these types. So your best bet is to encode your struct using an NSKeyedUnarchiver, which required a value that conforms to NSCoding. You could make your type conform to this, but I think it's cleaner to hide that from your users and simply have a private class for the internal representation, like this:

    struct Foo {
        var a : String
        var b : String?
    }
    
    extension Foo {
        init?(data: NSData) {
            if let coding = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? Encoding {
                a = coding.a as String
                b = coding.b as String?
            } else {
                return nil
            }
        }
    
        func encode() -> NSData {
            return NSKeyedArchiver.archivedDataWithRootObject(Encoding(self))
        }
    
        private class Encoding: NSObject, NSCoding {
            let a : NSString
            let b : NSString?
    
            init(_ foo: Foo) {
                a = foo.a
                b = foo.b
            }
    
            @objc required init?(coder aDecoder: NSCoder) {
                if let a = aDecoder.decodeObjectForKey("a") as? NSString {
                    self.a = a
                } else {
                    return nil
                }
                b = aDecoder.decodeObjectForKey("b") as? NSString
            }
    
            @objc func encodeWithCoder(aCoder: NSCoder) {
                aCoder.encodeObject(a, forKey: "a")
                aCoder.encodeObject(b, forKey: "b")
            }
    
        }
    }
    

    Then to save your array you can simply map .encode over your array:

    let fooArray = [ Foo(a: "a", b: "b"), Foo(a: "c", b: nil) ]
    let encoded = fooArray.map { $0.encode() }
    NSUserDefaults.standardUserDefaults().setObject(encoded, forKey: "my-key")
    

    and to get it back you can simply pass the NSData to the init:

    let dataArray = NSUserDefaults.standardUserDefaults().objectForKey("my-key") as! [NSData]
    let savedFoo = dataArray.map { Foo(data: $0)! }
    
    0 讨论(0)
  • 2020-12-17 04:22

    WORKING IN SWIFT 3

    Following a similar approach to ahruss, I ended up implementing in the following way:

    struct MyObject {
        var foo : String
        var bar : String?
    }
    
    extension MyObject {
        init?(data: NSData) {
            if let coding = NSKeyedUnarchiver.unarchiveObject(with: data as Data) as? Encoding {
                foo = coding.foo as String
                bar = coding.bar as String?
            } else {
                return nil
            }
        }
    
        func encode() -> NSData {
            return NSKeyedArchiver.archivedData(withRootObject: Encoding(self)) as NSData
        }
    
        private class Encoding: NSObject, NSCoding {
            let foo : NSString
            let bar : NSString?
    
            init(_ myObject: MyObject) {
                foo = myObject.foo
                bar = myObject.bar
            }
    
            @objc required init?(coder aDecoder: NSCoder) {
                if let foo = aDecoder.decodeObject(forKey: "foo") as? NSString {
                    self.foo = foo
                } else {
                    return nil
                }
                bar = aDecoder.decodeObject(forKey: "bar") as? NSString
            }
    
            @objc func encode(with aCoder: NSCoder) {
                aCoder.encode(foo, forKey: "foo")
                aCoder.encode(bar, forKey: "bar")
            }
    
        }
    }
    

    Oh, and to use it just type the following:

    let myObject = MyObject(foo: "foo", bar: "bar")
    UserDefaults.standard.set(myObject.encode(), forKey: "test")
    

    To fetch it,

    let objectData = UserDefaults.standard.object(forKey: "test") as? Data?
    guard let storedObject = objectData else {
        return
    }
    let fetchedObject: MyObject = MyObject(data: storedObject as NSData)
    
    0 讨论(0)
  • 2020-12-17 04:23

    Following is the flow that I have follow

    1. Make your struct object
    2. Convert struct to Json object (I will give you file link to convert struct to JsonObject and jsonString -> https://github.com/vijayvir/SwiftApi/blob/master/StructureToJson/StructToJson.swift ) import this file in your project :-)
    3. Append that value to array
    4. If you want to save in user default I prefer you to make class object of array as follow ,(as you can access from any where )

    5. save your array in user default as follow

    Struct to save

    struct CardDetails : StructJSONSerializable {
    var emailId :String
    
    var accountNo : String
    
    var expDate : String
    
    var cvc : String
    
    var isCurrrent : Bool = false      
    
    
    init(card : Dictionary<String, Any>  )
    {
        emailId =  card["emailId"]! as! String
    
        accountNo =  card["accountNo"]! as! String
    
        expDate  =  card["expDate"]! as! String
    
        cvc =  card["cvc"]! as! String
    
        isCurrrent = card["isCurrrent"]! as! Bool
    
    }
    
     }
    

    Save Array to User Default

      class var  cards : [AnyObject] {
        get
            {
                if (UserDefaults.standard.object(forKey:"cardss") != nil)
                {
    
                if let data = UserDefaults.standard.object(forKey: "cardss") as? Data
                {
                    let unarc = NSKeyedUnarchiver(forReadingWith: data)
    
                    let newBlog = unarc.decodeObject(forKey: "root")
    
    
    
                    return newBlog as! [AnyObject]
                }
                else
                {
                    return []
                }
    
              }
                else
                {
                return []
                }
    
            }
    
        set
        {
            //print(type(of: newValue) , newValue)
    
            let archiveData = NSKeyedArchiver.archivedData(withRootObject: newValue)
    
              let ud = UserDefaults.standard
              ud.set(  archiveData  ,forKey: "cardss")
              ud.synchronize()
        }
    
    }
    

    How to save Struct element to array Here convert you struct object to json Object

         let  firstCard = CardDetails(emailId: "asdf",
                                     accountNo: "dada",
                                     expDate: "nvn",
                                     cvc: "e464w",
                                     isCurrrent: true)
    
          CardsViewController.cards.append(firstCard.toJsonObect())
    

    How to access object from array Here convert you json Object object to Struct

    let sameCardIs = CardDetails(card:  CardsViewController.cards.last
    as! Dictionary<String, Any>)
    
    
    
        print ("Element Function " , sameCardIs )
    

    :-)

    0 讨论(0)
提交回复
热议问题