I have the following struct definition:
struct ThreadManager: Equatable {
let fid: Int
let date: NSDate
let forumName: String
let typeid: Int
var page: Int
var threadList: [Thread]
var totalPageNumber: Int?
}
and the thread is :
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
}
How can I encode a ThreadManager variable to NSData? I tried to used the following functions, but it does not worK.
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()
}
I have ThreadManager items, and I want to store them into sqlite. So I need to convert them to NSData. I have a variable called threadManager, the number of items in its threadList is about 70. I run the code and set a breakpoint, and input encode(threadManager) in xcode console, it is only 73bytes. It is wrong. How can I encode and decode those struct to NSData.
If your database is to be read on any other platform (Android, the web, wherever), you'd better choosing a cross-platform format such as JSON, or spread your struct members in their dedicated columns in a database table.
If you only target iOS/OSX/tvOS/etc, I recommend NSCoder. It is efficient, and most importantly:
The code below adds a asData() function to your struct, and an init(data:) initializer. Those two let you go back and forth from your struct to 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)
@Gwendal Roué : you are right, but I have to build another class according to each struct. I used the following method, it is ugly, but it works. Can you help me to improve it?
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)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With