1

我正在努力解决一个问题。我想向连接的设备发送一个结构。

这是我使用复制到 Playground 的代码

在代码中,我为 Data 类添加了一些扩展以进行编码/解码。我创建了一个 [String:Player] 字典并使用 NSKeyedArchiver 创建要发送的数据记录。

我不在这里发送,但在我的程序中我这样做。在操场上,代码/解码工作正常。当我在我的程序中执行此操作时,从数据中提取播放器时解码失败。它失败了:EXC_BAD_ACCESS

如果我使用 String 而不是 Player 结构,它会在 didReceive 数据函数中很好地解码。仅在使用 Struct 时失败。

有人有一些建议吗?

//: Playground - noun: a place where people can play
import UIKit

// Player structure
struct Player {
    var initials : String
    var name : String
}

//
// Data extension
//
extension Data {

    // struct
    init<T>(from value: T) {
        var value = value
        self.init(bytes: &value, count: MemoryLayout<T>.size)
    }

    // extract Struct
    func extract<T>(from: T.Type) -> T {
        return self.withUnsafeBytes { $0.pointee }   // FAILS HERE: EXC_BAD_ACCESS
    }
}

// Make a data record for sending
let sply = Player(initials: "PN", name: "Player Name")
let spda = Data(from: sply)
let sdic : [String:Data] = ["Player" : spda]
let sdta : Data = NSKeyedArchiver.archivedData(withRootObject: sdic)

// Do the sending
// ... send...

//Decode
// The following code that is used on the receiving device in 
// the "didReceive data" function.
let rdic = NSKeyedUnarchiver.unarchiveObject(with: sdta) as! [String : Data]
let rdta = rdic["Player"]!
let rply = rdta.extract(from: Player.self)
print(rply.name)        // Prints: "Player Name"
4

1 回答 1

2

对我有用的是一个继承自 NSObject 并符合 NSCoding 的自定义类。

class Player: NSObject, NSCoding {
    var initials: String!
    var name: String!

    required convenience init(coder decoder: NSCoder) {
        self.init()
        self.initials = decoder.decodeObject(forKey: "initials") as! String
        self.name = decoder.decodeObject(forKey: "name") as! String
    }

    convenience init(initials: String, name: String) {
        self.init()
        self.initials = initials
        self.name = name 
    }

    func encode(with aCoder: NSCoder) {
        if let initials = initials { aCoder.encode(initials, forKey: "initials") }
        if let name = name { aCoder.encode(name, forKey: "name") }
    }
}

制作要发送的数据:

let data = NSKeyedArchiver.archivedData(withRootObject: Player(initials: "PN", name: "Player Name"))

将数据返回给 Player:

guard let player: Player = NSKeyedUnarchiver.unarchiveObject(with: data) as! Player? else { return }
于 2017-07-07T21:07:40.277 回答