如何将包含字符串的消息struct作为游戏中心的NSData发送

时间:2015-04-05 19:21:20

标签: swift game-center

我正在尝试创建一个多人游戏,使用Game Center在玩家之间发送动作。我还在学习很多关于编程的知识,所以如果我的问题不正确,请原谅。另外,我对Obj-C不太熟悉,所以Swift的答案会很棒。

在我尝试自学的玩具程序中,我试图遵循Shayne Meyer使用GameKitHelper类所使用的策略:https://github.com/shaynemeyer/SwiftCircuitRacer/tree/master/SwiftCircuitRacer

使用这种方法,Shayne使用作为NSData发送的结构在线向其他玩家发送消息。我能够发送整数(例如,ILoveYou消息)但不能发送带有字符串属性的消息(例如,Thanks消息)。在后一种情况下,我在“var messageThanks = UnsafePointer,MesssageThanks>(data.bytes).memory”

这一行得到“Thread 1:EXC_BAD_ACCESS(code = 1,address = 0x78674100)”

最终,我想发送同时提供字符串和整数的游戏动作。当属性还包含字符串时,如何将消息结构作为NSData发送?其次,如果有人能够帮助我从根本上了解数据打包时的情况以及UnsafePointer正在做什么,因为它与通过Game Center发送数据有关,我将不胜感激。

谢谢。 崖

enum MessageType: Int {
    case ILoveYou, Thanks
}

struct Message {
    let messageType: MessageType
}    
struct MessageILoveYou {
    let message: Message
    let messageSenderNumber: UInt32    
}

struct MessageThanks {
    let message: Message
    let messageSenderName: String
    let messageSenderNumber: UInt32    
}

func sendILoveYou() {    
    println("sendILoveYou:")
    let nameNumber = UInt32(56)
    var message = MessageILoveYou(message: Message(messageType: MessageType.ILoveYou), messageSenderNumber: nameNumber)
    let data = NSData(bytes: &message, length: sizeof(MessageILoveYou))
    sendData(data)    
}

func sendThanks() {
    println("sendThanks:")
    let nameString = "Don J"
    let senderNumberInt = UInt32(88)
    var message = MessageThanks(message: Message(messageType: MessageType.Thanks), messageSenderName: nameString, messageSenderNumber: senderNumberInt)        
    let data = NSData(bytes: &message, length: sizeof(MessageThanks))
    sendData(data)        
}

func matchReceivedData(match: GKMatch, data: NSData, fromPlayer player: String) {

    println("matchReceivedData:")
    var message = UnsafePointer<Message>(data.bytes).memory        
    if message.messageType == MessageType.ILoveYou {            
        println("messageType == ILoveYou")
        let messageILoveYou = UnsafePointer<MessageILoveYou>(data.bytes).memory
        iLoveYouThanksDelegate?.iLoveYouReceived(from: messageILoveYou.messageSenderNumber)

    } else if message.messageType == MessageType.Thanks {            
        println("messageType == Thanks")
        var messageThanks = UnsafePointer<MessageThanks>(data.bytes).memory
        iLoveYouThanksDelegate?.thanksReceived(from: messageThanks.messageSenderName)
    }
}

func sendData(data: NSData) {
    var sendDataError: NSError?
    let gameKitHelper = GameKitHelper.sharedInstance

    if let multiplayerMatch = gameKitHelper.multiplayerMatch {
        let success = multiplayerMatch.sendDataToAllPlayers(data, withDataMode: .Reliable, error: &sendDataError)
        if !success {
            if let error = sendDataError {
                println("Error:\(error.localizedDescription)")
                matchEnded()
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

这里的问题是,当你在Swift中创建一个String时,它会自己分配一些内存,然后使用该内存来存储字符串的实际字符。字符串值实际上保存的是一些数据,表示指向该内存的指针和一些其他信息(例如已分配了多少内存,以便可以正确释放它。

你可以在这里看到:

let str = "This is quite a long string, certainly more than 24 bytes"
sizeofValue(str)  // and yet this only returns 24

当你将变量填充到NSData对象中时,初始化器会获取一个指针,该指针指向保存这些指针的字符串变量的内存,字符本身:

// only storing those 24 bytes, not the actual string
let data = NSData(bytes: &str, length: sizeofValue(str))

注意,bytes参数的类型为UnsafePointer<Void>。这表明你正在进入棘手的领域。

然后,当您在另一端解组数据时,您的所有接收器都将获得随机存储器的一些指示(遗憾的是,其他用户设备上的内存!)

如果要将字符串值放入NSData对象,则需要先将它们编组为原始数据。例如,您可以将它们编码为数组:

let data = Array(str.utf8).withUnsafeBufferPointer { buf in
    NSData(bytes: buf.baseAddress, length: buf.count)
}

碰巧,因为这是一个常见的事情,有一种方法可以直接这样做:

let data = str.dataUsingEncoding(NSUTF8StringEncoding)

然后,要解压缩数据,可以使用NSString对象中的NSData构造函数:

let newStr = NSString(data: data, encoding: NSUTF8StringEncoding)

编辑:如果你想在一个NSData中编码不仅仅是一个字符串,你可以沿着这些方向做点什么...我应该说,我自己从来没有这样做过,所以我在不熟悉这方面的标准做法,可能有更好的技术或辅助类/功能。希望有经验的人可以编辑以显示如何正确地执行此操作:)

var type = MessageType.Thanks

// start the data with the type
let data = NSMutableData(bytes: &type, length: sizeofValue(type))

// then append the string
data.appendData(Array(str.utf8).withUnsafeBufferPointer { buf in
    NSMutableData(bytes: buf.baseAddress, length: buf.count)
    })

switch UnsafePointer<MessageType>(data.bytes).memory {
case .ILoveYou:
// ...
case .Thanks:
    let str = NSString(data: data.subdataWithRange(NSMakeRange(1, data.length-1)), encoding: NSUTF8StringEncoding)
}