Memory allocation, release and NSURLConnection in iPhone app - iphone

I'm hoping someone can help me with this. I'm struggling to find an answer to what should be an easy question. By the way, this is my first major obj-c project after years of using c and c# so feel free to point out things I'm failing on.
I have an iPhone app designed to load an album of photos into a UIScrollView. It also has a random image function which uses the same process but only displays a single image. It works like so:
Read an external XML feed (stored on ruby-on-rails website) which contains a path to a random url of photo once parsed.
Content of URL is downloaded using NSURLConnection to NSData.
ScrollView is created and pushed
Subclassed UIView allocs an UIImageView, allocs a UIImage with the NSData which, inits the UIImageView with the UIimage and finally adds the imageview to the UIView.
The parent view then adds the UIView to the UIScrollView which is then pushed to the front.
This process occurs again when when the next random image is required. It also uses the same process when displaying an entire album of images except several UIViews are added to the UIScrollView.
The problem is, despite using release and delloc where appropriate, the activity tool indicates that the memory used by NSURLConnection and UIImage isn't being released from memory when the next image is requested. This is further proven by building the app to the iPhone. Requesting several images in a row causes the app the crash presumably from memory consumption.
Below is some of the code as I'm unable to post the entire project due to contractual agreements.
URLDownload class (uses DataDownload)
#implementation URLDownload
-(NSData *)GetURL:(NSURL *)strURL
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
DataDownload *request = [DataDownload alloc];
request.strURL = strURL;
[request init];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
while (request.isLoading && [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
[pool release];
return [request urlData];
[request release];
}
DataDownload class
#implementation DataDownload
#synthesize urlData, connection, strURL, isLoading;
- (id)init
{
if(self = [super init])
{
self.isLoading = YES;
NSURLRequest *dataRequest = [NSURLRequest requestWithURL:self.strURL
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:60];
/* establish the connection */
self.connection = [[NSURLConnection alloc]
initWithRequest:dataRequest
delegate:self
];
if (connection == nil) {
self.urlData = nil;
} else {
self.urlData = [NSMutableData data];
}
}
return self;
}
- (void)dealloc {
[connection cancel];
[connection release];
[urlData release];
[strURL release];
[super dealloc];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
return nil;
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse*)response
{
[urlData setLength:0];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)incrementalData
{
[self.urlData appendData:incrementalData];
}
-(void)connectionDidFinishLoading:(NSURLConnection*)connection
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
self.isLoading = NO;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
self.isLoading = NO;
}
#end
ImageView subclass
#implementation ImageView
#synthesize strURL, imvImageView, image, currentlyRotated, imgOptionsView, startDate;
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.imvImageView = [UIImageView alloc];
if (self.strURL != nil){
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
NSData *datImageData = [NSData dataWithContentsOfURL: [NSURL URLWithString:self.strURL]];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
self.image = [UIImage imageWithData: datImageData];
CGSize imgSize = image.size;
CGFloat fltWidth = imgSize.width;
CGFloat fltHeight = imgSize.height;
[imvImageView initWithImage:image];
// If landscape rotate image
if (fltWidth > fltHeight){
imvImageView.frame = CGRectMake(-80.0, 80.0, 480.0, 320.0);
CGAffineTransform rotate = CGAffineTransformMakeRotation(-1.57079633);
[imvImageView setTransform:rotate];
self.currentlyRotated = YES;
}else{
imvImageView.frame = CGRectMake(0.0, 0.0, 320.0, 480.0);
self.currentlyRotated = NO;
}
[image release];
}else{
self.image = [UIImage alloc];
[imvImageView initWithImage:image];
[image release];
}
[self addSubview:imvImageView];
}
[imvImageView release];
return self;
}
- (void)drawRect:(CGRect)rect {
// Drawing code
}
- (void)dealloc {
[strURL release];
[imvImageView release];
[image release];
[imgOptionsView release];
[startDate release];
[super dealloc];
}
Sample code of how images are being displayed
- (void)displayImage:(NSString *)strURL {
NSString *strFullURL = #"http://www.marklatham.co.uk";
strFullURL = [strFullURL stringByAppendingString:strURL];
self.scroller = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0)];
[scroller setContentSize:CGSizeMake(320.0, 540.0)];
[self.view addSubview:scroller];
CGRect rect = CGRectMake(0.0, 0.0, 320.0, 480.0);
self.imageView = [ImageView alloc];
imageView.strURL = strFullURL;
[imageView initWithFrame:rect];
[scroller addSubview:imageView];
[scroller release];
[imageView release];
}
The following images show all allocations to illustrate what's happening. 1 shows alloc on startup, 2 shows after first image is loaded and 3 after after second image.
http://www.gretanova.com/misc/iphone/1.png & 2.png & 3.png
Thanks everyone,
Lee

A couple of things stick out. For example within the URLDownload class the call to [request release] will never be reached as its placed after the return statement
return [request urlData];
[request release];

Related

Can i load images from the device's documents directory to AsyncImageView?

Actually, I am not sure about this but i have this condition where i check whether internet is available or not and accordingly load the image into AsyncImageView. It works fine when i load any image from the internet, but is it possible to load a local image to AsyncImageView?
I guess you mean AsyncImageView by Nick Lockwood? This is simply a category to UIImageView, so when you have the image already, why not set the image property directly?
Actually i got the solution to this problem.All i did was this
NSURL *theURL = [NSURL fileURLWithPath:#"/Users/gaurav/Library/Application Support/iPhone Simulator/5.0/Applications/AC6E9B2E-DB25-4933-A338-755B134E1A61/Documents/Attachment290_294_1344928691.jpeg"];
NSLog(#"local URl is::%#",theURL);
[self.asyncimageview loadImageFromURL:theURL];
Perhaps the following will help you.
Make a new file
Inherit from UIImageView
Copy/Paste the following code.
import
import "ASIHTTPRequest.h"
#interface AsynchronousImageView : UIImageView{
NSMutableData *data;
UIActivityIndicatorView *activityIndicator;
NSString *urlString; // key for image cache dictionary
ASIHTTPRequest *requestLocal;
}
#property(nonatomic,assign) UIActivityIndicatorView *activityIndicator;
(void)loadImageFromURLString:(NSString *)theUrlString;
(void)loadImageFromNSURL:(NSURL *)theUrl;
(void)loadImageFromFile:(NSString *)filePath;
-(void) showLoader;
-(void) stopLoader;
#end
Then In .m file paste the following.
import "AsynchronousImageView.h"
import "ASIDownloadCache.h"
#implementation AsynchronousImageView
#synthesize activityIndicator;
(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
//[self setContentMode:UIViewContentModeScaleAspectFit];
}
return self;
}
-(void)dealloc
{
if (requestLocal) {
[requestLocal setDelegate:nil];
}
requestLocal = nil;
activityIndicator = nil;
[super dealloc];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
(void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
-(void) showLoader{
if(activityIndicator == nil){
activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[self addSubview:activityIndicator];
activityIndicator.frame = CGRectMake(self.bounds.size.width / 2.0f - activityIndicator.frame.size.width /2.0f, self.bounds.size.height / 2.0f - activityIndicator.frame.size.height /2.0f, activityIndicator.frame.size.width, activityIndicator.frame.size.height);
[activityIndicator release];
}
[activityIndicator startAnimating];
}
-(void) stopLoader{
if(activityIndicator){
[activityIndicator stopAnimating];
[activityIndicator removeFromSuperview];
activityIndicator = nil;
}
}
(void)loadImageFromFile:(NSString *)filePath {
UIImage *img = [UIImage imageWithContentsOfFile:filePath];
[self setImage:img];
[self stopLoader];
}
(void)loadImageFromURLString:(NSString *)theUrlString
{
/if (requestLocal) {
[requestLocal setDelegate:nil];
}/
requestLocal = nil;
[self showLoader];
NSURL *url = [NSURL URLWithString:theUrlString];
requestLocal = [ASIHTTPRequest requestWithURL:url];
[requestLocal setDelegate:self];
[requestLocal setDidFailSelector:#selector(requestFailed)];
[requestLocal setDownloadCache:[ASIDownloadCache sharedCache]];
[requestLocal setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
[requestLocal startAsynchronous];
self.image = [UIImage imageNamed:#"playerDefault.png"];
}
-(void)loadImageFromNSURL:(NSURL *)theUrl
{
if (requestLocal) {
[requestLocal setDelegate:nil];
}
requestLocal = nil;
requestLocal = [ASIHTTPRequest requestWithURL:theUrl];
[requestLocal setDelegate:self];
[requestLocal setDidFailSelector:#selector(requestFailed)];
[requestLocal startAsynchronous];
}
(void)requestFinished:(ASIHTTPRequest *)request
{
requestLocal = nil;
[self stopLoader];
UIImage *tempArt = [UIImage imageWithData:[request responseData]];
if (tempArt) {
self.image = tempArt;
}
[data release];
data = nil;
}
-(void)requestFailed:(ASIHTTPRequest *)request{
requestLocal = nil;
[self stopLoader];
[data release];
data = nil;
}
#end
Then in your ViewComtroller .h import AsycnhronousImageView class and write this
Make the IBOutlet of your image like this.
IBOutlet AsycnhronousImageView *image;
Change the class in xib AsycnhronousImageView rather than UIImage View
Call the following Method
(void)loadImageFromFile:(NSString *)filePath;

iOS NSURLConnection memory leak

i got code like this
#import "UIWebImageView.h"
#interface UIWebImageView (hiddenMethods)
- (void) initDefaults;
#end
#implementation UIWebImageView (hiddenMethods)
- (void) initDefaults
{
self.showActivityIndicator = NO;
self.activityIndicatorStyle = UIActivityIndicatorViewStyleWhite;
self.activityIndicatorSize = CGSizeMake(20.0, 20.0);
//data = [[NSMutableData alloc] init];
}
#end
#implementation UIWebImageView
#synthesize showActivityIndicator;
#synthesize activityIndicatorStyle;
#synthesize activityIndicatorSize;
- (id) init
{
if (self = [super init])
{
[self initDefaults];
}
return self;
}
- (void) loadFromURL:(NSString *) url
{
[self.image release];
self.image = nil;
request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:30.0];
if (connection == nil)
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
// activity indicator start
indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:activityIndicatorStyle];
indicator.frame = CGRectMake((self.frame.size.width - activityIndicatorSize.width)/2, (self.frame.size.height - activityIndicatorSize.height)/2,
activityIndicatorSize.width, activityIndicatorSize.height);
[self addSubview:indicator];
[indicator startAnimating];
}
- (void) dealloc
{
[data release];
[indicator release];
[connection release];
[super dealloc];
}
#pragma mark -
#pragma mark connection delegate
- (void) connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData
{
if (data == nil)
data = [[NSMutableData alloc] initWithCapacity:2048];
[data appendData:incrementalData];
}
- (void) connectionDidFinishLoading:(NSURLConnection *)theConnection
{
self.image = [UIImage imageWithData:data];
[indicator removeFromSuperview];
//data = nil;
[data release], data = nil;
[connection release], connection = nil;
[indicator release], indicator = nil;
}
- (void) connection:(NSURLConnection *)theConnection didFailWithError:(NSError *)error
{
self.image = [UIImage imageNamed:#"icon.jpg"];
[indicator removeFromSuperview];
//data = nil;
[data release], data = nil;
[connection release], connection = nil;
[indicator release], indicator = nil;
}
I'm using this for downloading images from web. one image for every cell in in table. and it works fine when image is not going out of the screen. BUT when u scrolling tableView fast and some images did not finished loading while they are on screen there huge memory leaks.
i know where is the leak and why its leaking. but i can't find solution.
any thoughts ?
thank you
PS sorry for my english
UPDATE
here is a code for adding images into tableView
UIWebImageView *tmpImageView = [[UIWebImageView alloc] initWithFrame:CGRectMake(0, 0, 57, 76)];
tmpImageView.showActivityIndicator = YES;
tmpImageView.contentMode = UIViewContentModeScaleAspectFit;
tmpImageView.activityIndicatorStyle = UIActivityIndicatorViewStyleGray;
[tmpImageView loadFromURL:[[tableArray objectAtIndex:indexPath.row] objectForKey:#"picurl"]];
[cell addSubview:tmpImageView];
[tmpImageView release];
and I'm repeating = ) its leaking only when it not finished loading and went off the screen while scrolling
The leaks are happening due to the allocation of UIWebImageView objects recursively (considering you are using reusable cells).
you should change your code to:
UIWebImageView *tmpImageView = [cell viewWithTag:2011];
if(!tmpImageView)
{
tmpImageView = [[UIWebImageView alloc] initWithFrame:CGRectMake(0, 0, 57, 76)];
tmpImageView.showActivityIndicator = YES;
tmpImageView.tag = 2011;
tmpImageView.contentMode = UIViewContentModeScaleAspectFit;
tmpImageView.activityIndicatorStyle = UIActivityIndicatorViewStyleGray;
[cell addSubview:tmpImageView];
[tmpImageView release];
}
[tmpImageView loadFromURL:[[tableArray objectAtIndex:indexPath.row] objectForKey:#"picurl"]];
you have to handle for the showActivityIndicator thing some how...based upon your code but the above mentioned change will remove your memory leaks.
Autorelase your NSURLConnection with this syntax
connection = [NSURLConnection connectionWithRequest:request delegate:self];
and delete your [connection release], connection = nil;

i want to save my pdf into my iphone, pdfs url are with me through parsing

I have parsed my xml and i got some images and their corresponding urls of pdf from server.so whenever i click on image i have their corresponding url of pdf.I am giving an alertView on click of images and when user select the download button of alertView it should download the pdf from url into my iphone device
CODE:-
#implementation SecondViewController
#synthesize scrollView,receivedData;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivedData appendData:data];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
[myIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhiteLarge];
myIndicator.hidesWhenStopped = YES;
[myIndicator startAnimating];
UIColor *background = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"iphone_landscape.png"]];
self.view.backgroundColor = background;
[background release];
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://litofinter.es.milfoil.arvixe.com/displayxml1.aspx"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:150.0];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
receivedData = [[NSMutableData data] retain];
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
int x=20,y=50;
appDelegate = (AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate];
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 45,320, 480)];
scrollView.contentSize = CGSizeMake(320,5000);
scrollView.showsVerticalScrollIndicator = YES;
for (Litofinter *lito in appDelegate.bookArray) {
if([appDelegate.currentButtonPressed isEqualToString:lito.cName])
{
NSLog(#"Count == %d ===",[lito.productsArray count]);
for (Products *prod in lito.productsArray) {
NSString * urlString = [prod.thumbnail stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
NSURL * imageURL = [NSURL URLWithString:urlString];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * image = [UIImage imageWithData:imageData];
[myIndicator stopAnimating];
[myIndicator removeFromSuperview];
UIButton *imageButton = [[UIButton buttonWithType:UIButtonTypeCustom]retain];
[imageButton setFrame:CGRectMake(x, y, 150, 200)];
[imageButton setImage:image forState:UIControlStateNormal];
[imageButton setTitle:prod.pdf forState:UIControlStateNormal];
[imageButton addTarget:self action:#selector(onTapBook:) forControlEvents:UIControlEventTouchUpInside];
[scrollView addSubview:imageButton];
x = x + 150;
if(x >300)
{
y = y +250;
x = 20;
}
}
}
}
[self.view addSubview:scrollView];
[connection release];
[receivedData release];
}
-(void)onTapBook:(id)sender{
UIButton *button = (UIButton *) sender;
appDelegate.currentBookPressed = [button currentTitle];
// viewController2 = [[PdfShowViewController alloc]initWithNibName:#"PdfShowViewController" bundle:nil];
// [self presentModalViewController:viewController2 animated:YES];
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Ver Catalogo!" message:#"" delegate:self cancelButtonTitle:#"Cancelar" otherButtonTitles:#"Ver on-line",#"Descargar",nil];
[alert show];
/*[NSString stringWithFormat:#"%#",appDelegate.currentBookPressed] */
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"Ver on-line"])
{
// i will show the pdf online here
}
else if([title isEqualToString:#"Descargar"])
{
// what to write to download the pdf
}
}
-(IBAction)onTapBack{
[self dismissModalViewControllerAnimated:YES];
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (void)dealloc {
[super dealloc];
[scrollView release];
}
#end
I would do it with NSURLConnection and then I would reuse same code above, because you have it already declared properly.
Save data to NSData and then with writeToFile save it to main bundle.
So here is some more explanation how I would do it.
There are several ways to do it.
Here is how to do it with NSData
NSData *myFile = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"your_url"]]; [myFile writeToFile:[NSString stringWithFormat:#"%#/%#", [[NSBundle mainBundle] resourcePath], #"yourfilename.pdf"] atomically:YES];
Also you can use ASIHTTPRequest library which has been discontinued by author, but still works like it should.
ASIHTTPRequest *myDownloadRequest = [ASIHTTPRequest requestWithURL:fileUrl];
[request setDownloadDestinationPath:[NSString stringWithFormat:#"%#/%#", [[NSBundle mainBundle] resourcePath], #"yourfilename.pdf"]];
But maybe easiest way of all because as I can see you have displayed pdf already, so it's contents are in receivedData is just to call
[receivedData writeToFile:[NSString stringWithFormat:#"%#/%#", [[NSBundle mainBundle] resourcePath], #"yourfilename.pdf"] atomically:YES];
So actually you can reuse code that you have already wrote in viewDidLoad, replace url if necessary and after connection is closed save file to disk.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://litofinter.es.milfoil.arvixe.com/displayxml1.aspx"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:150.0];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
receivedData = [[NSMutableData data] retain];
}

iPhone - Objective-C NSURL Memory Leaks galore

I am getting the following memory leak when using NSURL. I use this method in quite a few different places and receive memory leaks all the time using the Leaks instruments.
Object Management:
self.objManager = [[HJObjManager alloc] init];
NSString *cacheDirectory = [NSHomeDirectory() stringByAppendingPathComponent:#"/Library/Caches/App"];
HJMOFileCache *fileCache = [[[HJMOFileCache alloc] initWithRootPath:cacheDirectory] autorelease];
self.objManager.fileCache = fileCache;
fileCache.fileCountLimit = 100;
fileCache.fileAgeLimit = 60*60*24;
[fileCache trimCacheUsingBackgroundThread];
Where it's used:
HJManagedImageV *mi = [[[HJManagedImageV alloc] initWithFrame:CGRectMake(self.myHeaderView.profilePictureImageView.bounds.origin.x,
self.myHeaderView.profilePictureImageView.bounds.origin.y,
self.myHeaderView.profilePictureImageView.bounds.size.width,
self.myHeaderView.profilePictureImageView.bounds.size.height)] autorelease];
mi.layer.masksToBounds = YES;
mi.layer.cornerRadius = 8.0;
mi.layer.borderColor = [[UIColor blackColor] CGColor];
mi.layer.borderWidth = 1.0;
mi.url = [NSURL URLWithString:profilePictureUrl];
[mi showLoadingWheel];
[self.myHeaderView.profilePictureImageView addSubview:mi];
[self.objManager manage:mi];
Dealloc:
- (void)viewDidUnload {
self.tv = nil;
self.friends = nil;
self.sortedFriends = nil;
self.detailView = nil;
self.profileView = nil;
self.objManager = nil;
[super viewDidUnload];
}
- (void)dealloc {
[tv release];
[friends release];
[sortedFriends release];
[detailView release];
[profileView release];
[objManager release];
[super dealloc];
}
You can use stack trace to determine the place of leak.
Edit:
make sure you are releasing the mi.url in dealloc method:
-(void) dealloc {
//some other releases
self.url = nil;
[super dealloc];
}

Image view not updating on NSThread

I'm trying to make a test app which measures the performance for threads. However, I'm trying to set an image to imageview on a thread and it's not updating. In fact, the methods setImage1 and setImage2 aren't even getting called. Any ideas?
Look at the code for details
#import "UntitledAppDelegate.h"
#import <QuartzCore/QuartzCore.h>
#implementation UntitledAppDelegate
#synthesize window, imageView1, imageView2, label1, label2, label0;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[window makeKeyAndVisible];
return YES;
}
-(IBAction) startSeparate:(id) sender
{
imageView1.image = imageView2.image = nil;
double prev;
start = prev = CACurrentMediaTime();
[self setImage1];
label1.text = [NSString stringWithFormat:#"%.10g", CACurrentMediaTime() - prev];
prev = CACurrentMediaTime();
[self setImage2];
label2.text = [NSString stringWithFormat:#"%.10g", CACurrentMediaTime() - prev];
}
-(IBAction) startThreaded:(id) sender
{
imageView1.image = imageView2.image = nil;
double prev;
NSThread *t1 = [[NSThread alloc] init];
[t1 start];
NSThread *t2 = [[NSThread alloc] init];
[t2 start];
start = prev = CACurrentMediaTime();
//This doesn't work
//[self performSelector:#selector(setImage1) onThread:t1 withObject:nil waitUntilDone:NO];
//But this does
[self performSelectorInBackground:#selector(setImage1) withObject:nil];
label1.text = [NSString stringWithFormat:#"%.10g", CACurrentMediaTime() - prev];
prev = CACurrentMediaTime();
//This doesn't work
//[self performSelector:#selector(setImage2) onThread:t2 withObject:nil waitUntilDone:NO];
//But this does
[self performSelectorInBackground:#selector(setImage2) withObject:nil];
label2.text = [NSString stringWithFormat:#"%.10g", CACurrentMediaTime() - prev];
}
-(void) setImage1
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIImage *image1 = [UIImage imageNamed:#"bird.png"];
imageView1.image = image1;
[self pictureDone];
[pool drain];
}
-(void) setImage2
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIImage *image2 = [UIImage imageNamed:#"bird.png"];
imageView2.image = image2;
[self pictureDone];
[pool drain];
}
-(void) pictureDone
{
done++;
NSLog(#"%i", done);
if (done == 2) {
label0.text = [NSString stringWithFormat:#"%.10g", CACurrentMediaTime() - start];
done = 0;
}
}
#end
Never change anything in a currently displayed UIView from a background thread. There are a million different synchronization problems that you can encounter. Download the image in the background thread, and then call another method on the main thread (from the background thread) to actually update the UIImageView
performSelectorOnMainThread:...
As for the problem with the method not running, try this instead:
[self performSelectorInBackground:#selector(setImage2:) withObject:nil];
(adding a colon after setImage2).
Also, I don't think those two NSThread objects (t1 and t2) are necessary, and they are also probably creating a memory leak.
Technically, NSThread itself do not create run loop automatically, then the performSelector:onThread won't work if you just create thread that way.