How to fetch json data using url and write it in file? - iphone

As my above screen shot that i have a json file (productDetail.json) in my app then i write file from json data like below code
else if([(MultipleURLConnection *)connection tag]==2)
{
if([fn writeToFile:responseData fileName:#"productDetail.json"])
[self performSelector:#selector(loadingJSON) withObject:nil afterDelay:0.1];
}
in above code responseData is NSMutableData and fn is function Class object name where i have below method
- (BOOL)writeToFile:(NSData *)data fileName:(NSString *)fileName
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *myFile = [documentsDirectory stringByAppendingPathComponent:fileName];
NSFileManager *fm = [NSFileManager defaultManager];
if (![fm fileExistsAtPath:myFile]) // if file doesn't exist, create it
return ([fm createFileAtPath:myFile contents:data attributes:nil]);
else
return ([data writeToFile:myFile atomically:YES]);
}
Now i decide to remove json file from app and to put it on server and then fetch it .so after putting json file on server i tried to fetch it like below coding
else if([(MultipleURLConnection *)connection tag]==2)
{
NSURL *url = [NSURL URLWithString:#"http://mysite.com/Infomist/productDetail.json"];
NSData *jsonData = [NSData dataWithContentsOfURL:url];
if(jsonData != nil)
{
NSError *error = nil;
id result = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
if (error == nil)
NSLog(#"show data %#",result);
}
Now above method successfully fetching my data from server it show all my data in NSlog but problem for me is now how to modify this Method now
if([fn writeToFile:responseData fileName:#"])
Beacuse after putting the json file on server i don't have any file to pass file name in above method to call the
- (BOOL)writeToFile:(NSData *)data fileName:(NSString *)fileName .
I already have App flow for local json file so i need only to write json data in my app.

- (BOOL)writeToFile:(NSData *)data fileName:(NSString *)fileName
the above requires NSData as a parameter
id result = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
the above gives id as a return type object..you need to check which type of object it is using isKindOfClass
and then later convert it to data using decoding/NSkeyedArchiver or other techniques

Related

UIImage gets corrupted while Downloading

I have developed iOS App, in which i am downloading image from server and saving it in my Document directory.
But problem which i am facing is, sometimes my images getting corrupted when i download, even if the server response isSuccessful.
Here is my code snippet,
urlFile is path of UIImage which is on server e.g: www.abcd.com/images/pqr.jpg
fileName which i am using for saving image name in my DocDirectory.
- (void)downloadFile:(NSString *)urlFile withName:(NSString *)fileName
{
NSString *trimmedString = [urlFile stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSLog(#"trimmedString=%#",trimmedString);
if ([trimmedString length]>0)
{
HTTPEaterResponse *response = [HTTPEater get:[NSString stringWithFormat:#"%#",trimmedString]];
if ([response isSuccessful])
{
NSLog(#"isSuccessful");
[self saveImage:[[UIImage alloc] initWithData:[response body]] withName:fileName];
} else {
NSLog(#"Url response failed %#", [response description]);
}
}
}
- (void)saveImage:(UIImage *)image withName:(NSString *)name
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSData *data = UIImagePNGRepresentation(image);
NSLog(#"image =%#",image);
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:name];
[fileManager createFileAtPath:fullPath contents:data attributes:nil];
}
When i see my Log, it shows:
trimmedString= www.abcd.com/images/pqr.jpg
isSuccessful
image =null
Thanks in advance.
I use the following code and it works for me.
NSData *thumbImageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:ImageURL]];
[thumbImageData writeToFile:cachedThumbnailFileName atomically:YES];
UIImage * image = [UIImage imageWithContentsOfFile:cachedThumbnailFileName];
imageView.image = image;
Hope it helps you. :)
To save image on directory use:
NSString *pngPath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/Test.jpg"];
[UIImagePNGRepresentation(selectedImage) writeToFile:pngPath atomically:YES];
NSError *error;
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
have you logged the response [response body]?
Just try to convert that response as NSData and then save as image.
Using Base64Encoding class,you can convert the response as base64Data
NSData *imageData = [NSString base64DataFromString:[response body]];
[self saveImage:[[UIImage alloc] initWithData:imageData] withName:fileName];
i suggest yo use SDWebimage Class SDWebimage download.. i think its very helpful to you even i always prefer SDWebimage Library.
this are the some things.
An UIImageView category adding web image and cache management to the Cocoa Touch framework
An asynchronous image downloader
An asynchronous memory + disk image caching with automatic cache expiration handling
Animated GIF support
WebP format support
A background image decompression
A guarantee that the same URL won't be downloaded several times
A guarantee that bogus URLs won't be retried again and again
A guarantee that main thread will never be blocked
Performances!
Use GCD and ARC
instead u can use, "NSURLRequest" and "NSURLConnection"
for example if u get image URL then,
NSURL* aURL = [NSURL URLWithString:trimmedString];//get the url of string
NSURLRequest *aReq = [NSURLRequest requestWithURL:aURL];
NSURLConnection *aConnection = [NSURLConnection connectionWithRequest:aReq delegate:self]; //get a connection to url , since it confirms to delegate u need to implement delegate methods
if(aConnection == nil) //if it is nil then cancel and close the request
{
aConnection = nil;
[aConnection cancel];
}
// after this implement this delegate methods
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)received_data
{
if(image_data == nil) //if data is not initialised initialise it
{
image_data = [[NSMutableData alloc]init];
}
[self.image_data appendData:received_data];//append the received data
}
//this method is called after successful download of the image
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
{
// UIImage* sampleImage = [UIImage imageWithData:self.image_data];
// self.image = sampleImage; //convert the data to image
//since u hav complete downloaded date in "self.image_data"
NSString *imagePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:#"/myImage.png"];//set the name of the image and path may it saving in application directory check it out
[self.image_data writeToFile:imagePath atomically:YES]; //saving the data with name
}
Hope this helps u :)

not able to save data to file on iPhone

I created a method that first save the json data to the file
and then I am reading the data from the file.
I am able to save and read data when I run on simulator but when I try to run the application on iPhone and debug thru, it does not save or retrieve the data.
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSMutableData *retrievedData = [NSMutableData data];
[retrievedData appendData:data];
NSMutableString *allInfo = [[NSMutableString alloc] initWithData:retrievedData encoding:NSASCIIStringEncoding];
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"credentials" ofType:#"json"];
NSData *userCredentials = allInfo;
[userCredentials writeToFile:filePath atomically:YES];
NSError *error;
NSData* JSONData = [NSData dataWithContentsOfFile:filePath];
NSDictionary *JSONDictionary = [NSJSONSerialization JSONObjectWithData:JSONData options:kNilOptions error:&error];
//get the log in information from the credentials file
NSDictionary *login = [JSONDictionary objectForKey:#"login"];
//get the auth_token
NSDictionary *loginInfo = login;
if(loginInfo == NULL)
{
errorMessage.text = #"Invalid username or password";
errorMessage.hidden = NO;
}
else
{
NSString *authCode = [loginInfo objectForKey:#"auth_token"];
[self saveUserCredentials:authCode];
}
}
You should never write file to NSBundle. For the simulator, it seems a bug. Simulator have a lot more bugs than device. It's better to test your app on device instead of on the device if it's possible. Other guys also have seen this problem. See Apple's doc:
Application_Home /AppName.app
This is the bundle directory containing the app itself. Do not write
anything to this directory. To prevent tampering, the bundle directory
is signed at installation time. Writing to this directory changes the
signature and prevents your app from launching again.
I basically did this
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *directory = [paths objectAtIndex:0];
NSString *filepath = [NSString stringWithFormat:#"%#/%#", directory,#"credentials.json"];
And now my code is able to retrieve data on iPhone and as well as on simulator.

How to use addSkipBackupAttributeToItemAtURL API?

my application rejected due to this issue :
http://i.imgur.com/yajQh.png
My application is a dictionary which uses SQL DBs , with bookmarking and etc ...
so I copied this code from Apple docs in appDelegate.m :
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
NSError *error = nil;
BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
forKey: NSURLIsExcludedFromBackupKey error: &error];
if(!success){
NSLog(#"Error excluding %# from backup %#", [URL lastPathComponent], error);
}
return success;
}
but used like this :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self addSkipBackupAttributeToItemAtURL:[NSURL URLWithString:#"<myApplication>/Library/Caches"]];
}
but crashes with this reason :
Assertion failed: ([[NSFileManager defaultManager] fileExistsAtPath:
[URL path]]), function -[AppDelegate
addSkipBackupAttributeToItemAtURL:], file /iData/Development 2011/My
iPhone Project/APPNAME/APPNAME/AppDelegate.m, line 27.
According to that picture is this my only problem for rejection ? because this is my first time I work with data base .
Thanks .
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
EDITED :
- (NSString *) getDBPath
{
NSInteger kValue = [[[NSUserDefaults standardUserDefaults] stringForKey:#"Bv"] intValue];
NSString *documentsDir = [[NSString alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
documentsDir = [paths objectAtIndex:0];
switch (kValue) {
case 0:
documentsDir = [NSString stringWithFormat:#"%#/eng-per.sqlite", documentsDir];
break;
case 1:
documentsDir = [NSString stringWithFormat:#"%#/eng-per.sqlite", documentsDir];
break;
case 2:
documentsDir = [NSString stringWithFormat:#"%#/per-eng.sqlite", documentsDir];
break;
}
return documentsDir
}
and then changed to this in app delegate.m :
[self addSkipBackupAttributeToItemAtURL:[NSURL fileURLWithPath:dbClass.getDBPath]];
now app lunches fine without crash
Your app is "crashing" because you're hitting that assert on line:
assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
And I suspect your problem is actually in how you are setting up the URL:
[NSURL URLWithString:#"<myApplication>/Library/Caches"];
How are you getting the path to "<myApplication>"?
You need to get your application's true Cache's folder, which you can do via:
[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask]; (for the location passed back via file URL's)
or
NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); (for the path in the form of a NSString)
So ultimately, what you need to do is not assert if the key has already been set in defaults and you need to properly set the file URL for the file you're saving.
Create your URL (a file URL, to be precise) using something like:
NSArray * arrayOfURLs = [[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask];
// make certain there's at least one file url returned by the above call
if([arrayOfURLs count] > 0)
{
// and this would just be the URL to the cache directory...
NSURL * cacheDirectoryPath = [arrayOfURLs objectAtIndex: 0];
// ... to create a file url to your actual dictionary, you'd need to add a
// filename or path component.
// Assuming you save this as a property within your object
self.cacheFileURL = [cacheDirectoryPath URLByAppendingPathComponent: #"myDatabase.db"];
}

NSMutableData Save to a File

I downloaed the file using code shown below. Then i am trying to save NSMutableData variable to file, however, the file is not created. What am i doing wrong? Do i need to convert NSMutableData into NSString?
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)_response {
response = [_response retain];
if([response expectedContentLength] < 1) {
data = [[NSMutableData alloc] init];
}
else {
data = [[NSMutableData dataWithCapacity:[response expectedContentLength]] retain];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)_data {
[data appendData:_data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"file" ofType:#"txt"];
NSLog(#"saved: %#", filePath);
[data writeToFile:filePath atomically:YES];
NSLog(#"downloaded file: %#", data); //all i see in log is some encoded data here
}
You can’t write inside your app’s bundle. You’ll need to save it somewhere else, like your app’s Documents directory:
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"file.txt"];
[data writeToFile:filePath atomically:YES];

How to read & write to an NSArray to plist?

I'm having several issues based around reading and writing an NSArray to and from a plist.
I have created a plist file in the 'Supporting Files' folder which I want to use to initialise the app data with upon the first load.
Here is what my plist looks like:
I then use this code to try load the plist into the app:
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
filePath = [documentsDirectory stringByAppendingPathComponent:kDataFile];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:filePath])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"Data" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath:filePath error:&error];
}
I then try to load the data from the plist file like so, however nothing seems to be displayed.
NSMutableDictionary *savedData = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
NSMutableArray *myNSArray = [[savedData objectForKey:#"KEY_Level_1"] mutableCopy];
savedData = nil;
Sorry if this is a simple task, however I've been looking at lots of tutorials and trying to work out how to do this with no luck. I'm getting really frustrated now - I would have thought it should be a simple thing to do.
NOTE: My NSArray will contain a whole bunch of NSDictionaries.
You need to check the return value of copyItemAtPath:toPath:error: and at least log the error if the method returns false:
if (![fileManager copyItemAtPath:bundle toPath:filePath error:&error]) {
NSLog(#"error: copyItemAtPath:%# toPath:%# error:%#", bundle, filePath, error);
return;
}
-[NSDictionary initWithContentsOfFile:] has no way to report errors, so if it's failing, you cannot easily figure out why. Try reading the file into an NSData and using -[NSPropertyListSerialization propertyListWithData:options:format:error:] to parse it:
NSData *data = [NSData dataWithContentsOfFile:filePath options:0 error:&error];
if (!data) {
NSLog(#"error: could not read %#: %#", filePath, error);
return;
}
NSMutableDictionary *savedData = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListMutableContainers format:NULL error:&error];
if (!savedData) {
NSLog(#"error: could not parse %#: %#", filePath, error);
return;
}
NSMutableArray *myNSArray = [savedData objectForKey:#"KEY_Level_1"];
savedData = nil;
if (!myNSArray) {
NSLog(#"error: %#: object for KEY_Level_1 missing", filePath);
return;
}
If you do this, you'll be able to more easily see why your data is not being loaded.
UPDATE
On further inspection, it looks like the top-level dictionary in your plist contains the key "Root". The value for "Root" is a dictionary containing the key "KEY_Level_1". So you need to do this:
NSMutableArray *myNSArray = [[savedData objectForKey:#"Root"] objectForKey:#"KEY_Level_1"];