簡體   English   中英

如何快速對NSData進行結構編碼和解碼?

[英]How to encode and decode struct to NSData in swift?

我有以下結構定義:

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),它只有73字節。 這是錯誤的。 我如何編碼和解碼那些結構到NSData。

如果要在任何其他平台(Android,Web,無論在何處)上讀取數據庫,則最好選擇跨平台格式(例如JSON),或者將struct成員散布在數據庫表的專用列中。

如果您僅針對iOS / OSX / tvOS / etc,則建議使用NSCoder。 它是有效的,最重要的是:

  1. NSCoder與平台無關,這意味着您的NSData編碼和解碼不依賴於平台當前使用的特定內存布局。 例如,您不必擔心32/64位兼容性。
  2. NSCoder使您可以隨着時間的推移更改類型,同時保持導入結構的舊版本的能力。

下面的代碼向您的結構中添加一個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)

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM