NSURLConnection, tableview GUI hangs - iphone

I am showing the images in the tableview using NSData dataWithContentsOfURL method but when i scroll the tableview GUI gets hanged.so after searching over the forum i found that i can try with NSUrlConnection method. so i tried but i cant implement it successfully.
Please find my code below...
kindly help me out that how i can correctly done it..
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"DataIdentifier"] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.backgroundColor = [UIColor colorWithRed:230.0/255.0 green:249.0/255.0 blue:230.0/255.0 alpha:2.0];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
profileName = [appDelegate.arrCommunityUserList objectAtIndex:indexPath.row];
NSString *imgName = [profileName.user_image stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *strValue = [NSString stringWithFormat:#"%d", profileName.userID];
if (tableView == myTableView)
{
cellRectangle = CGRectMake(15, 2, 75, 75 );
NSString *myurl = [NSString stringWithFormat: #"%#pics/photos/%#/%#",ConstantImgURL, strValue,imgName];
NSURL *url = [NSURL URLWithString: myurl];
imageView = [[UIImageView alloc] initWithFrame: cellRectangle];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:myurl]];
[NSURLConnection connectionWithRequest:request delegate:self];
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection =[[NSURLConnection alloc] initWithRequest:
request delegate:self];
if (theConnection)
{
receivedData = [[NSMutableData data] retain];
}
[cell.contentView addSubview:imageView];
}
}
return cell;
}
// did receive response
- ( void )connection:( NSURLConnection * )connection didReceiveResponse:( NSURLResponse * )response
//--------------------------------------------------------------------------------------------------
{
NSLog(#"Received response: %#", response);
}
// get recieved data
- ( void )connection:( NSURLConnection * )connection didReceiveData:( NSData * )data
//----------------------------------------------------------------------------------
{
// NSLog(#"Connection received data, retain count: %d", [connection retainCount]);
[receivedData appendData:data];
}
// finished loading
- ( void )connectionDidFinishLoading:( NSURLConnection * )connection
//-------------------------------------------------------------------
{
// Set appIcon and clear temporary data/image
UIImage *image = [[UIImage alloc] initWithData:receivedData];
imageView.image = image;
}
// connection failed with error
- ( void )connection:( NSURLConnection * )connection didFailWithError:( NSError * )connError
//---------------------------------------------------------------------------------------
{
// NSLog(#"Error receiving response: %#", connError);
[connection release];
[receivedData release];
}

dataWithContentsOfURL is a synchronous network request. That means that where your code is called it will wait until the request finishes before moving on to the next instruction. Synchronous networking is bad. Really bad. It only really ever works in testing.
What you should be doing, is firing off asynchronous requests for these images. The reason why your code above is horrendously slow is that every single time that the tableView asks its dataSource delegate for cellForRowAtIndexPath:; your code fires off a network request synchronously - which means the cell won't be returned until the network request for the image is finished.
Instead, what you should be doing is either loading all the images asynchronously when the tableView is requested. Here's a good example which uses tags to identify them as they return. This is not easy in the whole context of what you're doing; so perhaps you might want to start all the NSURLConnections when the tableView is shown, return 0 for numberOfSectionsInTableView until the connections finish, then call reloadData on the tableView when they're all finished (and make numberOfSectionsInTableView now return the right number of rows to display).

Start using ASI library: http://allseeing-i.com/ASIHTTPRequest/How-to-use
The sooner the better.

I think this might solve your Problem... http://www.markj.net/iphone-asynchronous-table-image/

Related

Return to collectionView function after connectionDidFinishLoading

My question probably has a really obvious answer which I'm missing. I have an NSURLConnection like so:
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *urlstring = [NSString stringWithFormat:#"http://127.0.0.1:8000/image/"];
NSMutableURLRequest *postRequest = [NSMutableURLRequest
requestWithURL:[NSURL URLWithString:urlstring]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:30.0];
[postRequest setHTTPMethod:#"POST"];
self.firstConnection = [[NSURLConnection alloc] initWithRequest:postRequest delegate:self];
}
-(void)connectionDidFinishLoading:(NSURLConnection*)connection
{
if (connection == _firstConnection){
// Deal with the data
[self getImages];
[self.collectionView reloadData];
}
-(void)getImages
{
NSError *error;
NSMutableArray* images= [NSJSONSerialization JSONObjectWithData:_data options:0 error:&error];
NSUInteger arrayLength = [images count];
dressURLS = [[NSMutableArray alloc] init];
for (NSInteger i=0;i<arrayLength;i++)
{
NSString *temp = [images[i] objectForKey:#"image"];
[dressURLS addObject:temp];
}
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"Cell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
UIImageView *dressImageView = (UIImageView *)[cell viewWithTag:100];
NSString *clothesurl = dressURLS[i]; //i value????
NSString *url =[NSString stringWithFormat:#"http://127.0.0.1:8000/media/%#",clothesurl];
NSURL *imageURL = [NSURL URLWithString:url];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
dispatch_async(dispatch_get_main_queue(), ^{
// Update the UI
dressImageView.image = [UIImage imageWithData:imageData];
});
});
return cell;
}
The code is quite messy, I'm aware. This is how it works. viewDidLoad initializes the connection. It goes to connectionDidFinishLoading where getImages deals with the data which I had to manipulate and store in an array. Then I used the reloadData method to go to the Collection View which is where I run into all kinds of problems.
I need to access the elements of dressURLS[i] where i=0,1,2,3. But the looping is severely complicated by the fact that a. The collection view gets reloaded b. The asynchronous dispatch. I am unable to get i to loop from 0 to 3.
Any solutions to make this less complicated?
-(void)connectionDidFinishLoading:(NSURLConnection*)connection
{
if (connection == _firstConnection){
// Deal with the data
[self getImages];
[collectionView reloaddata]; // or self.collectionView (for property)
}
}
"Discussion
Call this method to reload all of the items in the collection view. This causes the collection view to discard any currently visible items and redisplay them." - Apple
You can the BOOL for the first time & for second time check the condition & display the images by reloading the Collection View.

Navigating in UITableView Slow with JSON Issue

I am loading 4 cities string in the table view which is working but when I select one of the cell and navigate to the other table it navigate too slow. I am using the same code below in the the other table with different link. Could you please tell me why it takes long time (~4 - 6 Sec) to get to the other view?
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL * url = [NSURL URLWithString:#"http://kalkatawi.com/jsonTest.php"];
NSData * data = [NSData dataWithContentsOfURL:url];
NSError *e = nil;
jsonArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&e];
jsonArray1 = [[NSMutableArray alloc] init];
for(int i=0;i<[jsonArray count];i++)
{
NSString * city = [[jsonArray objectAtIndex:i] objectForKey:#"city"];
[jsonArray1 addObject:city];
}
-
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
NSString *tempString = [jsonArray1 objectAtIndex:indexPath.row];
cell.textLabel.text = tempString;
return cell;
}
-
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
SeconfViewController *second = [[SeconfViewController alloc] initWithNibName:#"SeconfViewController" bundle:nil];
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
NSString *cellText = selectedCell.textLabel.text;
NSString *edit = [NSString stringWithFormat:#"http://kalkatawi.com/jsonTest.php?d=1&il=%#", cellText];
second.str2 = edit;
[self.navigationController pushViewController:second animated:YES];
}
It takes more time to navigate on the other screen because you are synchronously loading the data from the server. In iOS all the UI is done on the main thread, and by making your data call on the main thread you are blocking it. The best way I know to handle this is to use GCD (Grand Central Dispatch). It's an API in iOS that will spawn threads for you without a hassle. You just need to tell that you want to make the call to load data from the server on a background thread. When you do that, view should navigate instantaneously. You can use an Activity indicator while the data comes.
dispatch_async(dataQueue, ^{
// Load all your data here
dispatch_async(dispatch_get_main_queue(), ^{
// Update the UI
});
});
Maybe because you are downloading synchronous and you are blocking the main thread maybe that is the reason that your app freeze for 4-6 sec, try to download your json asynchronous
- (void)viewDidLoad
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *response = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://kalkatawi.com/jsonTest.php"]];
NSError *parseError = nil;
jsonArray = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:&parseError];
jsonArray1 = [[NSMutableArray alloc] init]
for(int i=0;i<[jsonArray count];i++)
{
NSString * city = [[jsonArray objectAtIndex:i] objectForKey:#"city"];
[jsonArray1 addObject:city];
}
}
dispatch_sync(dispatch_get_main_queue(), ^{
[self.myTableView reloadData];
});
});
}

Application Crash on Fast switching between UISegment

I have a segment and a table view, I have to reload the data in the table view its working but when i switch the segment buttons fast then application crashes.
On segment i have three buttons and on their action I am triggering a request to a url and fetching the json from that url (3 different urls resp. and returns 10, 17 and 8 results in json).
I have a custom table cell which have the images in it and i am trying to lazily load theose images.
In JSON result each object of json have various keys in it like name, id, imageurl etc.
the id is unique throughout the application and I am trying to load the images and save the images in local memory based on that unique id, so that i can show the cashed images and no need to redownload the images on segment change because some enteries on all three segments are same.
Here is my complete code
- (IBAction)segmentedControlIndexChanged {
NSString *offerRequestUrl = nil;
switch (self.mySegment.selectedSegmentIndex) {
case 0:
offerRequestUrl = #"url_one";
self.feedRequestUrl = [NSURL URLWithString:offerRequestUrl];
break;
case 1:
offerRequestUrl = #"url_two";;
self.feedRequestUrl = [NSURL URLWithString:offerRequestUrl];
break;
case 2:
offerRequestUrl = #"url_three";;
self.feedRequestUrl = [NSURL URLWithString:offerRequestUrl];
break;
default:
break;
}
[self parseJSONWithURL:self.feedRequestUrl];
}
- (void) parseJSONWithURL:(NSURL *) jsonURL
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL: jsonURL];
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:data waitUntilDone:YES];
});
}
- (void)fetchedData:(NSData *)responseData {
//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData
options:kNilOptions
error:&error];
self.feedsArray = [json objectForKey:#"result"];
[self.myTableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int count = self.feedsArray.count;
// if there's no data yet, return enough rows to fill the screen
if (count == 0)
{
return 1;
}
return count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// customize the appearance of table view cells
//
static NSString *CellIdentifier = #"MyTableCell";
static NSString *PlaceholderCellIdentifier = #"PlaceholderCell";
// add a placeholder cell while waiting on table data
int nodeCount = [self.feedsArray count];
if (nodeCount == 0 && indexPath.row == 0)
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:PlaceholderCellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:PlaceholderCellIdentifier];
cell.detailTextLabel.textAlignment = UITextAlignmentCenter;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell.detailTextLabel.text = #"Loading . . .";
[self performSelector:#selector(checkAndDisplayAlert) withObject:self afterDelay:10.0];
return cell;
}
CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (nodeCount > 0)
{
// Configure the cell...
cell.carImageView.image = [UIImage imageNamed:#"Placeholder"]; //acts as default image
if([self.imageDict valueForKey:[NSString stringWithFormat:#"%#", self.feedsArray[indexPath.row][#"id_str"]]]==nil)
{
[NSThread detachNewThreadSelector:#selector(displayingSmallImage:) toTarget:self withObject:indexPath];
} else {
cell.carImageView.image = [self.imageDict valueForKey:[NSString stringWithFormat:#"%#", self.feedsArray[indexPath.row][#"id_str"]]];
}
cell.imageView.clipsToBounds = YES;
cell.titleLabel.text = self.feedsArray[indexPath.row][#"title_key"];
}
return cell;
}
- (void) displayingSmallImage:(NSIndexPath *)indexPath
{
NSString *imageUrl = self.feedsArray[indexPath.row][#"icon_url"];
NSURL *url = [NSURL URLWithString:imageUrl];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
if(image == nil)
{
image = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Placeholder"]];
}
[self.imageDict setObject:image forKey:[NSString stringWithFormat:#"%#", self.feedsArray[indexPath.row][#"id_str"]]];
[self performSelectorOnMainThread:#selector(imageReceived:) withObject:indexPath waitUntilDone:NO];
}
- (void) imageReceived:(NSIndexPath *)indexPath
{
UIImage *image = (UIImage *)[self.imageDict objectForKey: [NSString stringWithFormat:#"%#", self.feedsArray[indexPath.row][#"id_str"]]];
UIImageView *imgs = (UIImageView *)[[self.myTableView cellForRowAtIndexPath:indexPath] viewWithTag:IMG_TAG];
[imgs setImage:image];
[self.myTableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
- (void) checkAndDisplayAlert
{
if (!self.feedsArray && self.isAlertPresent == NO) {
UIAlertView *nilAlert = [[UIAlertView alloc] initWithTitle:#"Sorry!"
message:#"No result returned from server."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[nilAlert setTag:kNilAlertTag];
self.isAlertPresent = YES;
[nilAlert show];
}
}
The main things I have to do is
lazily download the images
cache the images in local memory based on unique ID
Check the cashed images dictionary for already downloaded image and display it
If possible save these downloaded images in the local memory (nsuserdefaults etc) so that if user restart the app then also images are there and can be displayed based on their unique ID and no need to download again.
Any help would be appreciated.
Please post the error log, if it is array out of bounds exception I suspect these two methods
- (void)fetchedData:(NSData *)responseData & your tableViewDatasource
To find which line of code causes this crash do this. Go to break points tab on the left side and click + in the bottom.
Then you would get something like this:
Just hit done, run your code again and tell us which line caused the exception.
I understood your problem, why do you want to take the URL from the array in this function
- (void) displayingSmallImage:(NSIndexPath *)indexPath
you could pass the Url to load to that function, from cellForRowAtIndex like this:
NSArray *argsToPass=[NSArray arrayWithObjects:indexPath,self.feedsArray[indexPath.row][#"icon_url"]];
[NSThread detachNewThreadSelector:#selector(displayingSmallImage:) toTarget:self withObject:argsToPass];
and your function is modified as:
- (void) displayingSmallImage:(NSArray *)args
{
if([args count] == 0)
{
NSString *imageUrl = [args objectAtIndex:1];
NSIndexPath *indexPath=[args objectAtIndex:0];
NSURL *url = [NSURL URLWithString:imageUrl];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
if(image == nil)
{
image = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Placeholder"]];
}
[self.imageDict setObject:image forKey:[NSString stringWithFormat:#"%#", self.feedsArray[indexPath.row][#"id_str"]]];
[self performSelectorOnMainThread:#selector(imageReceived:) withObject:indexPath waitUntilDone:NO];
}
}
you can set self.view.userInteractionEnabled=NO when you are sending request to server.
and when u get the data just enable the user interaction .so that multiple requests are avoided.

Help me on loading the images on table view using NSOperationQueue

Kindly look the below code..i found from web
- (void) loadData {
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:#selector(loadDataWithOperation) object:nil];
[queue addOperation:operation];
[operation release];
}
- (void) loadDataWithOperation {
NSURL *dataURL = [NSURL URLWithString:#"http://icodeblog.com/samples/nsoperation/data.plist"];
NSArray *tmp_array = [NSArray arrayWithContentsOfURL:dataURL];
for(NSString *str in tmp_array) {
[self.array addObject:str];
}
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
[cell.textLabel setText:[self.array objectAtIndex:indexPath.row]];
return cell;
}
I have found the above code which loads the text from the web without any problem.( i mean gui is not hanging ).like wise i want to load images into the table view.for that i have wriiten the below code.
- (void) loadDataWithOperation {
NSString *Img_id, *Img_name, *DynamicImgUrl;
Img_id = xmltag.equip_id;
Img_name = xmltag.image;
DynamicImgUrl = [NSString stringWithFormat:#"http://test.com/pics/equipment/%#/%#",Img_id, Img_name];
NSURL *ImageUrl = [NSURL URLWithString:DynamicImgUrl];
//UIImage *image = [UIImage imageWithData: [NSData dataWithContentsOfURL:ImageUrl]];
NSArray *tmp_array = [NSArray arrayWithContentsOfURL:ImageUrl];
for(NSString *str in tmp_array) {
[self.array addObject:str];
}
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
}
Am i correct here? how can i go with adding into the table view...
Kindly help me out...
U are seeking to display images on Tableview from URL, when u download image from url we need to consider some issues, it will freeze ur table view if u goahead with ordinary loading image.
i suggest u look at LazyLoading image
u see this link http://developer.apple.com/library/ios/#samplecode/LazyTableImages/Introduction/Intro.html
Download this sample and get to know the things

NSURLConnection not "firing" until UITableView scrolls

I've got a UITableView that loads an image asynchronously and places it in the UITableViewCell once it's loaded (I'm using almost the exact same code as in the "LazyTableImages" tutorial). This works fine for all images when I scroll the table, but it's not loading the images that are first in the view.
The code is definitely working fine as the class that actually sends the NSURLConnection request is being called correctly (I added an NSLog and it reached the console). The NSURLConnection is just not calling the delegate methods (didReceiveData, connectionDidFinishLoading, etc).
Here's my code:
HomeController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
NSArray *feed = [feeds objectAtIndex: indexPath.row];
/**
* Name of person
*/
[...]
/**
* Feed entry
*/
[...]
/**
* Misc work
*/
[...]
}
FeedRecord *feedRecord = [self.entries objectAtIndex:indexPath.row];
if( !feedRecord.image ) {
if (self.table.dragging == NO && self.table.decelerating == NO)
{
[self startIconDownload:feedRecord forIndexPath:indexPath];
}
cell.imageView.image = [UIImage imageNamed:#"Placeholder.png"];
}
return cell;
}
- (void)startIconDownload:(FeedRecord *)feedRecord forIndexPath:(NSIndexPath *)indexPath
{
IconDownloader *iconDownloader = [imageDownloadsInProgress objectForKey:indexPath];
if (iconDownloader == nil)
{
iconDownloader = [[IconDownloader alloc] init];
iconDownloader.feedRecord = feedRecord;
iconDownloader.indexPathInTableView = indexPath;
iconDownloader.delegate = self;
[imageDownloadsInProgress setObject:iconDownloader forKey:indexPath];
[iconDownloader startDownload];
[iconDownloader release];
}
}
IconDownload.m
#import "IconDownloader.h"
#import "FeedRecord.h"
#define kAppIconHeight 48
#implementation IconDownloader
#synthesize feedRecord;
#synthesize indexPathInTableView;
#synthesize delegate;
#synthesize activeDownload;
#synthesize imageConnection;
#pragma mark
- (void)dealloc
{
[feedRecord release];
[indexPathInTableView release];
[activeDownload release];
[imageConnection cancel];
[imageConnection release];
[super dealloc];
}
- (void)startDownload
{
NSLog(#"%# %#",#"Started downloading", feedRecord.profilePicture); // this shows in log
self.activeDownload = [NSMutableData data];
// alloc+init and start an NSURLConnection; release on completion/failure
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:
[NSURLRequest requestWithURL:
[NSURL URLWithString:feedRecord.profilePicture]] delegate:self];
self.imageConnection = conn;
NSLog(#"%#",conn); // this shows in log
[conn release];
}
- (void)cancelDownload
{
[self.imageConnection cancel];
self.imageConnection = nil;
self.activeDownload = nil;
}
#pragma mark -
#pragma mark Download support (NSURLConnectionDelegate)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"%# %#",#"Got data for", feedRecord.profilePicture);
[self.activeDownload appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"%#",#"Fail!");
// Clear the activeDownload property to allow later attempts
self.activeDownload = nil;
// Release the connection now that it's finished
self.imageConnection = nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"%# %#",#"Done", feedRecord.profilePicture);
// Set appIcon and clear temporary data/image
UIImage *image = [[UIImage alloc] initWithData:self.activeDownload];
self.feedRecord.image = image;
self.activeDownload = nil;
[image release];
// Release the connection now that it's finished
self.imageConnection = nil;
NSLog(#"%# %#",#"Our delegate is",delegate);
// call our delegate and tell it that our icon is ready for display
[delegate feedImageDidLoad:self.indexPathInTableView];
}
#end
Has anyone else experienced anything like this or can identify an issue with my code? Thanks!
you can use this code
[tableView performSelector:#selector(reloadData) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES];
instead
[tableView reloadData];
You don't call the start method of the NSURLConnection object you create in your startDownload method.
Be sure to do it :
- (void)startDownload
{
NSLog(#"%# %#",#"Started downloading", feedRecord.profilePicture); // this shows in log
self.activeDownload = [NSMutableData data];
// alloc+init and start an NSURLConnection; release on completion/failure
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:
[NSURLRequest requestWithURL:
[NSURL URLWithString:feedRecord.profilePicture]] delegate:self];
self.imageConnection = conn;
NSLog(#"%#",conn); // this shows in log
[conn start];
[conn release];
}
You can also use the constructor : initWithRequest:delegate:startImmediately:
Also, your download will be blocked because of the run loop they are running if the user scrolls. Simply register your connection in the "common modes" :
[conn scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
Extracted from : how-to-avoid-blocked-downloads-during-scrolling
You do not start our NSURLConnection. Either initialize it with -[NSURLConnection initWithRequest:delegate:startImmediately:] or manually call -[NSURLConnection start] after initialization.
I have the same issue. Also, I nearly use the same code as you (it is from Apple sample LazyTableImages).
While the code in Apple's test project works, it did not work in my project - although I just made a copy of Apple's code.
What I found is: When I used
NSLog(#"Is%# main thread", ([NSThread isMainThread] ? #"" : #" NOT"));
in cellForRowAtIndexPath: as well as IconDownload.m's startDownload: (in both projects), I found out that it is the main thread in Apple's sample, but NOT main thread in my code.
This might be the problem.
Any idea how to solve?
EDIT !!! Solved !
I just forced main thread using
NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:entry.imageURL, #"imageURL", indexPath, #"indexPath", nil];
[self performSelectorOnMainThread:#selector(startIconDownload:) withObject:info waitUntilDone:NO];
in cellForRowAtIndexPath: You will need a dictionary to send more than one argument to the method.
You can do a similar solution in your code. Replace the line:
[self startIconDownload:feedRecord forIndexPath:indexPath];
with my code and modify startIconDownload: like this
- (void)startIconDownload:(NSDictionary *)info
{
NSString *url = [info objectForKey:#"imageURL"];
NSIndexPath *indexPath = [info objectForKey:#"indexPath"];
...
}
Some variables my be different in your app.
But I just can't understand why it works in Apple's sample without forcing main thread.
Any idea?
Have a look here: http://www.depl0y.com/?p=345
Maybe will help.
Edit: Yep, is working for me. Let me know if is working for you too or you need more information.