AsyncImage get picture from program source? - iphone

from this code
#import "AsyncImageView.h"
#import "ImageCache.h"
#import "ImageCacheObject.h"
static ImageCache *imageCache = nil;
#implementation AsyncImageView
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
}
return self;
}
- (void)drawRect:(CGRect)rect {
// Drawing code
}
- (void)dealloc {
[connection cancel];
[connection release];
[data release];
[super dealloc];
}
-(void)loadImageFromURL:(NSURL*)url {
if (connection != nil) {
[connection cancel];
[connection release];
connection = nil;
}
if (data != nil) {
[data release];
data = nil;
}
if (imageCache == nil)
imageCache = [[ImageCache alloc] initWithMaxSize:2*1024*1024];
[urlString release];
urlString = [[url absoluteString] copy];
UIImage *cachedImage = [imageCache imageForKey:urlString];
if (cachedImage != nil)
{ NSLog(#"get in");
if ([[self subviews] count] > 0)
{
[[[self subviews] objectAtIndex:0] removeFromSuperview];
}
UIImageView *imageView = [[[UIImageView alloc] initWithImage:cachedImage] autorelease];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:imageView];
imageView.frame = self.bounds;
[imageView setNeedsLayout];
[self setNeedsLayout];
return;
}
#define SPINNY_TAG 5555
UIActivityIndicatorView *spinny = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spinny.tag = SPINNY_TAG;
spinny.center = self.center;
[spinny startAnimating];
[self addSubview:spinny];
[spinny release];
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)incrementalData {
if (data==nil) {
data = [[NSMutableData alloc] initWithCapacity:2048];
}
[data appendData:incrementalData];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection {
[connection release];
connection = nil;
UIView *spinny = [self viewWithTag:SPINNY_TAG];
[spinny removeFromSuperview];
if ([[self subviews] count] > 0) {
[[[self subviews] objectAtIndex:0] removeFromSuperview];
}
UIImage *image = [UIImage imageWithData:data];
[imageCache insertImage:image withSize:[data length] forKey:urlString];
UIImageView *imageView = [[[UIImageView alloc]
initWithImage:image] autorelease];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:imageView];
imageView.frame = self.bounds;
[imageView setNeedsLayout]; // is this necessary if superview gets setNeedsLayout?
[self setNeedsLayout];
[data release];
data = nil;
}
#end
If I wanna get picture from app source if url is empty , what code should I add ??
and here is more code from xyz.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.newsTable dequeueReusableCellWithIdentifier:
CellIdentifier];
if (cell == nil) {
//cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell = [self getCellContentView:CellIdentifier];
}
else{
AsyncImageView *oldImage = (AsyncImageView *)[cell.contentView viewWithTag:999];
[oldImage removeFromSuperview];
}
int index = [indexPath indexAtPosition: [indexPath length] - 1];
//Get Picture
CGRect frame;
frame.size.width=50; frame.size.height=50;
frame.origin.x=10; frame.origin.y=0;
AsyncImageView* asyncImage = [[[AsyncImageView alloc] initWithFrame:frame] autorelease];
asyncImage.tag = 999;
NSString *string = [jsonPic objectAtIndex:index];
NSString *url=[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSURL *imageURL = [NSURL URLWithString:url];
if([string isEqualToString:#""]){
NSLog(#"Not found");
at here I don't know How can I get picture from source
AsyncImageView * NoImage = [[[AsyncImageView alloc] initWithFrame:frame] autorelease];
NoImage.tag = 999;
NoImage.image = [UIImage imageNamed:#"bl-noImg.gif"];
[cell.contentView addSubview:NoImage];
}
else
{ NSLog(#"image URL %#",imageURL);
[asyncImage loadImageFromURL:imageURL];
[cell.contentView addSubview:asyncImage];
I can get picture from asyncImage
Please , Help me or guide me to do that. thank you
.
.
.
.
Now It's all done and here is my result code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.newsTable dequeueReusableCellWithIdentifier:
CellIdentifier];
if (cell == nil) {
//cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell = [self getCellContentView:CellIdentifier];
}
else{
AsyncImageView *oldImage = (AsyncImageView *)[cell.contentView viewWithTag:999];
[oldImage removeFromSuperview];
}
int index = [indexPath indexAtPosition: [indexPath length] - 1];
//Get Picture
CGRect frame;
frame.size.width=50; frame.size.height=50;
frame.origin.x=10; frame.origin.y=0;
AsyncImageView* asyncImage = [[[AsyncImageView alloc] initWithFrame:frame] autorelease];
asyncImage.tag = 999;
NSString *string = [jsonPic objectAtIndex:index];
if([string isEqualToString:#""]){
//NSLog(#"Not found");
UIImageView * NoImg = [[[UIImageView alloc] initWithFrame:frame] autorelease];
NoImg.tag = 999;
[NoImg setImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"bg-noImg" ofType:#"gif"]]];
[cell.contentView addSubview:NoImg];
}
else
{ //NSLog(#"image URL %#",imageURL);
NSString *url=[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSURL *imageURL = [NSURL URLWithString:url];
[asyncImage loadImageFromURL:imageURL];
[cell.contentView addSubview:asyncImage];
}
thank you everyone : )

If you are checking for empty url then you should check it before calling to loadImageFromURL and even before creating NSURL object. If it is not empty then you should create NSURL object and call loadImageFromURL method.
somewhere in your code... from where you are calling loadImageFromURL:
if(urlString !=nil || [urlString length]>0)
{
create NSURL object
now again check NSURL object whether its nil or not
we are checking it because if the urlString has incorrect url pattern then no
NSURLObject would be created, so if there is no NSURLObject then we should not call
your method.
if(NSURLObject !=nil)
{
call loadImageFromURL method and so on
}
else
{
//load some default image. which will convey no URL Found
}
}
else
{
//load some default image. which will convey no URL Found
}
Thanks,

Related

IPhone - Images making scrolling and other functionality to crash

Everytime i load images in a tableview and try to scroll the table view i get a crash in my simulator but no errors are showing. Could this be that there is to much memory being used.
Below is the code for 1 out the three views:
#import "ResultViewController.h"
#import "JobAddSiteViewController.h"
#import "SpecificAddViewController.h"
#import "JobAddSiteAppDelegate.h"
#import "JSONKit.h"
#implementation ResultViewController
#synthesize listData;
#synthesize listLocation;
#synthesize listPostDate;
#synthesize listLogo;
#synthesize listDescription;
#synthesize uiTableView;
#synthesize buttonPrev;
#synthesize buttonNext;
NSInteger *countPage = 1;
NSMutableArray *tempArray;
NSMutableArray *tempArray2;
NSMutableArray *tempArray3;
NSMutableArray *tempArray4;
NSMutableArray *tempArray5;
-(IBAction)done{
JobAddSiteViewController *second = [[JobAddSiteViewController alloc]initWithNibName:nil bundle:nil];
[self presentModalViewController:second animated:YES];
[second release];
}
-(void)loadData{
NSString *strURL2 = [NSString stringWithFormat:#"http://www.bestitjobs.co.uk/totaljobs.php", ""];
NSData *nsData2 = [NSData dataWithContentsOfURL:[NSURL URLWithString: strURL2]];
NSString *dataResult = [[NSString alloc] initWithData:nsData2 encoding:NSUTF8StringEncoding];
tempArray = [[NSMutableArray alloc] init];
tempArray2 = [[NSMutableArray alloc] init];
tempArray3 = [[NSMutableArray alloc] init];
tempArray4 = [[NSMutableArray alloc] init];
tempArray5 = [[NSMutableArray alloc] init];
NSString *strURL = [NSString stringWithFormat:#"http://www.bestitjobs.co.uk/appresults3.php?pg=%d", countPage];
NSData *nsData = [NSData dataWithContentsOfURL:[NSURL URLWithString: strURL]];
NSDictionary *listDictionary = [nsData objectFromJSONData];
NSArray* people =[listDictionary objectForKey:#"jobs"];
for (NSDictionary *person in people) {
NSString *str = [NSString stringWithFormat:#"%#", [person valueForKey:#"position"]];
NSString *str2 = [NSString stringWithFormat:#"%#", [person valueForKey:#"subcounty"]];
NSString *str3 = [NSString stringWithFormat:#"%#", [person valueForKey:#"postdate"]];
NSString *str4 = [NSString stringWithFormat:#"%#", [person valueForKey:#"logo"]];
NSString *str5 = [NSString stringWithFormat:#"%#", [person valueForKey:#"description"]];
if(![str isEqualToString:#"<null>"])
{
NSString *position = [person objectForKey:#"position"];
[tempArray addObject: position];
if(![str2 isEqualToString:#"<null>"])
{
NSString *subcounty = [person objectForKey:#"subcounty"];
[tempArray2 addObject: subcounty];
}
else{
[tempArray2 addObject: #"-"];
}
if(![str3 isEqualToString:#"<null>"])
{
NSString *postDate = [person objectForKey:#"postdate"];
[tempArray3 addObject: postDate];
}
else{
[tempArray3 addObject: #"-"];
}
if(![str4 isEqualToString:#"<null>"])
{
NSString *logo = [person objectForKey:#"logo"];
[tempArray4 addObject: [NSString stringWithFormat:#"http://www.bestitjobs.co.uk/employers/logo/Files/%#", logo]];
}
else{
[tempArray4 addObject: [NSString stringWithFormat:#"http://www.bestitjobs.co.uk/employers/logo/Files/%#", "noimage.gif"]];
}
if(![str5 isEqualToString:#"<null>"])
{
NSString *description = [person objectForKey:#"description"];
[tempArray5 addObject: description];
}
else{
[tempArray5 addObject: #"-"];
}
}
}
if (countPage == 1) {
[self.buttonPrev setEnabled:FALSE];
}
else {
[self.buttonPrev setEnabled:TRUE];
}
NSInteger val = [dataResult intValue];
NSInteger pageEnd = val/10;
if (countPage < pageEnd) {
[self.buttonNext setEnabled:TRUE];
}
else {
[self.buttonNext setEnabled:FALSE];
}
//NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#"iPhone", #"iPod",#"iPad",nil];
self.listData = tempArray;
self.listLocation = tempArray2;
self.listPostDate = tempArray3;
self.listLogo = tempArray4;
self.listDescription = tempArray5;
[self.listData release];
[self.listLocation release];
[self.listPostDate release];
[self.listLogo release];
[self.listDescription release];
tempArray = nil;
tempArray2 = nil;
tempArray3 = nil;
tempArray4 = nil;
tempArray5 = nil;
}
- (void)viewDidLoad {
[self loadData];
[super viewDidLoad];
}
- (void)dealloc {
[tempArray dealloc];
[tempArray2 dealloc];
[tempArray3 dealloc];
[tempArray4 dealloc];
[tempArray5 dealloc];
[self.listData dealloc];
[self.listLocation dealloc];
[self.listPostDate dealloc];
[self.listLogo dealloc];
[self.listDescription dealloc];
[super dealloc];
}
#pragma mark -
#pragma mark Table View Data Source Methods
- (IBAction)prev{
countPage = countPage - 1;
[self.listData removeAllObjects];
[self.listLocation removeAllObjects];
[self.listPostDate removeAllObjects];
[self.listLogo removeAllObjects];
//NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#"1", #"2",#"3",nil];
//self.listData = array;
[self loadData];
[self.uiTableView reloadData];
}
- (IBAction)next{
countPage = countPage + 1;
[self.listData removeAllObjects];
[self.listLocation removeAllObjects];
[self.listPostDate removeAllObjects];
[self.listLogo removeAllObjects];
//NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#"1", #"2",#"3",nil];
//self.listData = array;
[self loadData];
[self.uiTableView reloadData];
}
- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
JobAddSiteAppDelegate *ja = (JobAddSiteAppDelegate *)[[UIApplication sharedApplication] delegate];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
for (UIView *view in cell.contentView.subviews){
if ([view isKindOfClass:[UILabel class]]){
UILabel *label = (UILabel *)view;
if (label.tag == 1) {
ja.jobText = label.text;
}
if (label.tag == 2) {
ja.locationText = label.text;
}
if (label.tag == 3) {
ja.dateText = label.text;
}
if (label.tag == 4) {
}
if (label.tag == 5) {
ja.specificText = label.text;
}
}
if ([view isKindOfClass:[UIImageView class]]){
UIImageView *image = (UIImageView *)view;
if (image.tag = 4){
ja.logoText = image.image;
}
}
}
SpecificAddViewController *second = [[SpecificAddViewController alloc]initWithNibName:nil bundle:nil];
[self presentModalViewController:second animated:YES];
[second release];
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [self.listData count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath
*)indexPath
{
if (indexPath.section == 1 && indexPath.row == 1) {
return 65;
}
return 65;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SimpleTableIdentifier];
UILabel *labelMain;
UILabel *labelLocation;
UILabel *labelDate;
UIImageView *image;
UILabel *ref;
if (cell == nil) {
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SimpleTableIdentifier] autorelease];
image = [[[UIImageView alloc] initWithFrame:CGRectMake(0,3,80,62)] autorelease];
image.tag = 4;
[cell.contentView addSubview:image];
labelMain = [[[UILabel alloc] initWithFrame:CGRectMake(90,3,200,20)] autorelease];
labelMain.tag = 1;
labelMain.font = [UIFont systemFontOfSize:14.0];
[cell.contentView addSubview:labelMain];
labelLocation = [[[UILabel alloc] initWithFrame:CGRectMake(90,20,200,20)] autorelease];
labelLocation.tag = 2;
labelLocation.font = [UIFont systemFontOfSize:12.0];
labelLocation.textColor = [UIColor darkGrayColor];
[cell.contentView addSubview:labelLocation];
labelDate = [[[UILabel alloc] initWithFrame:CGRectMake(90,40,200,20)] autorelease];
labelDate.tag = 3;
labelDate.font = [UIFont systemFontOfSize:12.0];
labelDate.textColor = [UIColor darkGrayColor];
[cell.contentView addSubview:labelDate];
ref = [[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 0)] autorelease];
ref.tag = 5;
[cell.contentView addSubview:ref];
}
[(UILabel *)[cell.contentView viewWithTag:1] setText:[self.listData objectAtIndex:indexPath.row]];
[(UILabel *)[cell.contentView viewWithTag:2] setText:[self.listLocation objectAtIndex:indexPath.row]];
[(UILabel *)[cell.contentView viewWithTag:3] setText:[self.listPostDate objectAtIndex:indexPath.row]];
[(UILabel *)[cell.contentView viewWithTag:5] setText:[self.listDescription objectAtIndex:indexPath.row]];
NSString *imagePath = [self.listLogo objectAtIndex:indexPath.row];
image.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imagePath]]];
return cell;
}
#end
The call
image.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imagePath]]];
will block the execution thread and being indeterminately long in terms of network use this is a bad thing. Each of your cells needs to wait to the image to load.
Check out "lazy loading of tableView cells" as a research topic.
Instead you should give the URL to the cell and tell it to load the image off the main thread.
as in
[cell loadImageAtURL:someURL];
and within a UITableViewCell subclass implementation
-(void)loadImageAtURL:(NSURL *)aurl
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:aurl];
if (data) {
UIImage *image = [UIImage imageWithData:data];
//must update UI on main queue
dispatch_async(dispatch_get_main_queue() ,^{
self.cellImageView = image;
}
}
});
}
Theres also a ton of Obj-C image loaders . EGOCache is my go to library but have a look round.
In summary the cell needs to own the image load process not the tableview because theres no guarantee that the cell will not be reused before the image loads and displays.
NSInteger is a primitive type, which means it can be stored locally on the stack. You don't need to use a pointer to access it. The way you are using it i think is a problem, getting the pointer value instead of the actual value of the primitive type.
I think this is what you want for the declaration/initialization of countPage:
NSInteger countPage = 1;

Application shows low memory warning and crashes while loading images?

I am using following code for loading images from server using following code.When i scroll UITableView application crashes.
AsynchrohousImageView class .m file
- (void)dealloc {
[connection cancel]; //in case the URL is still downloading
[connection release];
[data release];
[_imageView release];
[_activityIndicator release];
[super dealloc];
}
- (void)loadImageFromURL:(NSURL*)url
defaultImageName:(NSString *)defaultImageName
showDefaultImage:(BOOL)defaultImageIsShown
showActivityIndicator:(BOOL)activityIndicatorIsShown
activityIndicatorRect:(CGRect)activityIndicatorRect
activityIndicatorStyle:(UIActivityIndicatorViewStyle)activityIndicatorStyle {
if (connection!=nil) { [connection release]; } if (data!=nil) { [data release]; }
if ([[self subviews] count]>0) {
[[[self subviews] objectAtIndex:0] removeFromSuperview]; // }
if (defaultImageIsShown) {
self.imageView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:defaultImageName]] autorelease];
} else {
self.imageView = [[[UIImageView alloc] init] autorelease];
}
[self addSubview:_imageView];
_imageView.frame = self.bounds;
[_imageView setNeedsLayout];
[self setNeedsLayout];
if (activityIndicatorIsShown) {
self.activityIndicator = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:activityIndicatorStyle] autorelease];
[self addSubview:_activityIndicator];
_activityIndicator.frame = activityIndicatorRect;
_activityIndicator.center = CGPointMake(_imageView.frame.size.width/2, _imageView.frame.size.height/2);
[_activityIndicator setHidesWhenStopped:YES];
[_activityIndicator startAnimating];
}
NSURLRequest* request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData {
if (data==nil) { data = [[NSMutableData alloc] initWithCapacity:2048]; }
[data appendData:incrementalData];
}
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection {
[connection release];
connection=nil;
_imageView.image = [UIImage imageWithData:data];
if (_activityIndicator) {
[_activityIndicator stopAnimating];
}
[data release]; data=nil;
}
- (UIImage*) image {
UIImageView* iv = [[self subviews] objectAtIndex:0];
return [iv image];
}
In ViewController Class Which loads image
- (UITableViewCell *)tableView:(UITableView *)tV cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *reuseIdentifier =#"CellIdentifier";
ListCell *cell = (ListCell *)[tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if (cell==nil) {
cell = [[ListCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
NSMutableDictionary *dicResult = [arrResults objectAtIndex:indexPath.row];
NSURL *url=[NSURL URLWithString:[dicResult objectForKey:#"Image"]];
AsynchronousImageView *asyncImageView = [[AsynchronousImageView alloc] initWithFrame:CGRectMake(5, 10,80,80)];
[asyncImageView loadImageFromURL:url
defaultImageName:#"DefaultImage.png"
showDefaultImage:NO
showActivityIndicator:YES
activityIndicatorRect:CGRectMake(5, 10,30,30)
activityIndicatorStyle:UIActivityIndicatorViewStyleGray]; // load our image with URL asynchronously
[cell.contentView addSubview:asyncImageView];
// cell.imgLocationView.image = [UIImage imageNamed:[dicResult valueForKey:#"Image"]];
[asyncImageView release];
}
if([arrResults count]==1)
{
UITableViewCell *cell1=[tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if(cell1==nil)
cell1=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier] autorelease];
NSMutableDictionary *dicResult = [arrResults objectAtIndex:0];
cell1.textLabel.text=[dicResult valueForKey:#"NoResults"];
return cell1;
}
else
{
NSMutableDictionary *dicResult = [arrResults objectAtIndex:indexPath.row];
NSString *title = [NSString stringWithFormat:#"%# Bedrooms-%#", [dicResult valueForKey:KEY_NUMBER_OF_BEDROOMS],[dicResult valueForKey:KEY_PROPERTY_TYPE]];
NSString *strAddress = [dicResult valueForKey:KEY_DISPLAY_NAME];
NSString *address = [strAddress stringByReplacingOccurrencesOfString:#", " withString:#"\n"];
NSString *price = [dicResult valueForKey:KEY_PRICE];
NSString *distance = [dicResult valueForKey:KEY_DISTANCE];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.lblTitle.text = title;
cell.lblAddress.text = address;
if ([price length]>0) {
cell.lblPrice.text = [NSString stringWithFormat:#"£%#",price];
}else{
cell.lblPrice.text = #"";
}
if ([distance length]>0) {
cell.lblmiles.text = [NSString stringWithFormat:#"%.2f miles",[distance floatValue]];
}else{
cell.lblmiles.text = #"";
}
}
return cell;
}
How can i resolve this?
I have attached heapshot analysis screen shot of it.Here non Object consumes so much of memory what is that?
this is the error:
NSString *reuseIdentifier = [NSString stringWithFormat:#"%d",indexPath.row];
it seems you are NOT reusing cells, but creating a new cell for every row of your table!!!
this way if you need to see 100 or 1000 rows, you create/allocate 100 or 1000 object cells.
that's not the right use of a UITableView.
the "magic" of UITableView is that it reuse cells, and it just creates and allocates just the minor number of cells needed...
e.g. consider you have a vertical spaces of 480 pixels for your tables, and your cells are 100 pixel height, then you just need 5 cells for time, no need to create 1000 cells, you can see just 5 cells at time...
so the magic is to reuse an already allocated cell when you scroll it up and it goes out of screen, and to reset it's contents (images and text) and to use it for the new call that user is going to see down...
While cell reuse is not the problem, leaking cells is:
cell = [[ListCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
You forgot to autorelease this, so you're leaking cells very quickly. You did remember to autorelease cell1.

Crash after returning to tableview

So I am writing an app to read an rss feed, and display the contents in a tableview. It also lets the user play back mp3s that it finds for each item. Anyway the app seemed to be running fine before I started adding new views. Now every time I come back from a view and scroll around a bit, I get "Program received signal "SIGABRT"" or something similar.
here's most of the program:
- (IBAction)playAction:(id)sender
{
// Get row
UIButton *senderButton = (UIButton *)sender;
UITableViewCell *buttonCell =
(UITableViewCell *) [[senderButton superview] superview];
NSInteger buttonRow = [[self.tableView
indexPathForCell:buttonCell] row];
// Entry for row
RSSEntry *senderEntry = [_allEntries objectAtIndex:buttonRow];
// This is where _allEntries gets filled
- (void)requestFinished:(ASIHTTPRequest *)request {
[_queue addOperationWithBlock:^{
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:[request responseData]
options:0 error:&error];
if (doc == nil)
{
NSLog(#"Failed to parse %#", request.url);
}
else
{
NSMutableArray *entries = [NSMutableArray array];
[self parseRss:doc.rootElement entries:entries];
if ([_allEntries count] > 0) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// Update
int i=0;
while (![[[_allEntries objectAtIndex:i] articleUrl] isEqualToString:[[entries objectAtIndex:i] articleUrl]])
{
[_allEntries insertObject:[entries objectAtIndex:i] atIndex:0];
i++;
}
[self.tableView reloadData];
}];
}
else
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
for (RSSEntry *entry in entries)
{
[_allEntries addObject:entry];
}
NSLog(#"entries:%d", [_allEntries count]);
[self.tableView reloadData];
}];
}
}
}];
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"View did load");
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
target:self
action:#selector(refreshButton:)];
pauseImage = [UIImage imageNamed:#"pause_circle_small.png"];
playImage = [UIImage imageNamed:#"play_circle_small.png"];
player = nil;
isPlaying = NO;
self.title = #"Feed";
self.allEntries = [NSMutableArray array];
self.queue = [[[NSOperationQueue alloc] init] autorelease];
self.feed = [[NSString alloc] initWithString:#"http://site.org/rss/"];
[self refresh];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [_allEntries count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UILabel *mainLabel, *secondLabel;
UIButton *playBtn;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
mainLabel = [[[UILabel alloc] initWithFrame:CGRectMake(42.0, 5.0, 250.0, 20.0)] autorelease];
mainLabel.tag = MAINLABEL_TAG;
mainLabel.font = [UIFont fontWithName:#"Arial-BoldMT" size:18.0];
mainLabel.textAlignment = UITextAlignmentLeft;
mainLabel.textColor = [UIColor blackColor];
mainLabel.highlightedTextColor = [UIColor whiteColor];
[cell.contentView addSubview:mainLabel];
secondLabel = [[[UILabel alloc] initWithFrame:CGRectMake(42.0, 27.0, 250.0, 15.0)] autorelease];
secondLabel.tag = SECONDLABEL_TAG;
secondLabel.font = [UIFont fontWithName:#"ArialMT" size:14.0];
secondLabel.textAlignment = UITextAlignmentLeft;
secondLabel.textColor = [UIColor colorWithRed:222.0/255.0 green:95.0/255.0
blue:199.0/255.0 alpha:1.0];
secondLabel.highlightedTextColor = [UIColor whiteColor];
[cell.contentView addSubview:secondLabel];
playBtn = [UIButton buttonWithType:UIButtonTypeCustom];
playBtn.tag = PLAYBTN_TAG;
playBtn.frame = CGRectMake(2.0, 6.0, playImage.size.width, playImage.size.height);
[playBtn setBackgroundImage:playImage forState:UIControlStateNormal];
//[playBtn setBackgroundImage:playImage forState:UIControlStateHighlighted];
[playBtn addTarget:self action:#selector(playTapped:)
forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:playBtn];
}
else
{
mainLabel = (UILabel *)[cell.contentView viewWithTag:MAINLABEL_TAG];
secondLabel = (UILabel *)[cell.contentView viewWithTag:SECONDLABEL_TAG];
playBtn = (UIButton *)[cell.contentView viewWithTag:PLAYBTN_TAG];
}
// Alternate bg color
if (indexPath.row%2 == 0) {
UIColor *altColor = [UIColor colorWithRed:230.0/255.0 green:230.0/255.0
blue:230.0/255.0 alpha:1];
mainLabel.backgroundColor = altColor;
secondLabel.backgroundColor = altColor;
}
else
{
UIColor *altColor = [UIColor colorWithRed:255.0 green:255.0
blue:255.0 alpha:1];
mainLabel.backgroundColor = altColor;
secondLabel.backgroundColor = altColor;
}
RSSEntry *entry = [_allEntries objectAtIndex:indexPath.row];
NSLog(#"Entry: %#", entry);
// Manage play button
if (entry == currEntry)
{
if(isPlaying)
{
[playBtn setBackgroundImage:pauseImage forState:UIControlStateNormal];
}
else
{
[playBtn setBackgroundImage:playImage forState:UIControlStateNormal];
}
}
else
[playBtn setBackgroundImage:playImage forState:UIControlStateNormal];
mainLabel.text = entry.articleTitle;
secondLabel.text = entry.articleArtist;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
DetailView *detailViewController = [[DetailView alloc] initWithNibName:#"DetailedView" bundle:[NSBundle mainBundle]];
RSSEntry *entry = [_allEntries objectAtIndex:[indexPath row]];
[self.navigationController pushViewController:detailViewController animated:YES];
detailViewController.songTitle.text = entry.articleTitle;
detailViewController.artistName.text = entry.articleArtist;
[entry release];
[detailViewController release];
}
- (void)dealloc
{
[player release];
player = nil;
[_queue release];
_queue = nil;
[_feed release];
_feed = nil;
[_allEntries release];
_allEntries = nil;
[super dealloc];
}
#end
Please Dont release any #synthesize variable. You should only release it in dealloc method
It's a wild guess, but you don't retain the images that you get in viewDidLoad:
pauseImage = [UIImage imageNamed:#"pause_circle_small.png"];
playImage = [UIImage imageNamed:#"play_circle_small.png"];
Either use retaining property and dot syntax or send each a retain.
AHAA!!! I was setting my RSSEntry to autorelease before putting them in the _allEntries array. They were getting dealloc'd when I changed views. Don't do that. Thanks for the help everyone. That was so simple, I feel dumb now.
please don't release the self.feed and also when unload or dealloc the view at that time put delegate nil means
tableview.delegate = nil;
this one is the main thing check after this i think u don't nil the delegate of tableview.
without line where you get crash its hard to tell, but most likely you accessing some object what was dealloc'ed
most likely its here
self.feed = [[NSString alloc] initWithString:#"http://site.org/rss/music"];
[self.feed release];
you releasing objects right away, but its hard to tell without knowing if you have retained property

iphone nsurlconnect, tableview and activity indicator

i've a method that perform a connection to retreive some data and popolate a tableview.
This method works great.
Now i'm launching this method in viewDidLoad with
[NSThread detachNewThreadSelector:#selector(connTre)
toTarget:self
withObject:nil];
i've create this other function:
- (void)initSpinner {
av = [[[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(195.0, 8.0, 30.0, 30.0) ] autorelease];
av.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
[av hidesWhenStopped];
[self.view addSubview:av];
}
(i've initialite this in viewDidLoad)
- (void)spinBegin {
[av startAnimating];
}
- (void)spinEnd {
[av stopAnimating];
}
where's the better place to start and stop my activityindicatorview?
I've try to start with
[self performSelectorOnMainThread:#selector(spinBegin)
withObject:nil
waitUntilDone:false];
Here's my pretty standard code for table datasource:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [listaOggetti count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSDictionary *dictionary = [listaOggetti objectAtIndex:section];
NSArray *array = [dictionary objectForKey:#"Elementi"];
return [array count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 30;
}
-(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.selectionStyle = UITableViewCellStyleValue1 ;
}
NSInteger sectionRows = [tableView numberOfRowsInSection:[indexPath section]];
NSInteger row = [indexPath row];
// Configure the cell.
NSDictionary *dictionary = [listaOggetti objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:#"Elementi"];
NSString *cellValue = [array objectAtIndex:indexPath.row];
if (row == 0){
cell.textLabel.text = cellValue;
cell.textAlignment = UITextAlignmentCenter;
cell.backgroundColor = [UIColor redColor];
cell.font = [UIFont systemFontOfSize:13];
cell.selectionStyle = UITableViewCellStyleValue1 ;
} else {
cell.textLabel.text = cellValue;
cell.textAlignment = UITextAlignmentCenter;
cell.backgroundColor = [UIColor whiteColor];
cell.selectionStyle = UITableViewCellStyleValue1 ;
}
return cell;
}
this is the method for get my data:
- (void)connTre {
NSThread *spinThread=[[NSThread alloc] initWithTarget:self
selector:#selector(startSpinning) object:nil];
[spinThread start];
NSError *error;
NSURLResponse *response;
NSData *dataReply;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: #"myloginurl"]];
[request setHTTPMethod: #"GET"];
dataReply = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
//message tre soglie ok
path = #"my_url_for_getting_data";
url = [NSURL URLWithString:path];
NSError *errors;
htmlString = [NSString stringWithContentsOfURL:url encoding:NSASCIIStringEncoding error:&errors];
NSString *regexString = #"(?:\r\n|[\n\v\f\r\302\205\\p{Zl}\\p{Zp}])";
NSString *reg2 =#".+class=\"dettaglioSoglie.*";
NSString *reg3 =#"</table>";
NSString*reg4=#"<td><b>(.+) </b></td><td>(.+) </td><td>(.+) </td><td>(.+) </td>";
NSString *replaceWithString = #"$1";
NSString *replaceWithString1 = #"Effettuato $2";
NSString *replaceWithString2 = #"Rimanente $3";
NSString *replaceWithString3 = #"Totale $4";
if(htmlString){
NSArray *linesArray = [htmlString componentsSeparatedByRegex:regexString];
for(NSString *lineString in linesArray) {
if(lineString ==[lineString stringByMatching:reg2]) { print = YES;}
if (print == YES) {
if(lineString ==[lineString stringByMatching:reg4]) {
replace = [lineString stringByReplacingOccurrencesOfRegex:reg4 withString:replaceWithString];
replace1 = [lineString stringByReplacingOccurrencesOfRegex:reg4 withString:replaceWithString1];
replace2 = [lineString stringByReplacingOccurrencesOfRegex:reg4 withString:replaceWithString2];
replace3 = [lineString stringByReplacingOccurrencesOfRegex:reg4 withString:replaceWithString3];
//NSLog(#"%#\n%#\n%#\n%#\n",replace, replace1, replace2, replace3);
//sectionz = [NSMutableArray arrayWithObjects: replace, nil];
//NSMutableArray *voice = [NSMutableArray arrayWithObjects: replace, replace1, replace2, replace3, nil];
NSMutableArray *voice = [NSMutableArray arrayWithObjects: replace, replace1, replace2, replace3, nil];
NSDictionary *detVoice = [NSDictionary dictionaryWithObject:voice forKey:#"Elementi"];
[listaOggetti addObject:detVoice];
NSLog(#"%#", listaOggetti);
}
//NSLog(#"%#",listaDettaglioOggetti);
}
if (lineString ==[lineString stringByMatching:reg3]) { print = NO;}
}
} else {
NSLog(#"Error reading file '%#'", htmlString);
}
[av stopAnimating];
[spinThread release];
}
and this is how i've configure my spinning:
- (void)startSpinning {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
av = [[[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(195.0, 8.0, 30.0, 30.0) ] autorelease];
av.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
[av hidesWhenStopped];
[self.view addSubview:av];
[av startAnimating];
[pool release];
}
with no lucky: jobs were perform, i see with nslog my data, av start and stop but data were not populated in my table (i don't see empty table, i don't see any table).
if i don't perform my animation i get my right table with data.
Thank's.
I don't know this is the correct way or not but this works fine for me.
-(void) yourFunctionThatPopulatesTableView
{
NSThread *spinThread=[[NSThread alloc] initWithTarget:self selector:#selector(startSpinner) object:nil];
[spinThread start];
//Populate TableView
//Last Line of he function
[av stopAnimating];
[spinThread release];
}
-(void)startSpinner
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
CGRect frame = CGRectMake(195.0, 8.0, 30.0, 30.0);
av = [[UIActivityIndicatorView alloc] initWithFrame:frame];
av.activityIndicatorViewStyle=UIActivityIndicatorViewStyleGray;
[av hidesWhenStopped];
[self.view addSubview:av];
[av startAnimating];
[pool release];
}
Any Function called by thread should have a NSAutoReleasePool as per documentation.

Iphone cellForRowAtIndexPath Jerky when scrolling asynchronously problem

I've released my app and noticed the jerkyness when scrolling in the CellForRowAtIndexPath, this is because i'm rendering an image from an JSON Feed via a URL. I've searched the internet and found a few examples and this one i've almost got working. The problem is when it renders the images don't match the correct title. Can someone please have a look and see what if i'm doing something obviously wrong.
Anyway here is my code:
- (void)displayImage:(UIImage *)image {
[photo setImage:image];
}
-(void)loadImage:(NSString *)url {
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
UIImage* image = [[[UIImage alloc] initWithData:imageData] autorelease];
[imageData release];
[self performSelectorOnMainThread:#selector(displayImage:) withObject:image waitUntilDone:NO];
}
CellForRowAtIndexPath Methord
#define DATELABEL_TAG 1 #define MAINLABEL_TAG 2 #define PHOTO_TAG 3 UIImageView *photo;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MainNewsCellIdentifier = #"MainNewsCellIdentifier";
UILabel *mainLabel, *dateLabel;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: MainNewsCellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier: MainNewsCellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
dateLabel = [[[UILabel alloc] initWithFrame:CGRectMake(15.0,15.0,170.0,15.0)] autorelease];
dateLabel.tag = DATELABEL_TAG;
dateLabel.font = [UIFont systemFontOfSize:10.0];
dateLabel.textAlignment = UITextAlignmentLeft;
dateLabel.textColor = [UIColor darkGrayColor];
dateLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
[cell.contentView addSubview:dateLabel];
mainLabel = [[[UILabel alloc] initWithFrame:CGRectMake(15.0,28.0,170.0,60.0)] autorelease];
mainLabel.tag = MAINLABEL_TAG;
mainLabel.font = [UIFont boldSystemFontOfSize:14.0];
mainLabel.textColor = [UIColor blackColor];
mainLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin;
mainLabel.numberOfLines = 0;
[cell.contentView addSubview:mainLabel];
photo = [[[UIImageView alloc] initWithFrame:CGRectMake(190.0,15.0,85.0,85.0)] autorelease];
photo.tag = PHOTO_TAG;
photo.contentMode = UIViewContentModeScaleAspectFit;
[cell.contentView addSubview:photo];
}
else {
dateLabel = (UILabel *)[cell.contentView viewWithTag:DATELABEL_TAG];
mainLabel = (UILabel *)[cell.contentView viewWithTag:MAINLABEL_TAG];
photo = (UIImageView *)[cell.contentView viewWithTag:PHOTO_TAG];
}
NSUInteger row = [indexPath row];
NSDictionary *stream = (NSDictionary *) [dataList objectAtIndex:row];
NSString *title = [stream valueForKey:#"title"];
NSString *titleString = #"";
if( ! [title isKindOfClass:[NSString class]] )
{
titleString = #"";
}
else
{
titleString = title;
}
CGSize maximumSize = CGSizeMake(180, 9999);
UIFont *dateFont = [UIFont fontWithName:#"Helvetica" size:14];
CGSize dateStringSize = [titleString sizeWithFont:dateFont
constrainedToSize:maximumSize
lineBreakMode:mainLabel.lineBreakMode];
CGRect dateFrame = CGRectMake(15.0, 28.0, 170.0, dateStringSize.height);
mainLabel.frame = dateFrame;
mainLabel.text = titleString;
dateLabel.text = [stream valueForKey:#"created"];
NSString *i = [NSString stringWithFormat:#"http://www.domain.co.uk/images/stories/%#", [stream valueForKey:#"image"]];
photo.image = [UIImage imageNamed:#"i_digital_media.png"];
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(loadImage:)
object:i];
[queue addOperation:operation];
[operation release];
return cell;}
By the time that your image is loaded, the photo variable is pointed to a different photo :)
You need to pass both the loaded image and the UIImageView you want to update back - try using a NSDictionary to pass variables between threads :
- (void)displayImage:(NSDictionary *)info {
[[info objectForKey:#"photo"] setImage:[info objectForKey:#"image"]];
}
-(void)loadImage:(NSDictionary *)info {
NSString *imagePath = [info objectForKey:#"imagePath"];
UIImageView *photo = [info objectForKey:#"photo"];
// Load the image
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
UIImage* image = [[[UIImage alloc] initWithData:imageData] autorelease];
[imageData release];
// Pass it back to the main thread
NSDictionary *mainThreadInfo = [NSdictionary dictionaryWithObjectAndKeys:image, #"image", photo, #"photo", nil];
[self performSelectorOnMainThread:#selector(displayImage:) withObject:mainThreadInfo waitUntilDone:YES];
}
so now, your operation will pass the photo and the image data back to the main thread. Create the operation like this :
NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:i, #"imagePath", photo, #"photo", nil];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(loadImage:)
object:info];
And get rid of the global photo variable :)