2016-01-13 2 views
2

У меня есть следующее определение структуры:Как закодировать и декодировать структуру в NSData в 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. Я запускаю код и устанавливаю точку останова, а входной код (threadManager) в консоли xcode - всего 73 байта. Это неверно. Как я могу кодировать и декодировать эти структуры в NSData.

+1

Вы не можете сериализовать экземпляры класса, такие как 'NSDate' и сложные типы, такие как' String', только с помощью указателей. У них есть данные, которые хранятся по ссылке. Вам придется идти по элементу, чтобы выполнить сериализацию. Если вы хотите сохранить данные в виде двоичного блока, я бы предложил рассмотреть список свойств. –

ответ

0

@ Gwendal Roué: вы правы, но я должен построить другой класс согласно каждой структуре. Я использовал следующий метод, он уродлив, но он работает. Можете ли вы помочь мне улучшить его?

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 (...) '. Но это bikeshedding: ваш код уже прекрасен. –

4

Если ваша база данных должна быть прочитана на любой другой платформе (Android, в Интернете, где бы вы ни находились), вам лучше выбрать межплатформенный формат, такой как 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

Смежные вопросы