I am making an app that takes photos from web site for some Username and shows it in a UITable with username then when clicking user name it shows photos for this user and then clicking to name of photo it shows full screen photo.
My question is I am using NSData to get photos from internet. Do I have to save the data to CoreData? When pressing name of user it creates NSData and downloads photos from internet and shows them on UITable. And it takes time.
What is good approach? and How can save this images to CoreData?
I am using this method
NSData *imageData=[flickr dataForPhotoID:firstPhoto.id fromFarm:firstPhoto.farm
onServer:firstPhoto.server withSecret:firstPhoto.secret inFormat:
FlickrFetcherPhotoFormatSquare];
and here definition of dataForPhotoID method
- (NSData *)dataForPhotoID:(NSString *)photoID fromFarm:(NSString *)farm
onServer:(NSString *)server withSecret:(NSString *)secret
inFormat:(FlickrFetcherPhotoFormat)format {
#if TEST_HIGH_NETWORK_LATENCY
sleep(1);
#endif
NSString *formatString;
switch (format) {
case FlickrFetcherPhotoFormatSquare: formatString = #"s"; break;
case FlickrFetcherPhotoFormatLarge: formatString = #"b"; break;
}
NSString *photoURLString = [NSString stringWithFormat:#"http://farm%#.static.flickr.com/%#/%#_%#_%#.jpg", farm, server, photoID, secret, formatString];
NSURL *url = [NSURL URLWithString:photoURLString];
return [NSData dataWithContentsOfURL:url];
}
First, always store your images in a usable format such as PNG or JPEG instead of NSData. This will save you a lot of headaches.
Second, the rule for storing binary data is:
< 100kb store in the same table as the relevant data
< 1mb store in a separate table attached via a relationship to avoid loading unnecessarily
1mb store on disk and reference it inside of Core Data
Update
The storage inside of Core Data should be binary and you can write accessor methods for it. Take a look at this answer: Core data images from desktop to iphone
Update
The example code I linked to describes how to create accessors in your NSManagedObject subclass that will convert the image back and forth between a UIImage and binary data.
You can simply store UIImage objects in CoreData directly, just use Transformable data type, and you are ready to go
Related
I'm currently use binary data saved in Core Data object to generate UIImage as code below.
UIImage * postImage = [UIImage imageWithData:image];
double imageRatio = postImage.size.height / postImage.size.width;
[imageContent setFrame:CGRectMake(imageContent.frame.origin.x, imageContent.frame.origin.y, imageContent.frame.size.width, imageContent.frame.size.height * imageRatio)];
[imageContent setImage:postImage];
However, I found there's a little bit slow when generate image.
Should I save image locally when retrieve data from server instead?
Which way is faster?
Thanks,
Save the image locally (e.g. in the Documents or Caches directory) instead of in the Core Data database. You get no benefit from storing binary data in the database as you will never search or index by this data, and it will just bloat your database. Just store an NSString reference to the filename/path you save the image to.
I imagine the UIImage:imageWithData method is slower when compared with reading an image from file that is already in a suitable image format.
save image locally and in your coreData save the location and name "URL" for that image
save your image locally such as PNG or JPEG instead of NSData.
I've seen various questions here pertaining to saving NSArrays/NSDictionaries, but I'm a bit confused about what to do when some of the subelements are UIImages.
To give a little context, the app is essentially a blog-type app. When the user is composing a new entry, their post can contain the following:
Up to 3 images from their photo album
Text
Location
In essence, I'm trying to implement a "Save Draft" functionality to the app if the user decides to temporarily cancel their blog post. When the user cancels the blog post, they will be asked in a UIActionSheet if they would like to save their draft. When the user wants to post again, they can begin from where they left off with their saved draft.
At this point, I would need to save these following objects:
1) NSArray of selected photos
---> contains NSDictionaries (up to 3)
--------> UIImage (large sized version)
--------> UIImage (thumbnail sized version)
2) NSDictionary of NSValues (just some view x,y position data)
3) Text -- NSString data of the blog text they have written
4) Location text -- NString data of their current location
Given that I need to save the above 1~4 data in order to make the "Save Draft" functinality, what is the best way to do this? Should I make a special class to hold all of this data? Also, do I first need to make the UIImages into NSData before I can save them to disk?
Thank you!!
Yes a class/model like structure make more sense and easier to handle as well.
Something like-
Interface Blogdata
NSArray *selectedPhoto;
NSDictionary *positionValues;
NSString *blogText;
NSString *locationText;
and then you can make one more model for photo data;
Interface Photodata
NSDictionary *photo;
UIImage *largeImage;
UIImage *thumbImage;
All of the properties that you mentioned seem like they would belong in a Blog class. Are they already grouped together? A Blog object could capture the state of the draft with variables (properties) of the object being the four things you mentioned. You can then save the Blog object as NSData and read it when the user wants the draft again.
The advantage of this is that you only have to worry about saving one object, instead of having to think about saving four each time (and retrieving them).
The easiest way would be to save the images to the apps documents folder and save the NSArray of filenames and other data that can be represented as text in a drafts.plist.
filenameStr = [NSString stringWithFormat:#"image1.png"];
fileManager = [NSFileManager defaultManager];
paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
documentsDirectory = [paths objectAtIndex:0];
imagePath = [documentsDirectory stringByAppendingString:#"/"];
imagePath = [imagePath stringByAppendingString:filenameStr];
NSData *imageData = UIImagePNGRepresentation(myImage);
[imageData writeToFile:imagePath atomically:YES];
I'm trying to create a way to save the interface of my app in a JSON file. While static elements I can define by their frames and/or center points, the interface does include a single image selected from the photo library. Because some iPhones have 8MP cameras, I can anticipate that some images would be very large.
I would like to be able to save this interface and send it over by email, so another app user can re-open the file and see the same interface with the image included.
Currently I'm using JSONKit to save my data into a JSON object. This means that the email will contain a single JSON file containing both the layout parameters and the image. I've never worked with such large JSON files, so the question is - will having several megs of image data within JSON present parsing issues? Or should I select some other file container that would have : first part JSON file, second part raw image data and then separate that file into a JSON string and a raw data string?
This is what I'm using currently to get a JSON file. After adding NSData to JSON, the convert to json method returns nil
NSString* currentURL = webView.request.mainDocumentURL.absoluteString;
[dictionary setValue:currentURL forKey:#"webViewAddress"];
//this call correctly returns the json string
NSLog(#"%#", [dictionary JSONString]);
NSLog(#"+++++++++++++++++++++++++++++++++++++");
NSData* imageData = UIImagePNGRepresentation(arOverlayView.image);
//after this call, the json returns nil
[dictionary setValue:imageData forKey:kimageData];
NSLog(#"%#", [dictionary JSONString]);
If you are using email as a transport mechanism, your binary data will have to end up as something like Base64 encoded at some point in its life. There is no "raw" format for email, there is only text.
At best you could implement Base85 encoding which is more efficient than Base64
So you are going to have to suck up the large file sizes unless you invent your own transport mechanism - such as a point to point TCP/IP based link.
I'm using NSCoding to manage a custom object with a few different fields, one of them images. I'm only targeting iOS 5.0+ and have switched to ARC. I have everything working but am focused on performance--I haven't seen a question like this asked, so here it goes:
I transform the UIImage into NSData and add it to the main NSCoding file (a plist, if it matters) for storage on the disk. If there is more than one image, the image names become sequential (e.g. image1, image2, image3.) I then use the image both in a UITableView (as a resized thumbnail) and in a detail view. The negative side to this is that the plist balloons in size, which means slow initial load times when I use it because it's loading all of the NSData at once.
What is the best way to eliminate this problem and only force the loading of one image at a time?
What I've thought of:
I write the NSData to the disk, add an array to the plist, and add only a reference to the filename of each image to the array. I suppose I'd then reference the image filename at specified position, find it on the disk, and use it?
Any and all thoughts would be most welcome. I'm more stuck on the conceptual implementation than anything else and, funnily enough, this is not an oft-discussed topic.
Thanks,
EDIT:
As requested below, here's an example of taking an image and turning it into NSData:
UIImage *originalImage;
NSData *imageData = UIImagePNGRepresentation(originalImage);
//I save it all to the app's document directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//I am using the images in a tableView and thus found it easiest to append the row number to each image filename.
//'y' below is just an integer that corresponds to the number of items in the master array
NSString *fileName = [NSString stringWithFormat:#"image%d.png",y];
documentsDirectory = [documentsDirectory stringByAppendingPathComponent:fileName];
[imageData writeToFile:documentsDirectory atomically:YES];
// NSLog(#"The filename is %#", fileName);
//newObject is an instance of my NSCoding object
[newObject setImageName: fileName];
Your suggestion is sound. Imagine a relational database. I would never save the images in one field as a blob. A filesystem is a very good place to save binary date in large amounts. It also gives you easy ways to duplicate files and so on.
So saving a reference in your plist will make parsing really fast and lazy loading an easy task to process images only when you need them.
iOS Programming: The Big Nerd Ranch Guide has a perfect example of this solution in chapter 14 of the 3rd Edition. Just download the code that is accessible from their site for a completed solution.
iOS Programming 3rd edition
Download Solutions
In my iPhone App I want to retrieve image from (stored in ) sqlite database table in "BLOB" datafield.
For that I am storing my image in NSData using code
NSData *imageData = UIImagePNGRepresentation(image);
and I am also able to retrieve image from NSData -> UIImage by code
self.img1=[UIImage imageWithData:imageData];
And displaying Image into imageView by
imageView2.image=img1;
I am storing image (in NSData form) into sqlite database table column (of BLOB Datatype) successfully.
I am using below code to retrieve image from database
NSData *imageData2 = [[arraySelect objectAtIndex:0] valueForKey:#"image_column"];
NSLog(#"imagedata2 in retrive :: %#",imageData2);
in NSLOG i am getting the same data stored in database column (in blob datatype "NSData form" )
Now I am retrieving image by
(while debugging it crashes here and showing meaasge EXE_BAD_ACCESS)
self.img3=[UIImage imageWithData:imageData2];
imageview3.image=img3;
But I am not getting that image in imageView.
I checked all outlets but they are ok.
So please Help and Suggest what I should do to get image in imageView from database.
Thanks.
#Prerak i think this will help you something..and solve your problem
http://dblog.com.au/iphone-development-tutorials/iphone-sdk-tutorial-reading-data-from-a-sqlite-database/