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];
Related
I have the following implementation, where I am adding a footerview as a customcell. However, if there is no content, I do not want to show the last cell, if there is I want to show it.
In my current implementation, it always displays the last cell.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.adminOrderElements count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return adminOrderElements[section].products.count + 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row < adminOrderElements[indexPath.section].products.count)
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSArray * tempArray = adminOrderElements[indexPath.section].products;
cell.textLabel.text = [[tempArray objectAtIndex:indexPath.row] objectForKey:#"productname"];
return cell;
}
else
{
static NSString *CellIdentifier = #"FooterCell";
FooterTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[FooterTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
if(adminOrderElements[indexPath.section].expanded && [adminOrderElements[indexPath.section].notes length]>0)
{
cell.footerLabel.text = [NSString stringWithFormat:#"Notes: %#", adminOrderElements[indexPath.section].notes];
}
else
{
cell.heightConstraints.constant = 1;
cell.footerLabel.text = #"";
}
return cell;
}
}
There is one option that you can make cellHeight to 0.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(CHECK_IF_NO_CONTAIN)
return 0;
return 40;// Normal height as you want
}
I think you can add condition in else clause like if certain condition is met then you want to display this cell other wise not...
if (indexPath.row < adminOrderElements[indexPath.section].products.count)
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSArray * tempArray = adminOrderElements[indexPath.section].products;
cell.textLabel.text = [[tempArray objectAtIndex:indexPath.row] objectForKey:#"productname"];
return cell;
}
else //Here add your condition here if you have content for the section like I think this condition might work [adminOrderElements[indexPath.section].notes length]>0
{
static NSString *CellIdentifier = #"FooterCell";
FooterTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[FooterTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
if(adminOrderElements[indexPath.section].expanded && [adminOrderElements[indexPath.section].notes length]>0)
{
cell.footerLabel.text = [NSString stringWithFormat:#"Notes: %#", adminOrderElements[indexPath.section].notes];
}
else
{
cell.heightConstraints.constant = 1;
cell.footerLabel.text = #"";
}
return cell;
}
}
Its quite simple with UITableView delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (dataObjects.count == 0){
return 0;
}
return dataObjects.count;
}
I have allSpecialities array, and selectedSpecialities array. I'm downloading those arrays from the server, parse them to object and adding them to those arrays. Now, I want to check/uncheck some specialities. I've tried with containsObject, but that's not working, because those objects are not on the same memory location. This is code that I've done so far, and it's working, but I have problem how to add them to this array.
in cellForRowAtIndexPath:
for (Speciality *specTemp in self.selectedSpecialities) {
if (speciality.specialityId == specTemp.specialityId) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
break;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
in didSelect:
Speciality *speciality = [[Speciality alloc]init];
speciality = self.allSpecialities[indexPath.row];
NSMutableArray *tempSelectedSpecialities = [[NSMutableArray alloc]initWithArray:self.selectedSpecialities];
int i=0;
for (Speciality *tempSpeciality in tempSelectedSpecialities) {
if (tempSpeciality.specialityId == speciality.specialityId) {
[self.selectedSpecialities removeObjectAtIndex:i];
}
else {
}
i++;
}
[self.delegate companySpecialities:self.selectedSpecialities];
[self.specialitiesTableView reloadData];
I have declare one Mutable array in .h to store a data
NSMutableArray *selectedMarks;
assign memory in viewDidLoad
selectedMarks = [NSMutableArray new];
add and remove object in didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
TableViewCell *cell = (TableViewCell *)[self.tblview cellForRowAtIndexPath:indexPath];
NSString *strIndex=[NSString stringWithFormat:#"%ld",(long)indexPath.section];
if ([selectedMarks containsObject:strIndex])// Is selected?
{
[selectedMarks removeObject:strIndex];
}
else{
[selectedMarks addObject:strIndex];
}
}
in cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CRTableViewCellIdentifier = #"TableViewCell";
TableViewCell *cell = (TableViewCell *)[self.tblview dequeueReusableCellWithIdentifier:CRTableViewCellIdentifier];
if (cell == nil) {
cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CRTableViewCellIdentifier];
}
cell.backgroundColor=[UIColor colorWithRed:122/255.0 green:196/255.0 blue:251/255.0 alpha:1];
// Check if the cell is currently selected (marked)
NSString *txtQRCodeid = [[[dictListQR objectForKey:#"boxlist"]objectAtIndex:indexPath.section]valueForKey:#"qr_code_id"];
NSString *text1 = [[[dictListQR objectForKey:#"boxlist"]objectAtIndex:indexPath.section]valueForKey:#"box_name"];
NSString *text=[NSString stringWithFormat:#"QR Code %ld with %#",indexPath.section+1,text1];
cell.isSelected = [selectedQR containsObject:txtQRCodeid] ? YES : NO;
if (cell.isSelected) {
[cell.btnSelection setImage:[UIImage imageNamed:#"check"] ];
// set image of selected
}
else{
[cell.btnSelection setImage:[UIImage imageNamed:#"uncheck"] ];
// set unselected image
}
cell.lblQRcodeText.text=text;
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:15];
return cell;
}
It's Work for me
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;
}
I tried searching but did not find any solutions helpful.
I am using the following code for icons lazy loading.
The issue is, the icons are downloaded via lazy loading, but they are only seen once that particular cell is out of screen and is scrolled back into the screen.
I think it is some issue with dequeueReusableCellWithIdentifier but am not sure how to resolve it.
The images are downloaded alright, but are only visible in the cell once the cell goes out of screen.
// -------------------------------------------------------------------------------
// tableView:cellForRowAtIndexPath:
// -------------------------------------------------------------------------------
- (UITableViewCell *)tableView:(UITableView *)tableVw cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// customize the appearance of table view cells
//
static NSString *CellIdentifier = #"LazyTableCell";
static NSString *PlaceholderCellIdentifier = #"PlaceholderCell";
// add a placeholder cell while waiting on table data
NSUInteger nodeCount = [dataArray count];
if (nodeCount == 0 && indexPath.row == 0)
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:PlaceholderCellIdentifier];
cell.detailTextLabel.text = #"Loading…";
return cell;
}
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.backgroundColor = [UIColor grayColor];
// Leave cells empty if there's no data yet
if (nodeCount > 0)
{
// Set up the cell...
AppRecord *appRecord = [dataArray objectAtIndex:indexPath.row];
cell.textLabel.text = appRecord.appName;
cell.detailTextLabel.text = appRecord.artist;
// Only load cached images; defer new downloads until scrolling ends
if (!appRecord.appIcon)
{
if (tableView.dragging == NO && tableView.decelerating == NO)
{
[self startIconDownload:appRecord forIndexPath:indexPath];
}
// if a download is deferred or in progress, return a placeholder image
cell.imageView.image = [UIImage imageNamed:#"Placeholder.png"];
}
else
{
cell.imageView.image = appRecord.appIcon;
}
}
return cell;
}
- (void)startIconDownload:(AppRecord *)appRecord forIndexPath:(NSIndexPath *)indexPath
{
IconDownloader *iconDownloader = [imageDownloadsInProgress objectForKey:indexPath];
if (iconDownloader == nil)
{
iconDownloader = [[IconDownloader alloc] init];
iconDownloader.appRecord = appRecord;
[iconDownloader setCompletionHandler:^{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
// Display the newly loaded image
cell.imageView.image = appRecord.appIcon;
// Remove the IconDownloader from the in progress list.
// This will result in it being deallocated.
[imageDownloadsInProgress removeObjectForKey:indexPath];
}];
[imageDownloadsInProgress setObject:iconDownloader forKey:indexPath];
[iconDownloader startDownload];
}
}
- (void)loadImagesForOnscreenRows
{
if ([dataArray count] > 0)
{
NSArray *visiblePaths = [tableView indexPathsForVisibleRows];
for (NSIndexPath *indexPath in visiblePaths)
{
AppRecord *appRecord = [dataArray objectAtIndex:indexPath.row];
if (!appRecord.appIcon)
// Avoid the app icon download if the app already has an icon
{
[self startIconDownload:appRecord forIndexPath:indexPath];
}
}
}
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if (!decelerate)
{
[self loadImagesForOnscreenRows];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self loadImagesForOnscreenRows];
}
I did code like following,
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:aURL
options:0
progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
{
if (image)
[aCell.imgViewThumb setImage:image];
else
[aCell.imgViewThumb setImage:[UIImage imageNamed:#"Dummy-image.jpg"]];
[aCell.indicator stopAnimating];
}];
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.