UItableView deplicated cell when scrolling - ios

Sorry for posting this question again but I've looked into many answers and neither of them was helpfull to solve my issue.
So this my code :
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"radioCell";
RadioTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[RadioTableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
}
[self configureCommentCell:cell atIndexPath:indexPath];
return cell;
}
when I scroll down my cell get mixed up and some of data are repeated, so I've tried this :
static NSString *CellIdentifier = #"memberCell";
RadioCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[RadioTableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
}
and this :
RadioTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil) {
cell = [[RadioTableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil];
}
But it didn't fixed my issue and I get white empty cells ? please how to fix this issue ?
Update
- (void)configureCommentCell:(RadioTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
NSDictionary *object;
if ([_dataArray[indexPath.section] isKindOfClass:[NSArray class]])
object = [_dataArray[indexPath.section] objectAtIndex:indexPath.row];
else
object = [[_dataArray[indexPath.section] valueForKey:#"radioList"] objectAtIndex:indexPath.row];
if (object[#"jsonUrl"]) {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:object[#"jsonUrl"] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
//NSDictionary *tempObject = (NSDictionary *) responseObject;
if (![[responseObject objectForKey:#"type"] isEqualToString:#"error"]) {
NSDictionary *tempObject = [responseObject[#"data"] objectAtIndex:0];
cell.playingNow.text = tempObject[#"song"];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
cell.name.text = [NSString stringWithFormat:#" %#", object[#"title"]];
if (object[#"logoUrl"])
[cell.logo setImageWithURL:[NSURL URLWithString:object[#"logoUrl"]]];
}

I see that your problem is that you are fetching the data of you cells inside configureCommentCell that's called inside cellForRowAtIndexPath. which is wrong, because it too late to fetch data inside cellForRowAtIndexPath, in this delegate method you should return the cell.
this line may be called before retrieving the data from server :
cell.name.text = [NSString stringWithFormat:#" %#", object[#"title"]];
Instead you should:
Fetch the data inside a separate method for example fetchData
when the data is downloaded inside the completion block of AFNetworking method, store the data inside an NSArray called for example myDataArray still inside the completion block call [self.tableView reloadData];
In viewDidLoad method just call your method fetchData
And your cellForRowAtIndexPath should looks like this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// hey please give me the cell to display ... harry up please
// please harry up ! oh my god you are fetching data from server
// while I am asking for the cell !
// ok I don't care do what you want
// I will return an empty cell anyway
// and guess what I will not take in consideration
// the retried data because it's inside a block
// which is called asynchronously
static NSString *cellIdentifier = #"radioCell";
RadioTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; if (cell == nil) {
cell = [[RadioTableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier]; }
// now before return the cell you need to update the content of cell
// maybe you have an array of items and you should update the label
// for example here and then return the cell
cell.usernameLabel = self.myDataArray[indexPath.row]; // example
return cell;
}

Well the TableView is reusing the cells, and you add the image every time a cell is displaid. Thus when reusing the cell you add an other image, but there already is an image.
You will have to reuse the image view, and only add the image if you create the cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifer = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifer];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifer]autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(20,0,30,44)];
imageView.tag = 1001;
[cell addSubview:imageView];
[imageView release], imageView= nil;
}
TabBarTestAppDelegate *delegate = (TabBarTestAppDelegate *)[[UIApplication sharedApplication] delegate];
NSArray *local = delegate.myData;
// ok, it's horrible, don't look at it :-)
cell.textLabel.text = [NSString stringWithFormat:#"%#%#", #" " ,[local objectAtIndex:indexPath.row]];
//
NSString* name = nil;;
if (indexPath.row == 0) {
name = #"topicon";
}
else if (indexPath.row + 1 == [local count]) {
name = #"bottomicon";
}
else {
name = #"innericon";
}
UIImageView *imageView = (UIImageView *)[cell viewWithTag:1001];
imageView.image = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:name ofType:#"png"]];
return cell;
}

Related

Stop reloading UItableView again and again in Iphone

I am working on a chat app,In that i have used UITableView for chatting screen. In every chat bubble user's profile pic is there,Now my issue is when a new message come or i am sending new message whole tableView is reloading with images in chat bubble also, I want to stop it,Can anybody help me to figure it out?
my code is:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == self.chatTableView)
{
NSString *cellID;
if([[((UUMessageFrame *)(self.chatModel.dataSource[indexPath.row])) message] from] == UUMessageFromMe)
{
cellID = #"outgoing_cell";
}
else
{
cellID = #"incoming_cell";
}
//commented by jigar
// UUMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
// UUMessageCell *cell = [tableView];
UUMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[UUMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
cell.delegate = self;
if ([cellID isEqualToString:#"outgoing_cell"])
{
// cell.recognizer.numberOfTapsRequired
[cell.recognizer addTarget:self action:#selector(longPress:)];
}
}
[cell setMessageFrame:self.chatModel.dataSource[indexPath.row]];
NSLog(#" text message is : %#",[cell.btnContent titleForState:UIControlStateNormal]);
cell.btnContent.tag = indexPath.row;
return cell;
}
else
{
NSString *cellIdentifier;/* = isOutgoingMessage ? self.outgoingCellIdentifier : self.incomingCellIdentifier;*/
if ([[self.arrTableData objectAtIndex:indexPath.row] isKindOfClass:[OTRVoice class]])
{
OTRVoice *voice = (OTRVoice *)[self.arrTableData objectAtIndex:indexPath.row];
if(![voice.fk_Tripper isEqualToString:appDelegate.account.uniqueId])
{
cellIdentifier = self.incomingCellIdentifier;
}
else
{
cellIdentifier = self.outgoingCellIdentifier;
}
}
else{
cellIdentifier = self.outgoingCellIdentifier;
}
#try
{
VoiceTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
cell.avatarImage.clipsToBounds = YES;
cell.avatarImage.layer.cornerRadius = cell.avatarImage.bounds.size.width / 2.0;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
tableview.separatorStyle = UITableViewCellSeparatorStyleNone;
cell.circular_ProgressView.frame = CGRectMake(cell.btnPlay.frame.origin.x-2, cell.btnPlay.frame.origin.y, 26, 26);
[self configureCell:cell atIndexPath:indexPath];
cell.tag = indexPath.row +10000;
return cell;
}
#catch(NSException *e)
{
NSLog(#"Exception is : %#",e);
}
}
}
you can use https://github.com/rs/SDWebImage library.
In this lib you can set the image directly to UIImageview using lazy loading concept. So even if you set image every time. it will not download again and again.
check the below code for example.
NSURL *url = [NSURL URLWithString:#"url"];
[cell.avatarImage setImageWithURL:url usingActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];

UITableView inside UIView - data loads only when scrolling cells outside uitableview

I have a problem using a UITableView inside a UIViewController:
When I start the app the UITableView is shown, but the data from _opponents isn't shown.
When I start scrolling the first cell outside the UITableView, now this cell gets updated.
Also, when I trigger [_topponents reloaddata] manually, the whole UITableView shows the correct data.
What do I have to add or change, so that the data is shown from the beginning?
dataSource and delegate are both connected with the class in the storyboard
Here is my code:
viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
myappdel = (AppDelegate *)[UIApplication sharedApplication].delegate;
self.title = #"New Match";
_lopponent.text = _opponent;
opponents = [[NSMutableArray alloc] init];
NSMutableDictionary *opponent = [[NSMutableDictionary alloc] init];
[opponent setObject:#"opponent A" forKey:#"name"];
[opponent setObject:#"xx matches | xx wins || xx losts" forKey:#"stats"];
[opponent setObject:#"Krems" forKey:#"location"];
NSMutableDictionary *opponent2 = [[NSMutableDictionary alloc] init];
[opponent2 setObject:#"opponent B" forKey:#"name"];
[opponent2 setObject:#"yy matches | yy wins || yy losts" forKey:#"stats"];
[opponent2 setObject:#"Location B" forKey:#"location"];
NSMutableDictionary *opponent3 = [[NSMutableDictionary alloc] init];
[opponent3 setObject:#"opponent C" forKey:#"name"];
[opponent3 setObject:#"zz matches | zz wins || zz losts" forKey:#"stats"];
[opponent3 setObject:#"Location C" forKey:#"location"];
[opponents addObject:opponent];
[opponents addObject:opponent2];
[opponents addObject:opponent3];
[_topponents reloadData];
}
and here my cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"opponentcell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UILabel *lopponentname = (UILabel*)[cell viewWithTag:1];
UILabel *lopponentstats = (UILabel*)[cell viewWithTag:2];
UILabel *llocation = (UILabel*)[cell viewWithTag:3];
lopponentname.text = [[opponents objectAtIndex:indexPath.row] objectForKey:#"name"];
lopponentstats.text = [[opponents objectAtIndex:indexPath.row] objectForKey:#"stats"];
llocation.text = [[opponents objectAtIndex:indexPath.row] objectForKey:#"location"];
return cell;
}
I found my fault!
I used to write:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]
but I should use
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
with "forIndexPath"
I think, the trouble is in the cell. Create UITableViewCell subclass.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"opponentcell";
CustomTableViewCell *cell = (CustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.lopponentname.text = [[opponents objectAtIndex:indexPath.row] objectForKey:#"name"];
cell.lopponentstats.text = [[opponents objectAtIndex:indexPath.row] objectForKey:#"stats"];
cell.llocation.text = [[opponents objectAtIndex:indexPath.row] objectForKey:#"location"];
return cell;
}
Hope it helps you.
Add this after initialisation of cell. For me works properly.
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
I think you are using custom cel and it looks you have trouble in "cellForRowAtIndexPath". If you using .xib, you may find it useful.
static NSString *cellIdentifier = #"opponentcell";
CustomTableViewCell *cell = (CustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
NSArray *nibObjects =[[NSBundle mainBundle] loadNibNamed:#"CustomTableViewCell" owner:nil options:nil];
for (id currentObject in nibObjects)
{
if ([currentObject isKindOfClass:[CustomTableViewCell class]])
{
cell = (CustomTableViewCell *) currentObject;
}
}
[cell initViewStyles];
}
You need to check for condition when cell is nil..
Initially the cell is nil..
So the data is loading only after scrolling...
Add below lines of code in your cellForRowAtIndexPath delegate method after initializing cell.
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Hope this fixes the issue...

How to reload data from a specific NSMutableArray into a UITableView

Hi I'm using a web service that returns a JSON document. In that document are several objects, each one containing a value for "STATE" (among others like "ADDRESS", "DISTANCE",etc). This "STATE" value can be either "ARCHIVED" or "ACTIVE". What I want to do is to load the objects with "ARCHIVED" value of "STATE" into the archivedProcessTV and the others to activeProcessTV.
I managed to fill both mutable arrays with the desired data but when the TableViews reload, they reload all the objects into the cells.
Here is what I'm doing on connectionDidFinishLoading:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(#"Entrou no connectionDidFinishLoading");
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
process = [[NSJSONSerialization JSONObjectWithData:data options:0 error:nil] objectForKey:#"GetGesturbeDataJsonResult"];
NSInteger i = 0;
archived = [[NSMutableArray alloc] init];
active = [[NSMutableArray alloc] init];
for (NSObject *array1 in process) {
while (i <= process.count) {
if([[[process objectAtIndex:i] objectForKey:#"STATE" ] isEqualToString:#"ARCHIVED"])
{
[archived addObject:[process objectAtIndex:i]];
i++;
}else
[active addObject:[process objectAtIndex:i]];
i++;
}
}
[activeProcessTV reloadData];
[archivedProcessTV reloadData];
}
Thanks for your help!
EDIT:
-(UITableViewCell *)tableView:(UITableView *)atableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [atableView dequeueReusableCellWithIdentifier:#"a cell"];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"a cell"];
cell.textLabel.text = [[process objectAtIndex:indexPath.row] objectForKey:#"DISTANCE"];
return cell;
}
You appear to have 2 problems:
tableView:cellForRowAtIndexPath: does not check which table view is asking for data
You don't use your specific array contents to populate the table views, you use [[process objectAtIndex:indexPath.row] objectForKey:#"DISTANCE"]; which contains all data
So, at the start of tableView:cellForRowAtIndexPath: you should have an if statement which checks the atableView parameter and decides which array to use. Then, edit the line which updates the cell text to use that array.
- (UITableViewCell *)tableView:(UITableView *)atableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *sourceArray;
if (atableView == self.activeProcessTV) {
sourceArray = self.active;
} else {
sourceArray = self.archived;
}
UITableViewCell *cell = [atableView dequeueReusableCellWithIdentifier:#"a cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"a cell"];
}
cell.textLabel.text = [[sourceArray objectAtIndex:indexPath.row] objectForKey:#"DISTANCE"];
return cell;
}
Aside: this code:
UITableViewCell *cell = [atableView dequeueReusableCellWithIdentifier:#"a cell"];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"a cell"];
needs to be changed to:
UITableViewCell *cell = [atableView dequeueReusableCellWithIdentifier:#"a cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"a cell"];
}
as currently you're always creating a new cell even if you did get a reusable one back...
In-spite of using sourcearray just pass like that below and check:-
-(UITableViewCell *)tableView:(UITableView *)atableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [atableView dequeueReusableCellWithIdentifier:#"a cell"];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"a cell"];
}
if ( atableView ==self.activeProcessTV) {
cell.textLabel.text = [[self.activeProcessTV objectAtIndex:indexPath.row] objectForKey:#"DISTANCE"];
}
else{
cell.textLabel.text = [[self.archived objectAtIndex:indexPath.row] objectForKey:#"DISTANCE"];
}
return cell;
}
Note: Pass the correct array count inside numberOfRowsInSection method of UITableView.

How to use to two cell identifiers to sort data?

com documentation, and I am using the PFQueryForTable method with two different tableViewCells to sort my parse objects when they are put into the cells. I am doing this so when the object returns a blank string I can reduce its height to 0. Unfortunately when I do this it does not run like I want to and the blank cells are loaded into the first first cell, and not the one that I want to reduce the height to.
My cellForRowAtIndexPath looks like:
-(UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object{
BOOL blank = [[[object objectForKey:#"post"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] isEqualToString:#""];
static NSString *CellIdentifier = #"Cell";
static NSString *Cell2Identifier = #"Cell2";
if (!blank) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
UILabel *label;
label = (UILabel *)[cell viewWithTag:1];
label.text = [object objectForKey:#"post"]; //[object objectForKey:#"post"];
label.textAlignment = NSTextAlignmentCenter;
NSLog(#"posted cell");
return cell;
}
else {
UITableViewCell *cell2 = [tableView dequeueReusableCellWithIdentifier:Cell2Identifier forIndexPath:indexPath];
if (cell2 == nil) {
cell2 = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:Cell2Identifier];
}
cell2.textLabel.text = [object objectForKey:#"post"];
NSLog(#"posted cell2");
return cell2;
}
}
Can someone please point me in the right direction?
Thank you.
OK, from your comment you are currently creating a query like this...
- (PFQuery *)theQuery
{
PFQuery *posts = [PFUser query];
[posts whereKey:#"location" nearGeoPoint:self.myLocation withinKilometers:10.0];
[posts includeKey:self.textKey];
return posts;
}
So all you need to do is add another where condition to it...
[posts whereKey:#"theText" notEqualTo:#""];
This will stop blank text posts from being sent down.

How can I solve this delegate error?

I have a delegate, but it doesn't work without the other delegate line in it:
- (id)initWithData:(NSData *)data delegate:(id <ParseOperationDelegate>)theDelegate {
self = [super init];
if (self != nil) {
self.dataToParse = data;
self.delegate = theDelegate;
}
appDelegate = (XMLAppDelegate *)[[UIApplication sharedApplication] delegate];
return self;
}
It should load data in a Cell but the data isn't shown before the first scroll. What can I do?
EDIT:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"productCell";
static NSString *PlaceholderCellIdentifier = #"placeholderCell";
int nodeCount = [appDelegate.products count];
if (nodeCount == 0 && indexPath.row == 0) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:PlaceholderCellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:PlaceholderCellIdentifier];
cell.detailTextLabel.textAlignment = UITextAlignmentCenter;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.detailTextLabel.text = #"Loading...";
return cell;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if (nodeCount > 0) {
XMLProductView *listedProduct = [appDelegate.products objectAtIndex:indexPath.row];
cell.textLabel.text = listedProduct.name;
// cell.detailTextLabel.text = appRecord.artist;
if (!listedProduct.productImage) {
if (self.tableView.dragging == NO && self.tableView.decelerating == NO) {
[self startImageDownload:listedProduct forIndexPath:indexPath];
}
UIImageView *listedImage = (UIImageView *)[cell viewWithTag:1];
listedImage.image = [UIImage imageNamed:#"Placeholder.png"];
}
else {
UIImageView *listedImage = (UIImageView *)[cell viewWithTag:1];
listedImage.image = listedProduct.productImage;
}
}
return cell;
}
your code seems that its waiting for some event, or some files to get fetched or downloaded, so you will need to call [tableview reloadData]; when this data is downloaded,
I cant figure it out from the code, but my guts tells me this
1st:
that you are waiting for data from int nodeCount = [appDelegate.products count]; to be ready, so you will need to have some sort of delegate that gets called when this data is ready
2nd:
you are waiting for an image to get downloaded here [self startImageDownload:listedProduct forIndexPath:indexPath], so when this actually get downloaded you will need to set the image to that cell or reloadData on the table
That is what i can figure out from the code.

Resources