iOS Save Game Getting Deleted or Corrupted Somehow

I’ve released a beta version of my game and users are complaining about save games being deleted. This is really confusing because I have never been able to reproduce the issue locally, save games for me always worked. I am not doing anything special. I init, load, and write my save game with the following code:

void ULlamagotchiGameInstance::InitSaveGame_Implementation()
{
	if (SaveInstance == nullptr)
	{
		if (!LoadSaveGame())
		{
			SaveInstance = CreateSaveGame();
			ensure(SaveInstance != nullptr);
			SaveInstance->bIsFirstLaunchInLevel = true;	   // Game launching for the first time
		}
	}
}

bool ULlamagotchiGameInstance::LoadSaveGame()
{
	SaveInstance = Cast<ULGSaveGame>(UGameplayStatics::LoadGameFromSlot(kGameSlotName, 0));
	return SaveInstance != nullptr;
}
bool ULlamagotchiGameInstance::WriteSaveGameToDisk(APetCharacter* Pet, ALlamagotchiPlayerController* PlayerController, APawn* PlayerPawn)
{
	if (!UpdateSaveInMemory(Pet, PlayerController, PlayerPawn))
	{
		UE_LOG(LogLgGameInstance, Log, TEXT("Savegame write to memory failed"));
		return false;
	}
	
	// Save game
	if(UGameplayStatics::SaveGameToSlot(SaveInstance, kGameSlotName, 0))
	{
		UE_LOG(LogLgGameInstance, Log, TEXT("Savegame successfully saved to disk"));
		return true;
	}

	UE_LOG(LogLgGameInstance, Error, TEXT("Savegame write to disk failed"));
	return false;
}

bool ULlamagotchiGameInstance::UpdateSaveInMemory(APetCharacter* Pet, ALlamagotchiPlayerController* PlayerController,
	APawn* PlayerPawn)
{
	UE_LOG(LogLgGameInstance, Log, TEXT("Updating save game in memory"));

	if (!SaveInstance)
	{
		UE_LOG(LogLgGameInstance, Error, TEXT("SaveInstance was null when trying to update save in memory"));
		return false;
	}

	[snip]

	TArray<AActor*> SaveableActors;
	UGameplayStatics::GetAllActorsWithInterface(GetWorld(), USaveableInterface::StaticClass(), SaveableActors);
	for (auto SaveableActor : SaveableActors)
	{
		SaveInstance->ActorSaver(SaveableActor, SaveInstance->CurrentLevel);
	}

	[snip]

	UE_LOG(LogLgGameInstance, Log, TEXT("Updated save game in memory"));

	return true;
}

The only thing I can think of that is a little bit non-standard is I am using a FObjectAndNameAsStringProxyArchive to write my actor data:

/**
 * Save Game Archiver.
 */
struct FLGSaveGameArchive : public FObjectAndNameAsStringProxyArchive
{
	FLGSaveGameArchive(FArchive& InInnerArchive) 
			: FObjectAndNameAsStringProxyArchive(InInnerArchive,true)
	{
		ArIsSaveGame = true;
	}
};
void ULGSaveGame::ActorSaver(AActor* SaveActor, ELgLevel Level)
{
	// All actors passed here need to implement this interface
	ISaveableInterface* ImplementsInterface = Cast<ISaveableInterface>(SaveActor);
	check(ImplementsInterface != nullptr);

	FString UniqueId = FObjectRecord::GenerateUniqueId(SaveActor, Level);
	FObjectRecord& ObjectRecord = UniqueIdToObjectRecords.Emplace(UniqueId);
	ObjectRecord.UniqueId = UniqueId;
	ObjectRecord.Name = SaveActor->GetFName();
	ObjectRecord.Transform = SaveActor->GetTransform();
	ObjectRecord.Class = SaveActor->GetClass();
	ObjectRecord.bShouldSpawn = ISaveableInterface::Execute_GetShouldSpawn(SaveActor);
	ObjectRecord.LevelToSpawnIn = ISaveableInterface::Execute_GetLevelToSpawnIn(SaveActor);
	
	SaveData(SaveActor, ObjectRecord.Data);

    UE_LOG(LogSaveGame, Display, TEXT("Complete Save Actor %s"), *SaveActor->GetName())
}

void ULGSaveGame::SaveData(UObject* Object, TArray<uint8_t>& Data)
{
    if (Object == nullptr) return;

    FMemoryWriter MemoryWriter = FMemoryWriter(Data, true);
    FLGSaveGameArchive MyArchive(MemoryWriter);

    Object->Serialize(MyArchive);
}

If anybody has any suggestions or can offer any tips it would be greatly appreciated. Really scratching my head on this one since I haven’t been able to reproduce locally.

Several times I encountered the problem of saving when updating the application.

What happened in your case exactly? the save files are written to the documents or library folder both of which are not deleted during app update.

Just an update incase anybody encounters a similar problem.

I was able to work around this issue by writing my save game multiple times and then loading the most recent one. This way even if a save game write fails it will just load the last successful save.

Eventually I would like to re-write all of the engine code that uses the low level c file-writing APIs with higher level NSData or NSFileDescriptor based APIs which I think would also solve whatever corner case bug I was running into that was causing writes to fail.