Iphone cellForRowAtIndexPath Jerky when scrolling asynchronously problem - iphone

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 :)

Related

IPhone UITableView jerky when scrolling

I'm loading my table from an XML feed in to an array then creating the cells as the code below shows. It can be really jerky when loading sometimes. I thought that was just the images downloading when I scroll but I removed them to test and sometimes it was still jerky. Can't work out what I'm doing wrong!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
const NSInteger BOTTOM_LABEL_TAG = 1002;
const NSInteger TEXT_FIELD_TAG = 1003;
UILabel *Labelcompanyname;
UILabel *Labeldistance;
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell =
[[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier]
autorelease];
const CGFloat LABEL_HEIGHT = 15;
int spaceSize;
if(currentType == #"categorySearch"){
spaceSize = 57;
}
else {
spaceSize = 34;
}
Labelcompanyname =
[[[UILabel alloc]
initWithFrame:
CGRectMake(
spaceSize + 2.0 * cell.indentationWidth,
0.5 * (tableView.rowHeight - 2 * LABEL_HEIGHT)+10,
tableView.bounds.size.width -
spaceSize - 20.0,
LABEL_HEIGHT)]
autorelease];
[cell.contentView addSubview:Labelcompanyname];
Labeldistance =[[[UILabel alloc]
initWithFrame:
CGRectMake(
spaceSize + 2.0 * cell.indentationWidth,
0.5 * (tableView.rowHeight - 2 * LABEL_HEIGHT)+40,
tableView.bounds.size.width -
spaceSize - 20.0,
LABEL_HEIGHT)]
autorelease];
if(currentType == #"categorySearch") {
[cell.contentView addSubview:Labeldistance];
}
Labelcompanyname.tag = BOTTOM_LABEL_TAG;
Labelcompanyname.font = [UIFont systemFontOfSize:[UIFont labelFontSize] - 2];
Labeldistance.tag = TEXT_FIELD_TAG;
Labeldistance.font = [UIFont systemFontOfSize:[UIFont labelFontSize] - 2];
cell.backgroundView = [[[UIImageView alloc] init] autorelease];
cell.selectedBackgroundView = [[[UIImageView alloc] init] autorelease];
cell.textLabel.numberOfLines=0;
}
else
{
Labelcompanyname = (UILabel *)[cell viewWithTag:BOTTOM_LABEL_TAG];
Labeldistance = (UILabel *)[cell viewWithTag:TEXT_FIELD_TAG];
}
PromotionObject *newObj1;
newObj1=[totalArray objectAtIndex:indexPath.row];
if(!newObj1.furtherURL){
Labelcompanyname.text =[NSString stringWithFormat:#"%#", newObj1.companyname];
Labeldistance.text =newObj1.distance;
}
else
{
Labelcompanyname.text =[NSString stringWithFormat:#"Load more results"];
Labeldistance.text =#"";
}
NSURL *Imageurl = [NSURL URLWithString:[NSString stringWithFormat:#"%#", newObj1.locImage]];
NSData *data = [NSData dataWithContentsOfURL:Imageurl];
UIImage *img = [[[UIImage alloc] initWithData:data] autorelease];
if(currentType == #"categorySearch"){
cell.imageView.image = img;
} else if(currentType == #"fullSearch") {
cell.imageView.image = [UIImage imageNamed:#"newmap.png"];
} else {
cell.imageView.image = [UIImage imageNamed:#"business.png"];
}
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
Any help will be really appreciated
Tom
You definitely shouldn't do anything that blocks the UI thread for significant time while loading cells. E.g. NSData *data = [NSData dataWithContentsOfURL:Imageurl];.
I recommend loading your images into the data source in the background and reload/update the table/cells when the data has been downloaded. Would also be good to implement a cache for your images so you don't have to download them again everytime the cell is loaded.
If you need help with asynchronous image loading, search for that. Lot's of stuff on SO.
I guess you got your answer yourself. Your image loading blocks your UI from finishing the current cell request. tableView:cellForRowAtIndexPath: can't return until your image is fetched. I suggest you replace your image by an activity indicator and start to fetch your image in background. You might want to take a look at Concurrency Programming Guide

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

AsyncImage get picture from program source?

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,

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 image memory leak

We have a code like this
NSData* imageData;
UIImage* imageForData;
UIImageView* imageView;
NSData* imageData;
UIImage* imageForData;
UIImageView* imageView;
CellWithId * cell = [[CellWithId alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier];
CGRect frame;
frame.origin.x = 5;
frame.origin.y = 0;
frame.size.height = 43;
frame.size.width = 52;
if ([[planDictionary objectAtIndex:indexPath.row] objectForKey:#"url"]!=[NSNull null]) {
imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[[planDictionary objectAtIndex:indexPath.row] objectForKey:#"url"]]];
imageForData = [[UIImage alloc] initWithData:imageData];
imageView = [[UIImageView alloc] initWithImage:imageForData];
imageView.frame = frame;
[cell.contentView addSubview:imageView];
[imageData release];
[imageForData release];
}NSData* imageData;
UIImage* imageForData;
UIImageView* imageView;
//CellWithId *cell = (CellWithId*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// if (cell == nil) {
CellWithId * cell = [[CellWithId alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier];
//}
CGRect frame;
frame.origin.x = 5;
frame.origin.y = 0;
frame.size.height = 43;
frame.size.width = 52;
if ([[planDictionary objectAtIndex:indexPath.row] objectForKey:#"url"]!=[NSNull null]) {
imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[[planDictionary objectAtIndex:indexPath.row] objectForKey:#"url"]]];
imageForData = [[UIImage alloc] initWithData:imageData];
imageView = [[UIImageView alloc] initWithImage:imageForData];
imageView.frame = frame;
[cell.contentView addSubview:imageView];
[imageData release];
[imageForData release];
}else {
//imageForData = [UIImage imageNamed:#"Plans-Default-image.jpg"];
imageForData = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Plans-Default-image" ofType:#"jpg"]];
imageView = [[UIImageView alloc] initWithImage:imageForData];
imageView.frame = frame;
[cell.contentView addSubview:imageView];
}
[imageView release];
I dont know what is the problem but imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[[planDictionary objectAtIndex:indexPath.row] objectForKey:#"url"]]]; is a place which always shows memory leaks. Please help me to debug this issue.
You allocate two CellWithIdand never release it. It looks as though you do not properly implement this method. The cell returned in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
should be autoreleased:
CellWithId * cell = [[[CellWithId alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
// ...
return (UITableViewCell *)cell;
Also you should use dequeueReusableCellWithIdentifier:CellIdentifierproperly to have decent performance.