如何在swift中对NSData进行编码和解码?

时间:2016-01-13 15:30:20

标签: ios swift sqlite

我有以下结构定义:

struct ThreadManager: Equatable {
  let fid: Int
  let date: NSDate
  let forumName: String
  let typeid: Int
  var page: Int
  var threadList: [Thread]
  var totalPageNumber: Int?
}

,主题是:

  struct Thread: Equatable {
    let author: Author
    let replyCount: Int
    let readCount: Int
    let title: String
    let tid: Int
    let isTopThread: Bool
    var attributedStringDictionary: [String: NSAttributedString]
    var postDescripiontTimeString: String
    var hasRead: Bool
}

如何将ThreadManager变量编码为NSData?我尝试使用以下函数,但它没有工作。

func encode<T>(var value: T) -> NSData {
  return withUnsafePointer(&value) { p in
    NSData(bytes: p, length: sizeofValue(value))
  }
}

func decode<T>(data: NSData) -> T {
  let pointer = UnsafeMutablePointer<T>.alloc(sizeof(T))
  data.getBytes(pointer, length: sizeof(T))

  return pointer.move()
}

我有ThreadManager项目,我想将它们存储到sqlite中。所以我需要将它们转换为NSData。我有一个名为threadManager的变量,其threadList中的项目数约为70.我运行代码并设置断点,并在xcode控制台中输入encode(threadManager),它只有73bytes。这是错误的。如何编码和解码这些结构到NSData。

2 个答案:

答案 0 :(得分:4)

如果要在任何其他平台(Android,Web,无论何处)上读取您的数据库,您最好选择跨平台格式(如JSON),或将结构成员分布在数据库表的专用列中

如果你只针对iOS / OSX / tvOS /等,我推荐NSCoder。这是有效的,最重要的是:

  1. NSCoder与平台无关,这意味着您的NSData编码和解码不依赖于平台当前使用的特定内存布局。例如,您不必担心32/64位兼容性。
  2. NSCoder允许您随着时间的推移更改类型,同时保持导入旧版本结构的能力。
  3. 下面的代码为您的结构添加了asData()函数,并添加了init(data:)初始值设定项。这两个让你从你的结构来回走向NSData。

    import Foundation
    
    struct MyStruct {
        let name: String
        let date: NSDate
    }
    
    extension MyStruct {
        init(data: NSData) {
            let coding = NSKeyedUnarchiver.unarchiveObjectWithData(data) as! Coding
            name = coding.name as String
            date = coding.date
        }
    
        func asData() -> NSData {
            return NSKeyedArchiver.archivedDataWithRootObject(Coding(self))
        }
    
        class Coding: NSObject, NSCoding {
            let name: NSString
            let date: NSDate
    
            init(_ myStruct: MyStruct) {
                name = myStruct.name
                date = myStruct.date
            }
    
            required init?(coder aDecoder: NSCoder) {
                self.name = aDecoder.decodeObjectForKey("name") as! NSString
                self.date = aDecoder.decodeObjectForKey("date") as! NSDate
            }
    
            func encodeWithCoder(aCoder: NSCoder) {
                aCoder.encodeObject(name, forKey: "name")
                aCoder.encodeObject(date, forKey: "date")
            }
        }
    }
    
    let encodedS = MyStruct(name: "foo", date: NSDate())
    let data = encodedS.asData()
    let decodedS =  MyStruct(data: data)
    print(decodedS.name)
    print(decodedS.date)
    

答案 1 :(得分:0)

@GwendalRoué:你是对的,但我必须根据每个结构构建另一个类。我使用了以下方法,它很难看,但它有效。你能帮我改进一下吗?

init(data: NSData) {
    let dictionary = NSKeyedUnarchiver.unarchiveObjectWithData(data) as! NSDictionary
    fid = (dictionary["fid"] as! NSNumber).integerValue
    date = dictionary["date"] as! NSDate
    forumName = dictionary["forumName"] as! String
    typeid = (dictionary["typeid"] as! NSNumber).integerValue
    page = (dictionary["page"] as! NSNumber).integerValue
    totalPageNumber = (dictionary["totalPageNumber"] as? NSNumber)?.integerValue
    let threadDataList = dictionary["threadDataList"] as! [NSData]
    threadList = threadDataList.map { Thread(data: $0) }
}
extension ThreadManager {
func encode() -> NSData {
    let dictionary = NSMutableDictionary()
    dictionary.setObject(NSNumber(integer: fid), forKey: "fid")
    dictionary.setObject(date, forKey: "date")
    dictionary.setObject(forumName, forKey: "forumName")
    dictionary.setObject(NSNumber(integer: typeid), forKey: "typeid")
    dictionary.setObject(NSNumber(integer: page), forKey: "page")
    if totalPageNumber != nil {
        dictionary.setObject(NSNumber(integer: totalPageNumber!), forKey: "totalPageNumber")
    }
    let threadDataList: [NSData] = threadList.map { $0.encode() }
    dictionary.setObject(threadDataList, forKey: "threadDataList")

    return NSKeyedArchiver.archivedDataWithRootObject(dictionary)
}
}