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

6

我有一个自定义结构体叫做“News”,我想将其附加到NSUserDefault数组中。 但是出现错误:“类型'News'不符合协议'AnyObject'”。

我不想将“News”结构体更改为类,因为它已被其他代码使用。 是否有任何办法可以将NSUserDefault.standardUserDefaults().arrayForKey(“savedNewsArray”)类型更改为[News]?

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

以下是'News'结构体。

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

2
请查看此文章 - Code Different
看一下 NSValue API。 - Evgeny Karkan
4个回答

14

NSUserDefaults只能保存一小部分类型的数据,包括:NSDataNSStringNSNumberNSDate、仅包含这些类型的NSArrayNSDictionary。因此,最好使用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)! }

3

以下是我所遵循的流程

  1. 创建你的结构体对象
  2. 将结构体转换为Json对象(我将给你转换struct到JsonObject和jsonString文件的链接 -> https://github.com/vijayvir/SwiftApi/blob/master/StructureToJson/StructToJson.swift),导入这个文件到你的项目中 :-)
  3. 将该值追加到数组中
  4. 如果你想保存在用户默认设置中,我建议您按照以下方式制作数组的类对象(因为您可以从任何地方访问它)

  5. 按照以下方式保存您的数组到用户默认设置中

要保存的结构体

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

}

如何将结构体元素保存到数组中 在这里,先将您的结构体对象转换为JSON对象

     let  firstCard = CardDetails(emailId: "asdf",
                                 accountNo: "dada",
                                 expDate: "nvn",
                                 cvc: "e464w",
                                 isCurrrent: true)

      CardsViewController.cards.append(firstCard.toJsonObect())

如何从数组中访问对象 这里将您的JSON对象转换为结构体

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



    print ("Element Function " , sameCardIs )

:-)


0

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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接