I am downloading several small size songs from server and storing(NSData) into NSUserDefaults, so that i can use it when needed to cache and play directly on the device, instead of downloading and playing again from server.
The problem, if i store few couple of smaller size songs as an data format in NSUserDefaults, it reduces lots of device memory and throwing memory warning or crashing etc.
Could you someone guide me how can i resolve it? How can i store song data persistently on the device for Cache purpose, and same time storing in less memory usage?
UPDATED: As per the suggestion, i tried to add song data into dictionary as file and tried to retrieve it as below. But, still i'm facing the same issue, memory warning after around 30mb of data retrieved.. Could someone help me to resolve this? I need to store around 40 mb of song data and store it.
NSURL *songurl = [NSURL URLWithString:downloadSOngUrl];
NSMutableData *songdata = [NSMutableData dataWithContentsOfURL:songurl];
NSString *fileName = [downloadSOngUrl lastPathComponent];
NSLog(#"fileName: %#",fileName);
[appDelegate writeSongIntoDocsDirectory :songdata :fileName];
-(void) writeSongIntoDocsDirectory :(NSData *) inSongData :(NSString *) songNamePath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSLog(#"songNamePath: %#", songNamePath);
songNamePath = [songNamePath stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet] ];
NSLog(#"songNamePath: %#", songNamePath);
if ( [inSongData writeToFile:[documentsDirectory stringByAppendingPathComponent:songNamePath] atomically:YES] )
{
// Success !
NSLog(#"Successfully saved the song into documents directory");
}
else
{
// Error !
NSLog(#"Error when Successfully saving song into documents directory");
}
}
-(NSData *) readSongDataFromDocsDirectory :(NSString *) filePath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSData *readData = [NSData dataWithContentsOfFile:[documentsDirectory stringByAppendingPathComponent:filePath]];
return readData;
}
Thanks in advance!
Better store these audio files in documents directory as this will reduce the size of the app , NSUserDefaults is usually used to stored in small settings particular to the app , like the preferences and all for the particular user of the app. hoping this helps. . :)
Whatever you store in the NSUserDefaults will increase the app size as this object is always alive while the app runs...
Related
I want to load a webpage when user connected to network and store it offline(including with images/resources). If the user not connected to any network then i should load the previously stored webpage. I have tried NSData dataWithContentsOfURL:(NSURL *)url and NSString stringWithContentsOfURL but these stores only html content not the resources.
Thanks in advance.
You can do that with ASIHttpRequest. If you do not want to to use that project (it is no longer active) you can look into the code and what it does. Look at "how to cache a whole web page with images in iOS" for more info as well.
I think the simple solution is this - "Safari Client-Side Storage and Offline Applications Programming Guide", https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/Introduction/Introduction.html
Only if you are making an app with HTML5 and webview, didn't test this method yet so far, so it might work.
Write this data into file using:
-(void)writeDataToFile:(NSString*)filename
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
if(filename==nil)
{
DLog(#"FILE NAME IS NIL");
return;
}
// the path to write file
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat: #"%#",filename]];
/*NSData *writeData;
writeData=[NSKeyedArchiver archivedDataWithRootObject:pArray]; */
NSFileManager *fm=[NSFileManager defaultManager];
if(!filePath)
{
//DLog(#"File %# doesn't exist, so we create it", filePath);
[fm createFileAtPath:filePath contents:self.mRespData attributes:nil];
}
else
{
//DLog(#"file exists");
[self.mRespData writeToFile:filePath atomically:YES];
}
NSMutableData *resData = [[NSMutableData alloc] init];
self.mRespData=resData;
[resData release];
}
and load it next time.
I don't know if there is one-line-solution like myWebView.cache4Offline = YES; , but I fear as long as you don't have access to the website's code (i.e. if you want to make any website available offline inside your app), you have to program this on your own. Thinking about it, it doesn't seem so difficult:
Scan the html string for image urls (and everything else you need)
Download those resources from the internet using NSData dataWithContentsOfURL (maybe a little annoying, because of relative/absolute URLs)
Save data to file with NSData writeToFile:options:error:
Replace URL in HTML with filePath from 3. (OR, better use a convention for converting their URLs in your file-URLs)
Hope it helps
i am doing one iphone app, for that i have to store bulk of MP3 song and images.
can ay one tell me what is the best to store those in terms of performance.
Store the image and songs in the application directory. This is best and easy way to handle. Try the following code. it will be help you.
//Store Image/Songs files to Application Directory
+(BOOL)writeToFile:(NSData *)data fileName:(NSString *)fileName {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
// the path to write file
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:fileName];
return [data writeToFile:appFile atomically:YES];
}
//Image/songs - Retrieve from Application Directory
+(NSData *)readFromFile:(NSString *)fileName {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:fileName];
NSData *myData = [NSData dataWithContentsOfFile:filePath];
if (myData) {
return myData;
}
return nil;
}
store the MP3 song and images into resources folder of your app project and give the refrences in the sqlite database(because saving large files in sqlite database is not a good practice)
I would suggest you to store all items of large size on the device disk, i.e, Documents directory and store their physical path in core data or sqlite or at least in a plist file so that you can retrieve them as per your convenience.
I have a NSMutableArray, each item in this array is different class. In each class has many field such as CPPlot, identifier,... (I am using CorePlot to develop a stock application). Now I would like to store this NSMutableArray to load when user reopen application, this will load all the chart they used before.
I try to figure out how to do that in Stackoverflow. And I found out there were 2 solutions:
NSUserDefaults
SQLite database
In NSUserDefaults, when I want to store NSMutableArray, I must implement with NSKeyedArchiver to archive and unarchive array object, also do NSCoding protocol for each item in array object. But I can not do this solution because in each item, it has some fields from CorePlot library, so that I can not use NSCoding to these fields.
SQLite database, I can not use this solution because each item in array object is different class.
I would like to ask if any other solution to solve this problem?
I hope my words are clear enough to understand.
Thanks
I would suggest you figure out what kind of data is at the root of your CorePlot objects. If it is integers, then simply store them in NSUserDefaults, and then simply rebuild your NSMutableArray on re-opening the app. Another option is to store your items in a separate plist file.
Use this method to save:
- (NSArray *)applicationDataFromFile:(NSString *)fileName {
NSArray *paths = NSSearchPathForDirecotiresInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory
stringByAppendingPathComponent:fileName];
NSArray *myData = [NSArray arrayWithContentsOfFile:appFile];
return myData;
}
- (BOOL)saveToFileForStringArray:(NSMutableArray *)array
toFile:(NSString *)fileName {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
if (!documentsDirectory) {
NSLog(#"Documents directory not found!");
return NO;
}
NSString *appFile = [documentsDirectory
stringByAppendingPathComponent:fileName];
return ([array writeToFile:appFile atomically:YES]);
}
We are caching images downloaded from our server. We get the data from an ASIHTTPRequest callback like this:
#pragma mark ASIHTTPRequest callback
-(void)imageDownloadFinished:(ASIHTTPRequest*)aRequest
{
NSString* fileName = aRequest.url.path.lastPathComponent;
[self imageDidArrive:[aRequest responseData] forFileName:fileName];
}
We write the image data to our local storage like this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0] ;
NSString* folder = [[documentsDirectory stringByAppendingPathComponent:#"flook.images"] retain];
NSString* fileName = [folder stringByAppendingFormat:#"/%#", aBaseFilename];
BOOL writeSuccess = [anImageData writeToFile:fileName atomically:NO];
The downloaded images are always the expected size, around 45-85KB.
Later, we read images from our cache like this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0] ;
NSString* folder = [[documentsDirectory stringByAppendingPathComponent:#"flook.images"] retain];
NSString* fileName = [folder stringByAppendingFormat:#"/%#", aBaseFilename];
image = [UIImage imageWithContentsOfFile:fileName];
Occasionally, the images returned from this cache read are much smaller because they are much more compressed - around 5-10KB. Has the OS done this to us?
Edit - it turns out that we are downloading the small images, so the issue isn't on the iPhone
If I'm reading your code correctly, you're using the NSData method writeToFile:atomically: to write to the file. That does an exact byte-for-byte write of the contents of the NSData object.
It appears that the NSData object is created directly from the contents of the HTTP response, so the answer is "no", there should not be any compression taking place.
We have the solution. When the phone is running on the 3G network, O2 kindly steps in and applies extra JPG compression to our images, so that they look extra horrible.
See this post on the UK 3G forum.
I am simply creating a student management system in iPhone.
There I need to store student's small images,
Which should be appear in tableView,
Ok, I know how to work with tableView...
how to work with database...
But question is
Where to store images
how can we obtain the path of stored images..
Do i have to store entire images to database...
Or
i have to store relative path of image to database...
What is suggested by You masters?
Thanks in advance for helping me.
You can create image files on the file system of the device in the Document directory. Use something like this:
// Generate a unique user filename
NSString *imageFilename = [NSString stringWithFormat:#"student_image_%#", uniqueIdentifier];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [NSString stringWithFormat:#"%#/%#", [paths objectAtIndex:0], imageFilename];
NSData *storage = [image UIImagePNGRepresentation]; // or UIImageJPEGRepresentation
[storage writeToFile:path atomically:NO];
Best Regards,