GKGameSession- saveData always fails with malloc error after getShareURLWithCompletionHandler

172 views Asked by At

I'm trying to incorporate GKGameSession into my Game Center game. I've tried several combinations of the following code: running the commands asynchronously, chaining them in the completion handlers, etc. Every time I see the same result: I can use saveData just fine until I've called getShareURLWithCompletionHandler. After that, any attempt to saveData throws an error.

Here's the simplest version of code that exhibits the problem:

CKContainer *defaultContainer = [CKContainer defaultContainer];
[GKGameSession createSessionInContainer:defaultContainer.containerIdentifier
                              withTitle:@"temp title"
                    maxConnectedPlayers:4
                      completionHandler:^(GKGameSession * _Nullable session, NSError * _Nullable error)
{
    if (error)
    {
        [self printError:error];
    }

    [session getShareURLWithCompletionHandler:^(NSURL * _Nullable url, NSError * _Nullable error)
    {
        if (error)
        {
            [self printError:error];
        }
    }];


    NSData *newData = [NSData dataWithBytesNoCopy:@"abcdefghijklmnopqrstuvwxyz" length:26];
    [reSession saveData:newData completionHandler:^(NSData * _Nullable conflictingData, NSError * _Nullable error)
    {
            if (error)
            {
                [self printError:error];
            }
    }];


}];

In most cases, the saveData call simply crashes:

malloc: *** error for object 0x32df14: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug

But sometimes it throws an error:

GKGameSessionErrorDomain:GKGameSessionErrorUnknown

I've tried different kinds of data being saved. I've tried making the calls sequential by chaining all the calls in completion handlers. I've tried doing the URL fetch and data save inside and outside of the creationSession completion handler.

Is there something I'm doing wrong here?

2

There are 2 answers

4
Graham Perks On BEST ANSWER

I see the same, but with a more useful error:

The requested operation could not be completed because the session has been updated on the server, causing a conflict.

The save documentation says,

It is up to the developer to decide how to handle save conflicts.

Here though, retrying the save fails every time, forever. So yeah, that's the same state you're in.

However, when the player joining the game enters the URL on their device, their GKGameSessionEventListener's didAddPlayer: is called, and then if they save... they get the same conflict error, but if they then retry the save... it works!

The player creating the link is locked out of saving or updating game state, until joining players have updated the data. When the other player saves, the original player gets a call to session:player:didSave: on the GKGameSessionEventListener.

At that point the original player can then save as expected.

1
Andrey Tozik On

You should put one block inside other. Because blocks may be completed in any order.

I have working code like this:

NSData *newData = [NSData dataWithBytesNoCopy:@"abcdefghijklmnopqrstuvwxyz" length:26];
[reSession saveData:newData completionHandler:^(NSData * _Nullable conflictingData, NSError * _Nullable error)
{
        if (error)
        {
            [self printError:error];
        } else {
[session getShareURLWithCompletionHandler:^(NSURL * _Nullable url, NSError * _Nullable error)
{
    if (error)
    {
        [self printError:error];
    }
}];

} }];