I want to update my local JSON file in the app when there is a new version of the file. I have the algorithm that checks if there is a new version or not.
But now, I need some code to change/update the local JSON for the online JSON.
I suggest you to use a .plist file as it can easily store a NSDictionary or NSArray (which can be translated from a JSON object)
try the code below:
//store plist file in documents directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = paths[0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"localJSON.plist"];
if([responseObject isKindOfClass:[NSArray class]])
{
//its an array
NSArray * dataToStore = jsonObject;
[dataToStore writeToFile:filePath atomically:YES];
}
else
{
//its a dictionary
NSDictionary * dataToStore = jsonObject;
[dataToStore writeToFile:filePath atomically:YES];
}
Related
I have an api inside are the city's ID, I do not want to request data every time,I want to writeToFile as plist,but the first written is too slow and memory skyrocketing.
Is there any method I can use to make it into a plist as local file,so users do not have to write again
Plist file obtained in this way is no data on the xcode view, but in fact it has already been written, you can find data through code
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *plistPath = [paths objectAtIndex:0];
NSMutableArray *marr = [NSMutableArray array];
NSString *filename=[plistPath stringByAppendingPathComponent:#"city.plist"];
NSLog(#"filename == %#",filename);
[marr addObject:#"字符串"];
[marr writeToFile:filename atomically:YES];
If you are about to create Plist without programmatically then follow these steps :
Right Click on Files and Select 'New File...' option.
Choose Resources from OS X tab.
An option for Property List is available.
Select an give an appropriate name.
This gets added to your project.
You can create a property list in Objective-C if all of the objects in the aggregate derive from the NSDictionary, NSArray, NSString, NSDate, NSData, or NSNumber class.
Use following code:
//Get the documents directory path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"plist.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path]) {
path = [documentsDirectory stringByAppendingPathComponent: [NSString stringWithFormat:#"plist.plist"] ];
}
NSMutableDictionary *data;
if ([fileManager fileExistsAtPath: path]) {
data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
}
else {
// If the file doesn’t exist, create an empty dictionary
data = [[NSMutableDictionary alloc] init];
}
//To insert the data into the plist
[data setObject:#"iPhone 6 Plus" forKey:#"value"];
[data writeToFile:path atomically:YES];
//To retrieve the data from the plist
NSMutableDictionary *savedValue = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
NSString *value = [savedValue objectForKey:#"value"];
NSLog(#"%#",value);
For more details click here
Apple has also put a demo project for creating plist file here.
I wrote a class that caches API responses, so later when u request Countries endpoint, it will check defined endpoints to cache, if it find it in list and it exist in cache, it will return the cached one and will not complete performing the HTTP request, in docs i provided steps how to implement it.
MGCacheManager
Following function take serilizable object(dictionary, array) as input and convert it into plist and write it in document disrectory of application:
+ (BOOL) writeBundelPlist : (NSString *) plistName with : (id) newPlistData {
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:plistName];
if (![fileManager fileExistsAtPath:plistPath]) {
NSString *bundle = [[NSBundle mainBundle] pathForResource:[plistName stringByDeletingPathExtension] ofType:[plistName pathExtension]];
NSLog(#"plistPath = %#", plistPath);
[fileManager copyItemAtPath:bundle toPath:plistPath error:&error];
}
return [newPlistData writeToFile:plistPath atomically:YES];
}
this method is very useful, thanks for evervone,thanks for rmaddy
do{
let data = try NSPropertyListSerialization.dataWithPropertyList(response.result.value as! NSMutableDictionary, format: NSPropertyListFormat.XMLFormat_v1_0, options: 0)
data.writeToFile(countryListPath, atomically: true)
}catch
{
}
When there is no internet connection on device, i am storing the json in to a text file. But the problem is, if i do again it is getting replaced. Here is what i am doing for store into a text file. How to store multiple json object in a text file.When i get connection i need to post json to server.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
NSString *filePath = [docDir stringByAppendingPathComponent:#"File.json"];
[jsonString writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&error];
Please advice.
That's not so straight forward as concatenating multiple JSON files does not result in a valid JSON file. To do this properly requires you to read and parse the existing JSON file, which will give you an NSArray or NSDictionary top-level object, then append the data from the new JSON file and write the whole thing out.
That is inefficient as you are processing old data.
Therefore I would suggest you write new data to a new file, using the current date/time for the filename, and when it's time to upload, read each of the files and upload them individually, one-at-a-time. Then delete each file as it's uploaded.
Use below method to append text to file
-(void) writeToLogFile:(NSString*)content{
content = [NSString stringWithFormat:#"%#\n",content];
//get the documents directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
NSString *filePath = [docDir stringByAppendingPathComponent:#"File.json"];
NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:fileName];
if (fileHandle){
[fileHandle seekToEndOfFile];
[fileHandle writeData:[content dataUsingEncoding:NSUTF8StringEncoding]];
[fileHandle closeFile];
}
else{
[content writeToFile:fileName
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:nil];
}
}
Here is kind of an overview of what I'm trying to do. My app has a form on it, and the form data is saved as a .csv file in the documents directory. I want to parse through the documents directory and get the filenames of the files that are .csv files. I then want to display these filenames in a UITableView so that the user can choose a file to be attached to the email. I'm having some trouble getting the filenames into an NSMutableArray. Below is my code:
NSString *extension = #"csv";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSError *error = nil;
NSArray *documentArray = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:&error];
NSLog(#"files array %#", documentArray);
NSString *filename;
for (filename in documentArray) {
if ([[filename pathExtension] isEqualToString:extension])
{
[_mySingleton.filePathsArray addObject:filename];
}
}
NSLog(#"files array %#", _mySingleton.filePathsArray);
The first NSlog returns what looks to be all the filenames in the folder. In the second NSlog it should only be printing the .csv filenames, instead it is returning null. Obviously that code in the for loop is not working, how can I fix this? Also I hope it is not confusing, I have a singleton class and in this case I'm storing the filenames in it so that they can be edited and accessed across multiple views.
Thanks,
Alex
try to use built in a filter function
NSArray *files = #[#"11.csv", #"22.txt", #"333.csv", #"444.doc"];
NSArray *cvsFiles = [files filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSString *evaluatedObject, NSDictionary *bindings) {
return [evaluatedObject hasSuffix:#".csv"];
}]];
NSLog(#"%#", cvsFiles);
And in your code the filePathsArray will have only names of files. You should append a directory path to.
[_mySingleton.filePathsArray addObject:[documentsDirectory stringByAppendingPathComponent:filename];
full version
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSArray *documentArray = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:nil];
NSArray *cvsFiles = [documentArray filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSString *evaluatedObject, NSDictionary *bindings) {
return [evaluatedObject hasSuffix:#".csv"];
}]];
NSMutableArray *filePaths = [#[] mutableCopy];
for (NSString *fileName in cvsFiles) {
[filePaths addObject:[documentsDirectory stringByAppendingPathComponent:fileName]];
}
_mySingleton.filePathsArray = filePaths
You wrote
In the second NSlog it should only be printing the .csv filenames,
instead it is returning null.
It means that _mySingleton.filePathsArray is not initialised. In case it will be initialised NSLog will print an empty array, not null.
What you have to do - add _mySingleton.filePathsArray initialisation somewhere before it is used:
_mySingleton.filePathsArray = [NSMutableArray new];
I'm basically trying to find a way to save a JSON server response, so can work on some app logic that relies on the response even when the server is no longer returning it. When I get the data back, I can print it out and it will look something like this:
<7b202254 7269704c 69737422 3a207b22 43757272 656e7454 696d6522 3a203134 30353037 33323836 ...
Is there any way I can create an instance of NSData using this information (NSData dataWithData?)? Or is there a way to create JSON dict/array with the JSON string?
TL;DR how do I save a JSON server response and add a debug option to fake the server response?
You can directly save the jsonData (NSData) into a file, and use it, see below
{
//Write NSData directly to file
[jsonData writeToFile:[self jsonFilePath] atomically:YES encoding:NSUTF8StringEncoding error:nil];
//Read from file
NSJSONSerialization *json=[NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:[self jsonFilePath]] options:0 error:nil];
//The json object can be used as an Array or, Dictionary
NSArray *array=(NSArray *)json;
//OR
NSDictionary *dic=(NSDictionary *)json;
}
-(NSString *)jsonFilePath{
return [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:#"file.json"];
}
Hope it helps.
Cheers.
You Json Response data is image data . You can store it in document directory as below.
NSData *webData = UIImageJPEGRepresentation(image1, 0.5);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:#"Profile1.jpeg"];
[webData writeToFile:savedImagePath atomically:YES];
Now in your Document Directory store image. check go to Iphone Simulator > Application > ProjectName > Documents
Store JSON in text file, as suggested by other.
Now where you want to fetch this text file data, you can use -
NSString *jsonFilepath = [[NSBundle mainBundle] pathForResource:#"jsonFile" ofType:#"text"];
// JSON Data
NSData *data = [NSData dataWithContentsOfFile: jsonFilepath];
// JSON String
NSString *jsonString = [[NSString alloc] initWithContentsOfFile:jsonFilepath encoding:NSUTF8StringEncoding error:nil];
Now you can perform all operation with JSON, as you want.
You can save your JSON Data as a plist in your App's Document Folder..
-(void)SaveResponse
{
NSError *error = nil;
NSData *JSONData = Your Current Data that received from server
NSMutableDictionary *objDictionary = [NSJSONSerialization
JSONObjectWithData:JSONData
options:NSJSONReadingAllowFragments
error:&error];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *strFilePath = [documentsDirectory stringByAppendingPathComponent:#"Response.plist"];
[objDictionary writeToFile:strFilePath atomically:YES];
}
I'm currently saving an NSDictionary to file on the iOS device. However, NSDictionary files are readable XML. I don't want people to be able to get in and read the contents so I need to be able to encrypt the file on writing and decrypt when loading it back again.
I'm currently saving the file like this:
NSFileManager* fileManager = [NSFileManager defaultManager];
if (!fileManager)
{
NSLog(#"Failed to get file manager to save.");
return;
}
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* filePath = [documentsDirectory stringByAppendingPathComponent:#"save.dic"];
[m_dictionary writeToFile:filePath atomically:YES];
And I'm loading the dictionary like this:
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* filePath = [documentsDirectory stringByAppendingPathComponent:#"save.dic"];
m_dictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
Can anyone tell me a nice way of encrypting\decrypting this?
Cheers,
Rich
Use a NSKeyedArchiver to create an NSData object from your dictionary (NSKeyedArchiver archivedDataWithRootObject:). Then encrypt the NSData with AES and write that to your file.
Reading takes the reverse: first, read the NSData, decrypt it via the method from the mentioned link, then pass the decrypted NSData to NSKeyedUnarchiver (NSKeyedUnarchiver unarchiveObjectWithData:) and you get your dictionary back.