2016-01-13 81 views
2

我有以下結構定義:如何在swift中對struct NSData進行編碼和解碼?

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。

+1

只能使用指針,不能序列化類實例像'NSDate'和類似'String'的複雜類型。他們有通過參考存儲的數據。你將不得不逐個進行序列化。如果你想將數據存儲爲二進制blob,那麼我會建議考慮使用屬性列表。 –

回答

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) 
} 
} 
+0

使用字典是一個整潔的想法,可以防止創建自定義的NSCoding類,你是對的!如果你想改進它,我會寫'dic [「date」] = date'而不是'dic.setObject(...)'。但它是自動的:你的代碼已經很好了。 –

4

如果要在任何其他平臺(Android,Web,任何地方)上讀取數據庫,最好選擇跨平臺格式(如JSON),或將結構成員分散到數據庫的專用列中表。

如果你只是針對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) 
+0

你是對的,但我必須根據每個結構建立另一個類。我用下面的方法,它很醜,但它的工作原理。你能幫我改進嗎? – leizh00701

相關問題