Getting an image from a remote server - iphone

In my iPhone app I have to show the preview of the thumbnail image. That preview image actually we will get from remote server. Before loading that big image on screen I have to show preloading view but actually this preloading view is not appearing on the screen.
The code I used is:
zoomview=[[UIView alloc]initWithFrame:CGRectMake(0,0,320,460)];
imageloadview.backgroundColor=[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.5];
[self.view addSubview:imageloadview];
[activity startAnimating];
[self loadimageview];
Here instead of loading the zoom view on screen this loading view method is executing but I want to display preloading view before getting the big image from the server.
-(void)loadimageview
{
imageloader.image=[UIImage imageNamed:#""];
[self loadimage];
}
-(void)loadimage
{
NSData *data=[NSData dataWithContentsOfURL:[NSURL URLWithString:[picfullarray objectAtIndex:0]]];
if([data length]==0)
{
NSLog(#"data");
}
else
{
UIImage *image1=[UIImage imageWithData:data];
imageloader.image=image1;
[activity stopAnimating];
[loadlabel1 setText:#""];
}
}
How do I show preloaded view on iPhone screen before getting the big image from the server?

You have to load the image asynchronously with NSURLRequest.
Make the class implement NSURLRequestDelegate protocol. In the function - (void)connectionDidFinishLoading:(NSURLConnection *)connection of NSURLRequestDelegate, add the code to update the view when the loading is completed.
// You must declare NSMutableData somewhere to write received data in delegate method
// - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
// I assume the instance of NSMutableData is named data
// If you want to load multiple images, it is a bit tricky, but doable.
// I'll post the code if that is what you need.
- (void) connectionDidFinishLoading: (NSURLConnection *) connection {
// You may want to declare a instance member to store the image (UIImage*), so that you can restore the view if the view is unloaded due to memory warning.
UIImage* image = [UIImage imageWithData: data];
data = nil; // Important. You should clean the data, or it will take up space.
// You may want to check whether image != nil, since the incoming data may not be image
[self displayImage: image];
}
- (void) displayImage: (UIImage*) aImage {
imageloader.image = aImage;
// Depending on how UIImageView is initialized, you may need to call sizeToFit.
// Or set the frame accordingly
[activity stopAnimating];
[loadlabel1 setText: #""];
}

I'd suggest using SDWebImage framework. It already has async image loading capability, and it's super easy to use.
[imageView.image setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
You don't have to worry about messing with NSURLConnection, maintaining NSData, etc..

There is also AFNetworking which has a way to do this easily.
https://github.com/AFNetworking/AFNetworking/wiki/Getting-Started-with-AFNetworking
Check out the "Download and Display Images" section.

Related

Resize taking photo through default camera

I am using UIImagePickerViewController to take photo from iPhone default camera in my App and storing it in Document directory. It is taking long time to complete the process and also it is displaying very slowly on tableview.Does resizing image help here?
-(IBAction)takePhoto:(id)sender
{
if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera])
{
imgPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:imgPicker animated:YES];
}
}
-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *pickedImage = [info objectForKey:UIImagePickerControllerOriginalImage];
[self dismissModalViewControllerAnimated:YES];
NSData *imageData = UIImagePNGRepresentation(pickedImage);
NSString *path = [SAVEDIMAGE_DIR stringByAppendingPathComponent:#"image.png"];
[imageData writeToFile:path atomically:YES];
}
Sure!
I do the following in my app:
store the image in an image store in a background thread
create a thumbnail (also in background thread), store this thumbnail in a core data table; in an field of type ID
So I get a smooth UI, where the User can take about a picture every 2 seconds.
The smoothness of the table views are also no problem. Although I populate the TableViewCells ImageViews also from a background-thread (preparing the image in the background, assigning to the UIImageView in the mainthread, of course).
I hope, that helps you. Further questions are welcome.
Some code for your convenience:
As Imagestore I use these: https://github.com/snowdon/Homepwner/blob/master/Homepwner/ImageStore.m
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[self performSelectorInBackground:#selector(saveFoto:) withObject:info];
// you should add some code for indicating the save process
}
// saves the photo in background-thread
-(void)saveFoto:(NSDictionary*)info {
// the following is some stuff that I do in my app - you will probably do some other things
UIImage *image = [ImageHelper normalizeImageRotation: [info objectForKey:UIImagePickerControllerOriginalImage]];
UIImage *thumb = [ImageHelper image:image fitInSize:CGSizeMake(imgWidth, imgWidth) trimmed:YES];
NSString *myGUID = myGUIDCreator();
[[ImageStore defaultImageStore] setImage:image forKey:myGUID];
myCoreDataManagedObject.thumb = thumb;
[self performSelectorOnMainThread:#selector(showYourResultsInTheUI:) withObject:thumb waitUntilDone:NO]; // every UI-Update has to be done in the mainthread!
}

objective - C : Loading image from URL?

Sorry for question title. I can not find a suitable title.
I have UITableView content images from url when i open the UITableView the View did not show until the images loaded and that takes along time.
I get the images from JSON by php.
I want to show the table and then images loading process.
This is code from my app:
NSDictionary *info = [json objectAtIndex:indexPath.row];
cell.lbl.text = [info objectForKey:#"title"];
NSString *imageUrl = [info objectForKey:#"image"];
cell.img.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrl]]];
[cell.img.layer setBorderColor: [[UIColor blackColor] CGColor]];
[cell.img.layer setBorderWidth: 1.0];
return cell;
Sorry my english is weak.
Perform the web request on a separate thread, to not block the UI. Here is an example using NSOperation. Remember to only update the UI on the main thread, as shown with performSelectorOnMainThread:.
- (void)loadImage:(NSURL *)imageURL
{
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(requestRemoteImage:)
object:imageURL];
[queue addOperation:operation];
}
- (void)requestRemoteImage:(NSURL *)imageURL
{
NSData *imageData = [[NSData alloc] initWithContentsOfURL:imageURL];
UIImage *image = [[UIImage alloc] initWithData:imageData];
[self performSelectorOnMainThread:#selector(placeImageInUI:) withObject:image waitUntilDone:YES];
}
- (void)placeImageInUI:(UIImage *)image
{
[_image setImage:image];
}
You have to use NSURLConnection and NSURLRequest. First create and show your empty table view (maybe with placeholder images, that are stored locally in the app). Then you start sending requests. These requests will run in the background and you (the delegate) will be notified when a request is completed. After that you can show the image to the user. Try not to load all the images at once if you have a lot of them. And don't load the ones that are invisible to the user, only load those if he scrolls down.
There is a UITableView lazy image loading example that Apple provided: https://developer.apple.com/library/ios/#samplecode/LazyTableImages/Introduction/Intro.html
Hopefully it's what you were looking for
This is among very common thing we do in our application.
You simply can have store the URLs in a persistent store e.g array or db & can get the images using Operation queue to download faster. You can set the priorities, cancel operations at anytime etc. Also, the application respond time will be quicker.

How to reuse a UIImage

I'm using some sample code I got from a tutorial to create basically a snapshot using AVCamRecorder. It doesn't save a picture, it just displays it in a little rect under the live camera view whenever I click a button. It seemed to be allocating more and more memory each time I clicked the button to update the image, so I put an if (image) {[image release]} and then continued with the rest of the code to capture the image. The problem I ran into there is that eventually I hit an EXC_BAD_ACCESS if I click the button fast enough repeatedly. I tried inserting an if (image) immediately before assigning it to my view, but I still get EXC_BAD_ACCESS. I tried adding an [NSThread sleepForTimeInterval:1] at the end, but that didn't help either. I still get the EXC_BAD_ACCESS after clicking the button several times. Is there a proper way to reuse this view? Thanks
if (image) {
[image release];
exifAttachments = nil;
}
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:stillImageConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
exifAttachments = CMGetAttachment(imageDataSamplebuffer, kCGImagePropertyExifDictionary, NULL);
if (exifAttachments) {
// NSLog
} else {
// NSLog
}
NSData *imagedata = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
image = [[UIImage alloc] initWithData:imageData];
if (image) {
self.capturedPicView.image = image;
}
}];`
Is the image variable declared as __block? If not, you may get all sorts of weird things because you can't modify it within a block.
You probably don't need a separate image variable - just do:
self.capturedPicView.image = [[[UIImage alloc] initWithData:imageData] autorelease];
in your block.
P.S. And it looks like your original memory leak was due to not releasing the new image - you could have added autorelease to UIImage creation or just release it right after assigning (UIImageView.image retains it anyway):
image = [[UIImage alloc] initWithData:imageData];
if (image) {
self.capturedPicView.image = image;
[image release];
}

How to know when UIimageView finished loading?

In my view controller, how can I know when a certain UIImageView has finished loading (large jpeg from documents directory)? I need to know so that I can then swap a placeholder low-res imageview with this hi-res imageview. Do I need to create a custom callback to know this? Any way is fine.
By the way, here is a snippet of code where I load the image:
NSString *fileName = [NSString stringWithFormat:#"hires_%i.jpg", currentPage];
NSString *filePath = [NSString stringWithFormat:#"%#/BookImage/%#", [self documentsDirectory], fileName];
hiResImageView.image = [[[UIImage alloc] initWithContentsOfFile:filePath] autorelease];
UIImageView isn't doing any loading at all. All the loading is being done by [[UIImage alloc] initWithContentsOfFile:filePath], and your thread is blocked while the file is loaded (so the load is already complete by the time that call finally returns).
What you want to do is something like this:
- (void)loadImage:(NSString *)filePath {
[self performSelectorInBackground:#selector(loadImageInBackground:) withObject:filePath];
}
- (void)loadImageInBackground:(NSString *)filePath {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:filePath];
[self performSelectorOnMainThread:#selector(didLoadImageInBackground:) withObject:image waitUntilDone:YES];
[image release];
[pool release];
}
- (void)didLoadImageInBackground:(UIImage *)image {
self.imageView.image = image;
}
You would set up self.imageView to display the low-res image and then call loadImage: to load the high-res version.
Note that if you call this repeatedly before didLoadImageInBackground: gets called from earlier calls, you may cause the device to run out of memory. Or you might have the image from the first call take so much longer to load than image from the second call that didLoadImageInBackground: gets called for the second image before it gets called for the first. Fixing those issues is left as an exercise for the reader (or for another question).

Code works in sim, but only sometimes on device

The code to set image to imageView is:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
SDWebImageManager *manager = [SDWebImageManager sharedManager];
UIImage *cachedImage = [manager imageWithURL:_url];
if (cachedImage)
{
_imageView.image = cachedImage;
[spinner stopAnimating];
}
else
{
[spinner startAnimating];
[manager downloadWithURL:_url delegate:self];
}
// Configure the view for the selected state
[super setSelected:selected animated:animated];
}
- (void)webImageManager:(SDWebImageManager *)imageManager
didFinishWithImage:(UIImage *)_image
{
[spinner stopAnimating];
_imageView.image = _image;
[self setNeedsLayout];
}
I use SDWebImage
this works every time in simulator, but when I run the app in the device (Ipod touch)
80 % of the images is just black, but if I go to another view and back the images are set (from cache).
I have try to set delay on _imageView = _image, but change.
(Answered in a question edit. Converted to a community wiki answer. See Question with no answers, but issue solved in the comments (or extended in chat) )
The OP wrote:
Now I have try the code on a Iphone 3gs and it works perfect, can understand why it wont work on ipod touch.
When i Compiled and Run as "Release" it works on ipod, but not in as debugger. Wierd..