Error writing to filesystem on iOS


#1

Hi All,

I’m trying to load/save some very basic settings in an iOS app. Traditionally on MSW/OSX I’ve done this by reading/writing to a json file. On iOS I’m able to read the initial settings, but it’s throwing errors when I’m trying to write to the same file. I’m looking into doing this natively using Objective-C using a plist instead, but figured it was worth finding out why this is happening.

The EXC_BAD_ACCESS error is being thrown in the JsonTree::write() method because of a nullptr resulting from trying to get the target’s stream.

void JsonTree::write( DataTargetRef target, JsonTree::WriteOptions writeOptions )
{
	// Declare output string
	string jsonString = "";

	try {
		
		// Create JsonCpp data to send to parser
		Json::Value value = createNativeDoc( writeOptions );

		// This routine serializes JsonCpp data and formats it
		if( writeOptions.getIndented() ) {
			jsonString = value.toStyledString();
			boost::replace_all( jsonString, "\n", "\r\n" );
		} else {
			Json::FastWriter writer;
			jsonString = writer.write( value );
		}
		jsonString += "\0";
	}
	catch ( ... ) {
		throw ExcJsonParserError( "Unable to serialize JsonTree." );
	}

	// Save data to file
	OStreamRef os = target->getStream();
	os->writeData( jsonString.c_str(), jsonString.length() ); // <= os is a nullptr
	
}

I can see the location of settings.json in the Sandboxed App dir on the device by logging to the console:

std::cout << "attempting to save to: " << ci::app::getAssetPath("settings.json") << std::endl;
mSettingsJson.write(ci::app::getAssetPath("settings.json"));

outputs the following:

attempting to save to: "/var/containers/Bundle/Application/72CB45DE-D9EA-4A07-9469-27AEE4C019A6/TestIos.app/assets/settings.json"

the ( FILE *) of mStream object of the target ptr is null, as per the image below:

Any insights would be appreciated!

(using Xcode 9, iOS 11.2, OSX 10.13.2)

Craig


#2

Try writing to the documents directory. I don’t think the app has permissions to write to assets/.


#3

I’m not sure if this is the best solution but for a quick example I have successfully used this before on a Cinder iOS project to save and load settings.

fs::path settingsPath = getHomeDirectory() / "Library" / "Application Support" / "Your_App_Name" / "settings.json"


#4

Thanks @wdlindmeier, I figured it might be something along those lines. Without knowing anything about iOS it made it a little tricky to search for the right thing, thanks for the SO link!


#5

Thanks @felixfaire plugging that in quickly solves the nullptr issue, I’ll dig in a little deeper and make sure it works as expected. Without having done any further investigation yet - is there a way to access the filesystem to place that ‘original’ settings.json file there to have a default, or is it a simple case of having the app to write to that location once and go from there?


#6

I dont think you can access the ios filesystem directly from outside the app, I have always got the app to save one if it hasn’t found one already at the desired path. Good luck.


#7

Figured as much - thanks again.