Async Images Download in a Table - iphone

I have a table view and I'd like to download an icon image (100x75) to each row asynchronously. I've followed many tutorials so far but I can't seem to figure it out. How should I do it?
Does anyone recommend just doing it using the standard NSURLConnection API or should I use one of those classes/libraries that are available online to do so? If so, what do you recommend?
Of course, I need it to be fast, efficient and does not leak. I also don't want the downloading to affect the scrolling.
Thank you!

Two options I can think of:
(1) Use ASIHTTPRequest.
(2) A custom implementation that spawns a thread in which you load the image using a combination of NSURL/NSData. Once the image is loaded, send it to a method on the main UI thread using performSelectorOnMainThread:withObject:.
NSThread *t = [[NSThread alloc] initWithTarget:self selector:#selector(loadImage:) object:nil];
[t start];
[t release];
-(void) updateImage:(id) obj {
// do whatever you need to do
}
-(void) loadImage:(id) obj {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSURL *url = [NSURL URLWithString:#"imageurl"];
NSData *imageData = [[NSData alloc]initWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
[imageData release];
[self performSelectorOnMainThread:#selector(updateImage:) withObject:data waitUntilDone:YES];
[pool release];
}

I'd recommend you using ASIHTTPRequest. Its simple and pretty fast.
Here is a link to the documentation - ASIHTTPRequest
EDIT
You need to download images for visible cells only.
Heres a sample:
- (void)loadContentForVisibleCells
{
NSArray *cells = [self.tableView visibleCells];
[cells retain];
for (int i = 0; i < [cells count]; i++)
{
...
// Request should be here
...
}
[cells release];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
{
if (!decelerate)
{
[self loadContentForVisibleCells];
}
}
Anyway u'll need to code a lot to make things work good and fast.

Related

iPhone - Make UITableViewCells appear on view load before NSURLConnection completes

I am trying to create a loose version of LazyTabelImages using storyboard and JSON. in ViewDidLoad on my main TableViewController, I start an NSURLConnection to get the JSON data, but my cells do not load until after the connection is completed. I want the same behavior that LazyTableImages has, where the cells load as blanks, but then have the information filled in (reload the table data). I can duplicate this if I do not use storyboard, as LazyTables does not use storyboard, but that is not an option.
I have looked through LazyTableImages to try to find the solution, but storyboard make a big difference (to me anyway).
Is there a simple way to get the cells to load as blanks? For example, if the device has no internet, I still want my TableView to show up, and I will put a custom message in the cell.
Code:
The part of my viewDidLoad where I initialize the connection....
NSURLRequest *urlrequest = [NSURLRequest requestWithURL:[NSURL URLWithString:serverURL]];
self.dataConnection = [[NSURLConnection alloc] initWithRequest:urlrequest delegate:self];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
connectionDidFinnishLoading...
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//ListData below is an array that my data received (JSON) is loaded into. It is then passed to getTableData.
self.dataConnection = nil;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self performSelectorOnMainThread:#selector(getTableData:) withObject:ListData waitUntilDone:YES];
});
}
getTableData...
-(void)getTableData:(NSData *)jsonData
{
NSError *error = nil;
arrayEntries = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:&error];
for (int x = 0; x < arrayEntries.count; x++)
{
NSMutableDictionary *dic = [arrayEntries objectAtIndex:x];
//ARecord is a class just like in LazyTableImages that creates objects to keep the icons/data together. The ARecords are loaded into the TableView
ARecord *arecord = [[ARecord alloc] init];
NSString *title = [dic objectForKey:#"title"];
NSString *subt = [dic objectForKey:#"subtitle"];
NSString *url = [dic objectForKey:#"image_URL"];
arecord.Icon = nil;
arecord.URL = url;
arecord.Name = title;
arecord.title = subt;
//this is where I load an array full of the arecord objects.
[array addObject:arecord];
}
[self.tableView reloadData];
}
I've done something similar. In viewDidLoad: I set the array for table data to a few objects of [NSNull null] for however many blank rows I want to show while the data is downloading. In cellForRowAtIndexPath: I check if [self.arrayOfTableData objectAtIndex:indexPath.row] = [NSNull null]. If so return a "blank" cell, otherwise load the cell with ARRecrod data.
Then when the URL completes, replace the array of NSNulls with array of your ARRecords.
I do this with two objects. First, I have an image fetcher class that downloads data asynchronously and notifies a delegate when it's complete. Then I have an image view class that implements the fetcher's delegate methods. So something like:
#implementation AsyncImageFetcher
-(id)initWithURL:(NSURL *)aURL andDelegate:(id<SomeProtocol>)aDelegate{
//...
NSURLRequest *req = [NSURLRequest requestWithURL:aURL];
//Note that NSURLConnection retains its delegate until the connection
//terminates! See comments in MyImageView below.
[NSURLConnection connectionWithRequest:req delegate:self];
//...
}
//Implement standard connection delegates here. The important part is:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
// ...
UIImage *anImage = [self decodeDownloadedDataIntoAnImage];
if([[self delegate] respondsToSelector:#selector(imageFetcher:didFetchImage:)]){
[[self delegate] imageFetcher:self didFetchImage:anImage];
}
//...
}
#end
Then I subclass UIImageView or UIView or something (depending on how flexible you need to be) to implement the delegate protocol and fire off the fetcher:
#implementation MyImageView
-(id)initWithURL:(NSURL *)aURL andPlaceHolderImage:(UIImage *)aPlaceHolder{
//...
[self setImage:aPlaceHolder];
//Note we don't assign this to an ivar or retain it or anything.
//That's ok because the NSURLConnection inside the fetcher actually
//retains the fetcher itself. So it will live until the connection
//terminates -- which is exactly what we want. Thus we disable
//CLANG's noisy warnings.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-value"
[[AsyncImageFetcher alloc] initWithURL:aURL andDelegate:self];
#pragma clang diagnostic pop
return self;
}
-(void)imageFetcher:(MCMAsyncImageFetcher *)anImageFetcher didFetchImage:(UIImage *)anImage{
[self setImage:anImage];
}
#end
In your specific case, you'd just set a MyImageView as your cell's imageView in -tableView:cellForRowAtIndexPath:, passing reasonable values for its placeholder and URL, of course.
Since I haven't see your code, I just give my suggestion here:
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_queue_t queue = dispatch_queue_create(NULL, NULL);
dispatch_async(queue, ^{
//add your connection code here
//parse the json and store the data
//
dispatch_async(dispatch_get_main_queue(), ^{
//here to reload your table view again,
//since UI related method should run on main thread.
[YOUR_TABLEVIEW reloadData];
});
});
[YOUR_TABLEVIEW reloadData];
}
Note: Make sure your tableview in storyboard has connected to that in code! Hope it helps!

Download image asynchronously

I need to download an image from the web and display it in an ImageView. Presently I am using SDWebImage (It is an asynchronous image downloader with cache support, with a UIImageView category).
But it crashes when I click the back button and forward button (when I try to go back and forth of the view repeatedly). Anyway this happens very rarely, but I need to get rid of this bug. Is there any other library (that does not use private API's) that I could use in my project?
Yes. You can user other libary. I've already implemented that using AsyncImageView which is inherited from UIImageView. What it does is it stores images in Cache memory fetched from a url and whenever you need to load image from the same URL again it will simply load it from the cache memory saving a lot of time.
Just follow the link for implementing that:
https://github.com/nicklockwood/AsyncImageView#readme
http://www.markj.net/iphone-asynchronous-table-image/
Please have a look at the image showing the technique I've implemented. It lets you do other activity while images are loading.:
NSURLConnection provides asynchronous downloading and is built into iOS.
I think that the bug that you describe may occur because when you "go back" release some objects that can be delegates of connections that are still running. For avoid crashes, you should cancel the connections before release or dealloc any object that could be a delegate of a running connection.
Another alternative for image async download is http://allseeing-i.com/ASIHTTPRequest/ .
I personally use the built in Grand Central Dispatch feature in iOS to download images from the server asynchronously.
Below is a code I used to fetch photos from Flickr in one of my apps.
In your image/photo class, have a function that is something like this:
- (void)processImageDataWithBlock:(void (^)(NSData *imageData))processImage
{
NSString *url = self.imageURL;
dispatch_queue_t callerQueue = dispatch_get_current_queue();
dispatch_queue_t downloadQueue = dispatch_queue_create("Photo Downloader", NULL);
dispatch_async(downloadQueue, ^{
NSData *imageData = *insert code that fetches photo from server*;
dispatch_async(callerQueue, ^{
processImage(imageData);
});
});
dispatch_release(downloadQueue);
}
In your Photo View Controller, you can call this function like this:
- (void)viewWillAppear:(BOOL)animated
{
[spinner startAnimating];
[self.photo processImageDataWithBlock:^(NSData *imageData) {
if (self.view.window) {
UIImage *image = [UIImage imageWithData:imageData];
imageView.image = image;
imageView.frame = CGRectMake(0, 0, image.size.width, image.size.height);
scrollView.contentSize = image.size;
[spinner stopAnimating];
}
}];
}
Check out EGOImageLoading by enormego for caching images.
It Works just like UIImageView and lets you download images from HTTP asynchronously and also its easy to integrate
//JImage.h
#import <Foundation/Foundation.h>
#interface JImage : UIImageView {
NSURLConnection *connection;
NSMutableData* data;
UIActivityIndicatorView *ai;
}
-(void)initWithImageAtURL:(NSURL*)url;
#property (nonatomic, retain) NSURLConnection *connection;
#property (nonatomic, retain) NSMutableData* data;
#property (nonatomic, retain) UIActivityIndicatorView *ai;
#end
//JImage.m
#import "JImage.h"
#implementation JImage
#synthesize ai,connection, data;
-(void)initWithImageAtURL:(NSURL*)url {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[self setContentMode:UIViewContentModeScaleToFill];
if (!ai){
[self setAi:[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]];
[ai startAnimating];
[ai setFrame:CGRectMake(27.5, 27.5, 20, 20)];
[ai setColor:[UIColor blackColor]];
[self addSubview:ai];
}
NSURLRequest* request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData {
if (data==nil) data = [[NSMutableData alloc] initWithCapacity:5000];
[data appendData:incrementalData];
NSNumber *resourceLength = [NSNumber numberWithUnsignedInteger:[data length]];
NSLog(#"resourceData length: %d", [resourceLength intValue]);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"Connection error...");
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[ai removeFromSuperview];
}
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[self setImage:[UIImage imageWithData: data]];
[ai removeFromSuperview];
}
#end
//Include the definition in your class where you want to use the image
-(UIImageView*)downloadImage:(NSURL*)url:(CGRect)frame {
JImage *photoImage=[[JImage alloc] init];
photoImage.backgroundColor = [UIColor clearColor];
[photoImage setFrame:frame];
[photoImage setContentMode:UIViewContentModeScaleToFill];
[photoImage initWithImageAtURL:url];
return photoImage;
}
//How to call the class
UIImageView *imagV=[self downloadImage:url :rect];
//you can call the downloadImage function in looping statement and subview the returned imageview.
//it will help you in lazy loading of images.
//Hope this will help
I know this is a very old thread but recently i had a lot of random crashes with SDWebImage, so i had to implement my own lazy loading and caching mechanism. It works pretty well, i just haven't tested it in heavy load cases. So here is the .h and .m files followed by the way i use it :
// UIImageView+CustomCache.h
#interface UIImageView(CustomCache)
-(void)startAsyncDownload:(UIImage*)placeHolderImage imageUrlString:(NSString*)imageUrlString;
#end
// UIImageView+CustomCache.m
#import "UIImageView+CustomCache.h"
#implementation UIImageView(CustomCache)
-(void)startAsyncDownload:(UIImage*)placeHolderImage imageUrlString:(NSString*)imageUrlString{
self.image = placeHolderImage;
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:
[NSURL URLWithString:imageUrlString]] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionHandler){
#autoreleasepool {
if (connectionHandler != nil) {
NSLog(#"error in downloading description %#",connectionHandler.localizedDescription);
} else {
ImagesCacheHandler *ref = [ImagesCacheHandler new];
UIImage *imageFromData = [[UIImage alloc] initWithData:data];
if (imageFromData != NULL && imageFromData != nil && data.length > 0) {
self.image = imageFromData;
//custom store to sqlite
[ref archiveImage:imageUrlString imageData:data moc:[ref fetchContext]];
}
}
}
}];
}
#end
And in my table view i use (i import of course UIImageView+CustomCache.h)
UIImageView *imageViewToLazyLoad = (UIImageView*)[cell viewWithTag:1];
[imageViewToLazyLoad startAsyncDownload:[UIImage imageNamed#"palce_Holder_Image_name"] imageUrlString:imageUrl];
I personally prefer using NSURLConnection sendSynchronousRequest and putting a GCD wrapper around it. Keeps everything neat and tidy.

Multiple NSThreads running simultaneously causing app freezes

I am developing an application in which I have a display a lot of images in my table view.These images has to come from server, so I have create another thread in which the image get processed and then set on table view cell to make our table view scrolls smoothly and properly.
My problem is when I scrolls my table view to a number of times, the app get freezes and after some time the xcode shows the message shown in below image:-
My table view cell code :-
id object = [imageDictFunctionApp objectForKey:[NSString stringWithFormat:#"%d",functionAppButton.tag]];
if(!object){
NSArray *catdictObject=[NSArray arrayWithObjects:[NSNumber numberWithInt:functionAppButton.tag],indexPath,[NSNumber numberWithInt:i],nil];
NSArray *catdictKey=[NSArray arrayWithObjects:#"btn",#"indexPath",#"no",nil];
NSDictionary *catPassdict=[NSDictionary dictionaryWithObjects:catdictObject forKeys:catdictKey];
[NSThread detachNewThreadSelector:#selector(displayingSmallImageForFunctionsApps:) toTarget:self withObject:catPassdict];
}
else
{
if(![object isKindOfClass:[NSNull class]]){
UIImage *img = (UIImage *)object;
[functionAppButton setImage:img forState:UIControlStateNormal];
}
-(void)displayingSmallImageForFunctionsApps:(NSDictionary *)dict
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSIndexPath *path=[dict objectForKey:#"indexPath"];
NSArray *catArray=[self.functionDataDictionary objectForKey:[self.functionsKeysArray objectAtIndex:path.row]];
int vlaue=[[dict objectForKey:#"no"] intValue];
NSDictionary *dict1=[catArray objectAtIndex:vlaue];
NSString *urlString=[dict1 objectForKey:#"artwork_url_large"];
NSURL *url = [NSURL URLWithString:urlString];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
if(image){
[imageDictFunctionApp setObject:image forKey:[NSString stringWithFormat:#"%d",[[dict objectForKey:#"btn"] intValue]]];
NSMutableDictionary *dict2=[NSMutableDictionary dictionaryWithCapacity:4];
[dict2 setObject:image forKey:#"imageValue"];
[dict2 setObject:[dict objectForKey:#"btn"] forKey:#"tag"];
[dict2 setObject:[dict objectForKey:#"indexPath"] forKey:#"indexPath"];
[self performSelectorOnMainThread:#selector(setImageInCellDictCategroryTable:) withObject:dict2 waitUntilDone:NO];
}
else{
[imageDictFunctionApp setObject:[NSNull null] forKey:[NSString stringWithFormat:#"%d",[[dict objectForKey:#"btn"] intValue]]];
}
[pool drain];
}
- (void)setImageInCellDictCategroryTable:(NSDictionary *)dict{
UITableViewCell *myCell = (UITableViewCell *)[categoriesAndFunctionsTableView cellForRowAtIndexPath:[dict objectForKey:#"indexPath"]];
UIButton *myBtn = (CustomUIButton *)[myCell viewWithTag:[[dict objectForKey:#"tag"] intValue]];
if ([dict objectForKey:#"imageValue"]) {
[myBtn setImage:[dict objectForKey:#"imageValue"] forState:UIControlStateNormal];
}
}
I have posted all my code that might be linked with this error.Please anyone suggest me how to solve this issue.
Thanks in advance!
I would suggest not to use threads and move you code to GCD, looks like what you want to use is a serial queue.
So what I would guess is happening is that you are running out of Mach ports. It looks to me like you are starting a thread for every single cell in your table and then they are all trying to schedule tasks to run on the main runloop when they are done. This is going to stress your system.
I would create an NSOperation for each image and schedule them all on the same NSOperationQueue. The runtime will use a pool of threads tuned to the specific system to run all of the operations.
For a simple thing like this, you can also use GCD as Oscar says, but I recently read on the Apple list that NSOperationQueue is preferred because it is higher level. It gives you more options for controlling what happens to your background tasks.

NSAutoreleasePool issues on the iPhone

I have a small iPhone app which has a button on the first view. When I select this button I load up my new view which has an image on it. I'm currently using the following code to load the image from an online source on a separate thread, whilst allowing the user to continue controlling the application:
- (void) loadImageTest
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSURL *url = [[NSURL alloc] init];
url = [NSURL URLWithString:logoPath];
NSData *data = [[NSData alloc] init];
data = [NSData dataWithContentsOfURL:url];
loadingImage = [UIImage imageWithData:data];
titleLogoImage.image = loadingImage;
//[pool drain];
[pool release];
}
This is called from this line of code in the new view's init:
[NSThread detachNewThreadSelector:#selector(loadImageTest) toTarget:self withObject:nil];
Now this works fine (ish), but if I close the new view and then load a new one up again in quick succession (or just after-wards in some cases) it will bomb out with the classic EXC_BAD_ACCESS. I'm sure that this is due to the code within the thread pool, but can anyone see why this is happening?
Thanks
Yours:
// This is ok, you might try using NSURLConnections asynchronous methods instead of making
// your own thread.
[NSThread detachNewThreadSelector:#selector(loadImageTest) toTarget:self withObject:nil];
- (void)loadImageTest
{
// This is fine
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// you're making and then abandoning this url object so it will leak
NSURL *url = [[NSURL alloc] init];
// this is fine
url = [NSURL URLWithString:logoPath];
// again making and abandoning an object
NSData *data = [[NSData alloc] init];
data = [NSData dataWithContentsOfURL:url];
// this works, but is not thread safe,
// can't operate on UIKit objects off the
// main thread
loadingImage = [UIImage imageWithData:data];
titleLogoImage.image = loadingImage;
// this is fine
//[pool drain];
[pool release];
}
Cleaned up to make things thread safe, etc. Should help:
// I'm assuming you have a iVar for logoPath but we don't want to
// make threaded calls to an iVar (it's not mutable, so you could do it, but it's just bad form)
// If i'm wrong about logoPath being an iVar don't sweat copying it.
- (void)whateverMethodYouWant
{
NSString *aLogoPath = [[logoPath copy] autorelease];
[NSThread detachNewThreadSelector:#selector(loadImageForPath:) toTarget:self withObject:aLogoPath];
}
- (void)loadImageForPath:(NSString *)aLogoPath
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:aLogoPath]];
// the performSelector will retain the data until the method can be performed
[self performSelectorOnMainThread:#selector(setImageForTitleLogo:) withObject:imgData waitUntilDone:NO];
[pool release];
}
- (void)setImageForTitleLogo:(NSData *)imgData
{
// This part is not strictly necessary
// but it's a nice way to wrap a method that needs to happen on the main thread.
if ([NSThread isMainThread])
{
// make the image (i'm assuming you meant loadingImage to be a local scope variable)
UIImage *loadingImage = [UIImage imageWithData:imgData];
// make sure the button still exists
// also make sure you're setting any references to this button to nil when you're releasing and making new views
// so that you're not addressing a button that's been released
// (assigning the image to the button will cause the button to retain it for you)
if (titleLogoImage != nil)
titleLogoImage.image = loadingImage;
}
else
{
[self performSelectorOnMainThread:#selector(setImageForTitleLogo:) withObject:imgData waitUntilDone:NO];
}
}
You're doing weird stuff.
NSURL *url = [[NSURL alloc] init];
means you create an NSURL object, which you own.
url = [NSURL URLWithString:logoPath];
This means you create another NSURL object, which is autoreleased. The NSURL you just created, just leaks. The same goes for the NSData here.
The loadingImage must be retained by titleLogoImage, or it will be deallocated on the drain of your NSAutoReleasePool. What is titleLogoImage and does it retain image?
edit ps: what also disturbes me, is that loadingImage is not confined to the scope of the function. To cut things short:
NSURL *url = [NSURL URLWithString:logoPath];
NSData *data = [NSData dataWithContentsOfURL:url];
titleLogoImage.image = [UIImage imageWithData:data];
may save some headaches, at least.
There is nothing in the posted code that would trigger a crash. Depending on how titleLogoImage is defined, it might be affects by the autorelease.
However, beyond the problems outlined by mvds, you have no pressing needs for a localized autorelease pool. It will do nothing here but cause you trouble.
Autorelease pools are dangerous and not for beginners. They will kill any autoreleased objects in them. You generally only create your own pool when you are rapidly creating a large number of memory intensive objects. That does not appear to be the case here.
Despite the attention given them, custom pools are seldom used. After over a decade Apple API work, I can probably count on my fingers the number of times I have used my own custom pool.

release NSMutable array in obj-c

where to dealloc/ release my NS-mutable array a1 ??
see this
- (void)viewDidLoad {
[NSThread detachNewThreadSelector:#selector(loadImage) toTarget:self withObject:nil];
}
- (void) loadImage
{
NSLog(#" THREAD METHOD");
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSUserDefaults *imgg = [NSUserDefaults standardUserDefaults];
myimg= [imgg stringForKey:#"keyToimg"];
NSLog(#"RES image sssssssss is = %#",myimg);
a1 = [[NSMutableArray alloc] init];
[a1 addObjectsFromArray:[myimg componentsSeparatedByString:#"\n\t"]];
//[a1 removeAllObjects];
////
//[myimg release];
[pool release];
}
and in table cell of secition 3 i am displaying image
switch(indexPath.section)
{
NSString *urlE=[a1 objectAtIndex:1];
NSLog(#"url is %#",urlE);
NSData *backgroundData = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlE]];
image = [UIImage imageWithData:backgroundData];
myImageView= [[UIImageView alloc] initWithImage:image];
[myImageView setUserInteractionEnabled:YES];
CGRect rect=CGRectMake(20 ,10, 270, 180);
myImageView.frame = rect;
myImageView.tag = i;
[cell.contentView addSubview:myImageView];
}
and based on tap images are changing
pragma mark working image tap
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#" life count %d",[myimg retainCount]);
NSLog(#" life array count %d",[a1 retainCount]);
//NSLog(#" GITSHffffffffffffffffffffffffffffffC");
NSUInteger sections = [indexPath section];
//NSLog(#"row is %d",sections);
if (sections == 3)
{ //Its either 1 or 0 I don't remember, it's been a while since I did some tableview
if(tap<[a1 count]-1) {
NSLog(#" life array count %d",[a1 retainCount]);
tap++;
NSString *sa=[a1 objectAtIndex:tap];
//////////////////////
image= [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat: sa,[a1 objectAtIndex:tap ]]]]];
NSData *imageData = [NSData dataWithData:UIImageJPEGRepresentation(image, 1.0)];
myImageView.image = image;
//[myimg release];
//[a1 release];
}
else {
tap=1;
//[myimg release];
//[a1 release];
}
}
//[a1 release];
}
so where should i release my a1 and myimg
a1 will never be released using this code.
You should put it on a member variable or add autorelease after init.
By the way, your myImageView should be released after you add it to the cell view.
It is possible because of the retain/release logic: when you alloc the myImageView the retain count is +1, once you add it to cell view,it is now +2, you should then release it so that the retain comes back to +1 and then when cell view will be further deallocated, it will decrement the retain count to 0.
The same logic for the variable image in the last function
Regards
Meir assayag
Instead of :
a1 = [[NSMutableArray alloc] init];
[a1 addObjectsFromArray:[myimg componentsSeparatedByString:#"\n\t"]];
Consider:
a1 = [NSMutableArray arrayWithArray:[myimg componentsSeparatedByString:#"\n\t"]];
That'll initialize your a1 with an autoreleased NSMutableArray object, and then you don't have to worry about manually releasing it.
The thing I don't know is whether your [pool release] will release it, but... I'd really prefer you NOT put that business in a background thread, but rather use asynchronous network methods to get your image data.
By the way, as I was learning iPhone development, I went through three or four levels of "aha moments" about backgrounded networking. One of them had to do with running selectors on background threads. That lasted about a week until I discovered ASIHttpRequest, which is how I do it now. MUCH simpler way to put network interactions in the background without having to mess with threading or any of that nonsense. See http://allseeing-i.com/ASIHTTPRequest/
If you look at my answers, every time HTTP client networking comes up I recommend ASI. I really don't mean to be a shill for it--it's just made my life so much easier I think everyone needs to know about it.