消息已发送到已释放的实例

时间:2014-08-29 22:53:49

标签: ios objective-c ipad methods game-center

我正在使用游戏中心在两个玩家之间发送数据。出于某种原因,我不断获得一个解除分配的实例消息。这是代码:

- (void)sendGameMove:(uint32_t)i andj:(NSString *)j {

    MessageMove message;
    message.message.messageType = kMessageTypeMove;
    message.i = 1;
    message.j = @"Testing 1 2 3s";
    NSData *data = [NSData dataWithBytes:&message length:sizeof(MessageMove)];
    MessageMove * messageMove = (MessageMove *) [data bytes];
    NSLog(@"Message I: %i", messageMove->i);
    NSLog(@"Message J: %@", messageMove->j);
    [self sendData:data];

}

(我填写了i和j参数,我正在通过)。在这个方法中,NSLog语句既记录了创建NSData对象之后的内容,又记录了我将NSData对象发送到方法[self sendData:data]:

- (void)sendData:(NSData *)data {
    MessageMove * messageMove = (MessageMove *) [data bytes];
    NSLog(@"Message I: %i", messageMove->i);
    NSLog(@"Message J: %@", messageMove->j);
    NSError *error;
    BOOL success = [[GCHelper sharedInstance].match sendDataToAllPlayers:data     withDataMode:GKMatchSendDataReliable error:&error];
    if (!success) {
        [self matchEnded];
    }

}

在NSLog语句中,第一个工作正常,所以我得到:

"Message I: 1"
在控制台中

但是对于我得到的第二个日志语句:

"*** -[ respondsToSelector:]: message sent to deallocated instance"

分解数据对象的代码与第一种方法完全相同。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

我猜测MessageMove是一个类似的结构:

typedef struct {
    int i;
    NSString *j;
} MessageMove;

问题在于您只发送结构本身的内容。在内存和网络上,它看起来像这样:

01000000 07FCA700
-----------------
i        j

当第二个设备收到消息并尝试读取j指针时,它会崩溃,因为那里没有任何东西:该指针仅在原始设备上有效。该结构甚至根本不包含字符串的内容。

要解决此问题,您需要在邮件中实际发送字符串。灵活的数组成员是直接在结构中存储字符串的一种方法:

typedef struct {
    int32_t i; // explicit integer sizes are a good idea for network protocols
    int32_t j_length;
    char j[]; // the flexible array member
} MessageMove;

发送:

NSString *s = @"Testing 1 2 3s";
NSData *d = [s dataUsingEncoding:NSUTF8StringEncoding];
size_t messageSize = sizeof(MessageMove) + [d length];
MessageMove *mm = calloc(1, messageSize);
mm->i = 1;
mm->j_length = [d length];
memcpy(mm->j, [d bytes], [d length]);
[self sendData:[NSData dataWithBytes:mm length:messageSize]];

接收:

MessageMove *mm = (MessageMove *)[data bytes];
assert(mm->j_length == [data length] - offsetof(MessageMove, j));
NSString *j = [[NSString alloc] initWithBytes:mm->j length:mm->j_length encoding:NSUTF8StringEncoding];

断言阻止读取超过data缓冲区的末尾。 offsetof是来自<stddef.h>的宏。


对于比这更复杂的事情,我建议序列化并发送plist或JSON。它们为您处理所有字符串复制细节,并允许您发送数组和字典。