如何使用swift将自定义结构数组保存到NSUserDefault?

时间:2016-07-16 00:00:57

标签: arrays swift struct swift2 nsuserdefaults

我有一个名为' News'的自定义结构。我想将数据附加到NSUserDefault。但它显示错误" Type' News'不符合协议' AnyObject'"。

我不想改变'新闻' struct to a class,因为它已经用于其他代码。无论如何我可以将NSUserDefaults.standardUserDefaults()。arrayForKey(" savedNewsArray")类型更改为[新闻]?

var savedNews = NSUserDefaults.standardUserDefaults().arrayForKey("savedNewsArray")
var addSavedNews = savedNews as? [News]
addSavedNews.append(News(id: "00", title: newsTitle, source: source, imageURL: imageURL, url: url))
NSUserDefaults.standardUserDefaults().setObject(addSavedNews, forKey: "savedNewsArray")
NSUserDefaults.standardUserDefaults().synchronize()

这是'新闻'结构

public struct News {
    public var id: String
    public var title: String
    public var source: String?
    public var imageURL: String?
    public var date: NSDate?
    public var url: String

    init(id: String, title: String, source: String, imageURL: String, url: String) {
        self.id = id
        self.title = title
        self.source = source
        self.imageURL = imageURL
        self.url = url
    }
}

3 个答案:

答案 0 :(得分:14)

NSUserDefaults只能保存一小组类型:NSStringNSNumberNSDateNSArrayNSDictionary仅包含这些类型,或{ {1}}仅包含这些类型。因此,最好的办法是使用NSKeyedUnarchiver对结构进行编码,这需要一个符合NSCoding的值。你可以让你的类型符合这一点,但我认为从你的用户隐藏它并且只是为内部表示创建一个私有类更清晰,如下所示:

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")
        }

    }
}

然后,为了保存您的数组,您只需在数组上映射.encode

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")

要将其恢复,您只需将NSData传递给init:

即可
let dataArray = NSUserDefaults.standardUserDefaults().objectForKey("my-key") as! [NSData]
let savedFoo = dataArray.map { Foo(data: $0)! }

答案 1 :(得分:3)

以下是我遵循的流程

  1. 制作您的结构对象
  2. 将struct转换为Json对象(我​​将为您提供文件     链接转换结构到JsonObject和jsonString - > https://github.com/vijayvir/SwiftApi/blob/master/StructureToJson/StructToJson.swift)在您的项目中导入此文件: - )
  3. 将该值附加到数组
  4. 如果你想保存在用户默认值中,我更喜欢你制作数组的类对象,如下所示(你可以从任何地方访问)

  5. 将数组保存为用户默认值,如下所示

  6. 要保存的结构

    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
    
    }
    
     }
    

    将数组保存为用户默认

      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()
        }
    
    }
    

    如何将Struct元素保存到数组  这里将struct对象转换为json Object

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

    如何从数组访问对象  这里将json Object对象转换为Struct

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

    :-)

答案 2 :(得分:0)

在SWIFT 3中工作

按照与ahruss类似的方法,我最终以下列方式实现:

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")
        }

    }
}

哦,使用它只需键入以下内容:

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

要获取它,

let objectData = UserDefaults.standard.object(forKey: "test") as? Data?
guard let storedObject = objectData else {
    return
}
let fetchedObject: MyObject = MyObject(data: storedObject as NSData)