Hey all. I'm really new at this obj-c/xcode stuff. I'm trying to load the background of my xib file. To do this i'm using a UIImageView and populating that with an image I found from the net. the problem with that is that it's REALLY slow. Feels like it's crashing but it's not. I was told to use an NSURLConnection to fix the problem but don't know how. Here's the code i was using previously.
wallpaper.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://mysite.com/mobile/wallpaperR.asp?id=%i",customerID]]]];
How do i translate the above code into the NSURLConnection equivalent?
NSURLConnection will download the data in a new thread, so you app will feel much faster.
It is pretty easy to implement but it does require you to understand the concept of delegation.
I have a useful class I created to handle image downloads on separate threads, I will share the code with you, with comments to let you know what is going on:
AsyncImage.h
AsyncImage.m
If you need help implementing it just leave a comment and I can help you get it working, I remember this used to be pain for me too when I started developing.
You need to do parsing for this as you are using the webservice.Like this
-(void)startParsingForPhotoAlbumList:(NSString*)providerIdString
{
NSString *urlString = [NSString stringWithFormat:#"http://YourUrl/showalbumxml.php?id=%#&show=show",providerIdString];
NSURL *xmlURL = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:xmlURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0]autorelease];
NSURLResponse *returnedResponse = nil;
NSError *returnedError = nil;
NSData *itemData = [NSURLConnection sendSynchronousRequest:request returningResponse:&returnedResponse error:&returnedError];
self.xmlParser = [[NSXMLParser alloc] initWithData:itemData];
[xmlParser setDelegate:self];
[xmlParser parse];
}
and need to implement parser's delegate method as an example.
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
if ([[[resultArray objectAtIndex:1]objectForKey:#"Transaction"]isEqualToString:#"Myapp/snaps"])
{
[(LoginViewController *)obj getRegisterResult:resultArray];
}
}
Then in your Viewcontroller access the data,from parsing you need to pass objects,using array or dictionary.
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:itemImagePath]];
UIImage *image = [[UIImage alloc] initWithData:imageData];
There is an example which may help:
NSURLConnection loading image example
Related
I use AFImageRequestOperation to download some icons, meanwhile use SDWebImage to download some pics for main view. Each AFImageRequestOperation is added to my publicOperationQueue defined in app delegate, its maxConcurrentOperationCount is set to 10. Strange thing is that sometimes one or two of my 10+ icons will be replaced by some pic in main view, which should be downloaded by SDWebImage. And when I set a larger maxConcurrentOperationCount which is bigger than my icon counts, it works fine. I doubt if it has something to do with multiple NSOperationQueues sharing some resources and maxConcurrentOperationCount. Any one could help?
//below is the icon downloading code
//============================//
for(NSString *url in picUrls)
{
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
[urlRequest setHTTPShouldHandleCookies:NO];
[urlRequest addValue:#"image/*" forHTTPHeaderField:#"Accept"];
AFImageRequestOperation *requestOperation = [[AFImageRequestOperation alloc] initWithRequest:urlRequest];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject){
NSString *imageName = trimNilOrNuLL([url lastPathComponent]);
if(imageName.length > 0)
{
NSData *imageData = UIImagePNGRepresentation(responseObject);
[imageData writeToFile:[path stringByAppendingPathComponent:imageName] atomically:YES];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error){
NSLog(#"%#",error);
}];
[[AppShare appDelegate].publicOperationQueue addOperation:requestOperation];
}
//============================//
and for SDWebImage, I use - (void)setImageWithURL:(NSURL *)url method in UIImageView+WebCache category to download pic
OK,From the question found that you are using AFNetworking .Then for image downloading why dont you use the UIImageView Extention of AFNetworking?
You dont have to implement any queue or anything for this
some code like this is enough i think
[self.imageview setImageWithURL:url placeholderImage:nil];
The code below works fine if I give statically but
imgDescView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:
[NSURL URLWithString:[NSString stringWithFormat:#"http://4cing.com/mobile_app/uploads/pageicon/6.jpg"]]]];
Same code - I am passing the image url name dynamically it's not working
imgDescView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:
[NSURL URLWithString:[NSString stringWithFormat:#"%#",[imagename objectAtIndex:0]]]];
You need to verify the NSArray contents. Log out the objects of the array:
NSLog(#"imagename = %#",[imagename description]);
Also, a side-note - might want to think about loading that image dynamically. I wrote a class that makes this pretty painless:
https://stackoverflow.com/a/9786513/585320
The answer is geared toward using in TableViews (where lag would really hurt performance), but you can (and I do) use this for any web image loading. This keeps the UI fluid and is very fast.
NSMutableArray *imagename = [[NSMutableArray alloc] initWithObjects:#"http://4cing.com/mobile_app/uploads/pageicon/6.jpg", nil];
UIImageView *imgDescView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0, 200, 200)];
imgDescView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:
[NSURL URLWithString:[NSString stringWithFormat:#"%#",[imagename objectAtIndex:0]]]]];
it is working ... i think u r not creating array properly.
Hi create url in this manner
[NSURL URLWithString:[[NSString stringWithFormat:#"%#",[imagename objectAtIndex:0]] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]
i think it will work and will resolve ur problem.
I am trying to save an image to the photo library from a website which is opened in an uiwebview.The link is not just an image link where NSURLConnection can be used to download.I want to achieve the download by long pressing the image in UIWebView just as it can be done in safari. How can i achieve this..is it possible??
NSURL *url = [NSURL URLWithString:link];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
NSURLResponse *response = NULL;
NSError *requestError = NULL;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&requestError];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
the response string contains complete information
Sorry to ask, but why do you use an UIWebView to only load an image. The UIImageView class constructor imageWithContentsOfURL: would do the job perfect.
Then you can just use an UIPopoverController for presenting a UIViewController with an UIButton calling UIImageWriteToSavedPhotosAlbum (http://goo.gl/uAJYS) to save the UIImage from your UIImageView directly into the users camera roll.
For Optimisation use an UITableViewController instead of the UIViewController - more the default iOS look&feel - and present the UIPopoverController with a small delay by overwriting the UIResponder methods on the UIImageView.
// EDIT: If you really mean how to get the exact behaviour of the Safari to save any image in the dom tree, i am a bit stumped. Maybe someone else can contribute some information on that.
I am trying to send a query as part a the URL to obtain an XML file, and then trying to parse the XML file using NSXMLParser and initWithContentsOfURL. However the parser is not able to parse the file. I tested the parser with the same file, but this time the file was saved on the server (it was not being generated) and it worked just fine, so I know it is not a problem with the parser.
I have come to think that it does not parse it because I need to load the file before I try to parse it, or give the initWithContentsOfURL time to load the contents. So I tried to put those contents in a NSString and a NSData and using a sleep function as well as using a block but that did not work either.
What would be the best way to go about this problem?
Here is some of the code:
NSString *surl = [NSString stringWithFormat:#"http://lxsrv7.oru.edu/~maria_hernandez/query.xml"];
url = [NSURL URLWithString:surl];
NSString *curl = [[NSString alloc] initWithContentsOfURL:url];
NSLog(#"URL: %#", surl);
NSLog(#"URL Content: %#", curl);
SXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:receivedData];
//Other stuff we have tried:
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:surl] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLResponse = nil;
NSError = nil;
receivedData = [NSURLConnection sendSynchronousRequest: theRequest returningResponse: &theResponse error: &error];
Let me know if you have more questions or if you wish to see more code.
Thanks!
have you tried setting a delegate for the NSXMLParse that implements the NSXMLParserDelegate which has events for parsing the document
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSXMLParser_Class/Reference/Reference.html
I'm making an app that allows you to browse through pictures from a website. I'm currently downloading the images using:
UIImage *myImage = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url]]];
which works great, but can be time consuming. I start off by downloading 20 images, but I can't do anything until after the 30 or so seconds it takes to download them all.
This one time wait isn't all that bad, but if I want to download the 21st-40th images, I would have to wait another 30 seconds.
Basically, is there a way I can download these images one at a time without holding up any of my animations?
Thanks.
Sure, put the download task in a thread, and use a callback to let your program know when each image is finished. Then you can draw your images as they finish loading, and not hold up the rest of the app. This link has a template that you can use as an example.
Here's a quick and dirty example:
- (void)downloadWorker:(NSString *)urlString
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [[UIImage alloc] initWithData:data];
[self performSelectorOnMainThread:#selector(imageLoaded:)
withObject:image
waitUntilDone:YES];
[image release];
[pool drain];
}
- (void)downloadImageOnThread:(NSString *)url
{
[NSThread detachNewThreadSelector:#selector(downloadWorker:)
toTarget:self
withObject:url];
}
- (void)imageLoaded:(UIImage *)image
{
// get the image into the UI
}
Call downloadImageOnThread for every image you want to load, each will get its own thread, and you'll get calls to imageLoaded as each one completes.
While loading the image on a background thread is definately the solution, I'd use an NSOperation and an NSOperationQueue instead of dealing with the threads yourself (this is the way Apple recommend to deal with threading problems like this!)
The NSOperationQueue will deal with starting/stopping the threads nicely and you can choose how many to run at once etc. It's basically a the same as the other answers but you get a little more control.
There's a tutorial here that looks pretty good.
yeah you can use a secondary thread, and do a lot of work OR you could use things that apple gives us.
NSURLDownload, doesn't "lag" your main thread, You spawn it with a method and you set a endSelector, the endSelector will get called when the download is done.
Spawning a secondary thread for this is not really what you should do.
here you got some code from my app wich does it work perfectly without giving a beach ball of doom.
- (void)downloadAvatar:(NSString *)URL{
NSURL *url = [[NSURL alloc] initWithString:URL];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
[url release];
NSURLDownload *download = [[NSURLDownload alloc] initWithRequest:request delegate:self];
NSString *path = [[NSString alloc] initWithFormat:#"%#data/%#.jpg",[[BFAppSupport defaultSupport] bfFolderPath],[[xfSession loginIdentity] userName]];
[download setDestination:path allowOverwrite:YES];
[download release];
[path release];
[request release];
}
- (void)downloadDidFinish:(NSURLDownload *)download{
NSString *path = [[NSString alloc] initWithFormat:#"%#data/%#.jpg",[[BFAppSupport defaultSupport] bfFolderPath],[[xfSession loginIdentity] userName]];
NSData *imageData = [[NSData alloc] initWithContentsOfFile:path];
if( [imageData length] < 10 ){
[self performSelector:#selector(downloadAvatar:) withObject:#"http://media.xfire.com/xfire/xf/images/avatars/gallery/default/xfire160.jpg" afterDelay:0.0];
[imageData release];
[path release];
return;
}
NSImage *theImage = [[NSImage alloc] initWithData:imageData];
[imageData release];
[path release];
[yourImage setImage:theImage];
[theImage release];
}
- (void)download:(NSURLDownload *)aDownload didFailWithError:(NSError *)error{
NSLog(#"Avatar url download failed");
}
The code is a bit ugly, but its not hard to change it as you got the 3 things you need, the method that starts the download and 2 that handle or an error or the finish.
You can also use autoreleased objects some more, but in terms of performance I like using it without autoreleased objects when I can.