I have an ordinary tableview with custom cells, working perfectly on iOS 6.0 but after upgrading the app to iOS 10, scattered problem arises.
Note: The app works as expected on iPhone 5, both on simulator and on a real device. All devices are running iOS 10.2 but iPhone 6 and above has the issues described below.
Some tableviews work fine just like before, while one of the tableViews always shows exactly 1 cell (even tough cellForRowAtIndexPath is called 7 times) and another table shows no cells at all despite cellForRowAtIndexPath getting called twice.
I am wondering why the method is called if the tableview does not care to display the result?
I am at a total loss as to what is going on and how to fix it. Been at it for a day with no progress at all. I have tried cleaning and running different builds and can not get the affected tableviews to behave correctly. I don't know what to try next? Any help is appreciated, thanks!
Ok since you need some code here is a part of it that is not that sensitive. DataSource:
- (void)viewDidLoad
{
[super viewDidLoad];
NOSUserInfo2 *userInfo = [S24SharedUserHandler currentUser];
dataSource = [NSMutableArray arrayWithArray:[userInfo children]];
if([userInfo student] || [userInfo teacher])
{
[dataSource insertObject:userInfo atIndex:0];
}
self.contentSizeForViewInPopover = CGSizeMake(250, 45*dataSource.count-1);
self.tableView.backgroundColor=[UIColor colorWithWhite:0.95f alpha:1];
self.tableView.scrollEnabled=NO;
[self.tableView registerNib:[UINib nibWithNibName:#"NOSPersonSelectorCell" bundle:nil] forCellReuseIdentifier:#"PersonPopoverCell"];
}
This gets called 2 times:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PersonPopoverCell";
NOSPersonSelectorCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.selectionStyle=UITableViewCellSelectionStyleNone;
cell.textLabel.font = [UIFont fontWithName:#"HelveticaNeue-Medium" size:15];
cell.textLabel.backgroundColor=[UIColor clearColor];
NSObject *dataObject = [dataSource objectAtIndex:[indexPath row]];
if ([dataObject isKindOfClass:[NOSUserInfo2 class]]) {
cell.textLabel.text = [(NOSUserInfo2 *)dataObject name];
cell.pk = [(NOSUserInfo2 *)dataObject personPK];
}
else {
cell.textLabel.text = [(NOSChild2 *)dataObject childName];
cell.pk = [(NOSChild2 *)dataObject childPK];
}
cell.textLabel.textColor = [UIColor colorWithWhite:0.18f alpha:1];
//NSLog(#"%d", [S24SharedUserHandler selectedPk]);
cell.checkmark.hidden=cell.pk!=[S24SharedUserHandler selectedPk];
return cell;
}
And the result is that the tableview is empty.
New information 11 Jan 2017
The app works when testing on phone, but not on simulator. I still have no idea what is wrong and am really dissapointed in the downvotes I am still getting for asking this question. I would appreciate if somebody can explain why they think it is a bad question.
Apparently everything works on an iPhone 5. It does not work on iPhone 6 and up. Be advised that the iOS is still 10.2, for both the iPhone 5 and iPhone 6 and 7 also have iOS 10.2
Since the only difference between working and not working is the device, not ios version, I am now leaning towards it being an UI bug that only occurs at certain sizes.
One other issue that arises is that my gesturerecognizer also only works on iPhone5 and not 6+
New info!
I can fix the problem by commenting the heightForRowAtIndexPath code. This now means that I need some other way to adjust the height of certain cells and that is the current problem. I still have no idea at all why uitableview behaves this way.
The reason for this particular problem was that the method "heightForRowAtIndexPath" returns a double on iPhone 5 and long on iPhone 6, to be correct, one should use a defined datatype called "CGFloat"!
It was not easy to find this problem and I hope I can help someone else with this. Also thanks to anyone that tried to help!
Related
I'm developing an Emoji keyboard. This is my approach:
I decided to use UICollectionView. I do everything in code and don't intend to use Xib files.
I create a subclass of UICollectionViewCell. This is going to contain a single label showing the Emoji. This is what I do inside its initWithFrame
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
if (_label == nil) {
_label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
_label.autoresizingMask = (UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight);
_label.textAlignment = NSTextAlignmentCenter;
[_label setNumberOfLines:1];
self.contentView.layer.cornerRadius = 6.0;
[self.contentView addSubview:_label];
}
}
return self;
}
In UICollectionView dataSource object, I read a plist file containing an NSDictionary with NSString as keys and NSArrays as values. Inside each NSArray, one can find the emojis I'm going to show. I then store the dictionary in a property. Here is the code:
#property (nonatomic, strong) NSDictionary *emojis;
- (NSDictionary *)emojis {
if (!_emojis) {
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"EmojisList"
ofType:#"plist"];
_emojis = [NSDictionary dictionaryWithContentsOfFile:plistPath];
}
return _emojis;
}
In the following method, I try to populate the cells:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellIdentifier = #"Cell";
EmojiCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
cell.label.font = [UIFont systemFontOfSize:self.isiPad ? 47 : 33];
NSArray *dataArray = [self.emojis objectForKey:self.categoryNames[indexPath.section]];
cell.label.text = dataArray[indexPath.row];
return cell;
}
The problem I have, is that the memory usage increases when I scroll. This leads to crash on real device.
Please help me. I tested many different ways to solve this but I had no success.
This is a screenshot of instruments. I really don't know what those are about.
Font size do the tricks.
"Apple Color Emoji" font replaces emoji characters to different size of PNG images based on font size. Bigger images soon use up 40MB memory limit.
In my case, I tried font size of 16 and use 1.5 scale transform to make it bigger enough. The result doesn't look good but at least it works...
I'm not sure how much memory is really allocated, but it really shouldn't crash because of the collection view. However, do realize that the keyboard, especially running on the iPhone 6+, is restricted to a rather small memory footprint. Having lots of cells shown with many subviews could therefore lead to memory issues like that.
However, I'm assuming that this is due to a retain cycle. Two classes are most likely capture each other strongly. This can happen in any kind of block or two strong properties referring to each other.
When you can't track down the point where this is happing it's probably the easiest way to just narrow down the code it can possibly be caused by.
Do so by for example not loading the emoji from the plist to check whether that code is affecting it.
I hope this helps, it's basically impossible to tell without looking through your whole project.
Are you reading the plist from disk every time you load a cell? If so you are probably reading the plist into memory every time a cell is loaded and it isn't getting released again. Try disabling the code which reads the plist (put some test strings in the array for now) and see if that helps. If so, that's the problem.
I have really same issue,
Well, still issue is remaining but....
What I found is that when I use transform rather then UIFont.size, it reduces the memory usage quite a bit.
You might want to offload the UIViewCells and contents out of the memory as you scroll and these cells are off the screen. UICollectionView should be doing that but I would double check.
try set the label's opaque YES
My image data is being loaded from core data into a UITableView cell. These images are automatically scaled by the OS (as far as I know) in cellForRowAtIndexPath:indexPath:. Not surprisingly, this causes a lot of lag while scrolling through the table view.
Similarly, I have a UICollectionViewController that loads all the same images into a collection view similar to the iOS Photos app and again, the images are scaled in cellForItemAtIndexPath:indexPath. Scrolling is laggy, but it also takes a very long time for the VC to load.
What is the best way to optimize performance in this scenario?
I've done some research and have come up with a couple possible solutions:
Initialize a "thumbnailArray" in viewDidLoad:animated:, scaling all the images I need before the table/collection view is loaded, then use this new array as the data source for the views. I figure this will solve the scrolling issue, but not the collection view loading issue.
Create new properties for thumbnail data in my image wrapper class. This data would be created when the image wrapper object is created (i.e. when the user adds an image) and saved in core data. I think this would be preferred over option #1.
Is option two the best way to go, or is there a better solution I am unaware of?
Here are my cellForRowAtIndexPath:indexPath and cellForItemAtIndexPath:indexPath: methods:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CMAEntryTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"entriesCell" forIndexPath:indexPath];
CMAEntry *entry = [self.entries objectAtIndex:indexPath.item];
cell.speciesLabel.text = [entry.fishSpecies name];
cell.dateLabel.text = [self.dateFormatter stringFromDate:entry.date];
if (entry.location)
cell.locationLabel.text = [entry locationAsString];
else
cell.locationLabel.text = #"No Location";
if ([entry.images count] > 0)
cell.thumbImage.image = [[entry.images objectAtIndex:0] dataAsUIImage];
else
cell.thumbImage.image = [UIImage imageNamed:#"no_image.png"];
if (indexPath.item % 2 == 0)
[cell setBackgroundColor:CELL_COLOR_DARK];
else
[cell setBackgroundColor:CELL_COLOR_LIGHT];
return cell;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"thumbnailCell" forIndexPath:indexPath];
UIImageView *imageView = (UIImageView *)[cell viewWithTag:100];
[imageView setImage:[[self.imagesArray objectAtIndex:indexPath.item] dataAsUIImage]];
return cell;
}
Thanks in advance!
Cohen
Thanks for your input, guys, but this is the solution that worked really well for me. The only thing I don't like is that now I store an NSData instance of the full image, and two different sized thumbnail images in core data; however, that doesn't seem to be a problem.
What I did was add a couple attributes to my NSManagedObject subclass to store the thumbnail images. The thumbnail data is initialized when the image is selected by the user, then saved in core data along with the original image.
Then, I load the thumbnails into a collection asynchronously in the view controllers I need them.
Works great. Gets rid of all issues I was experiencing.
1 I think the best approach is to load images in a background thread so the tableview loads quickly.
2 Also you can use coredata feature of batchsize to load only necessary data.
3 Perhaps using some type of cache in memory for the images may help
In one of my project i faced same kind of issue and i solved it by using AsyncImageView for loading the thumbimage for my tableview cell.It will load the image asynchronously.
#property (nonatomic,strong)AsyncImageView * thumbImageView;
self.thumbImageView =[[AsyncImageView alloc] init];
cell.thumbImageView.imageURL =[NSURL fileURLWithPath:UrlString];
I am working on an app since a while, it is going well. However, this weekend I updated to Xcode 6 and now my app is behaving differently as opposed to before the update to Xcode 6.
I have a UITableView in my app which I rotate in viewDidLoad:
//Rotate playerCardsTable.
CGAffineTransform rotateTable = CGAffineTransformMakeRotation(-M_PI_2);
_playerCardsTable.transform = rotateTable;
_playerCardsTable.frame = CGRectMake(0, 0, _playerCardsTable.frame.size.width, _playerCardsTable.frame.size.height);
In Xcode before the update (Xcode 5) I had this view:
But now, after updating to Xcode 6, I have this view:
The tableview is rotated, ergo I have horizontal scrolling, but it seems like the frame is not changed correctly after rotation. It is 320 pixels high and 80 pixels wide and it should be the other way round. I don't know why, but it seems I cannot change the frame afterwards in code, in other words, I don't see any change after changing the width and height.
The tableview is added via the interface builder and holds custom cells:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSString *cardName = [[[[[Game game] localPlayer] playerCards] objectAtIndex:indexPath.row] fileNameCard];
cell.cardImage.image = [UIImage imageNamed:cardName];
Card *card;
card = [[[[Game game] localPlayer] playerCards] objectAtIndex:indexPath.row];
if(card.playable == IsPlayable){
cell.backgroundColor = isPlayableColor;}
else if (card.playable == IsNotPlayable) {
cell.backgroundColor = isNotPlayableColor;}
else if (card.playable == IsReallyPlayable) {
cell.backgroundColor = isReallyPlayableColor;}
//Rotate image to align with rotated tableview.
CGAffineTransform rotateImage = CGAffineTransformMakeRotation(M_PI/2);
cell.cardImage.transform = rotateImage;
cell.playableImage.transform = rotateImage;
cell.cardImage.layer.borderWidth = 2;
cell.cardImage.layer.borderColor = [UIColor clearColor].CGColor;
cell.cardImage.layer.shouldRasterize = YES;
cell.cardImage.layer.rasterizationScale = [[UIScreen mainScreen] scale];
cell.cardImage.layer.shadowColor = [UIColor blackColor].CGColor;
cell.cardImage.layer.shadowOffset = CGSizeMake(0, 1);
cell.cardImage.layer.shadowOpacity = 0.7;
cell.cardImage.layer.shadowRadius = 2.0;
cell.cardImage.clipsToBounds = NO;
return cell;}
To be clear; I did not change any code after the update, so the different behavior is caused by the update.
Hope you guys could help.
Thanks!
I ran into a very similar situation after upgrading iPad to ios8 just recently - Horizontal tables not appearing correctly.
I don't have a complete solution, but can tell you from research and testing that in my case it was due to the transform action and AutoLayout constraints on the UITableView not coordinating/cooperating. Evidently the way these two concepts work together changed somewhat in ios8.
A top constraint set in a storyboard becomes a left constraint after the transform (or right, never did figure it out properly).
Bottom line for me was that after trying a number of combinations of constraints, including removing them before transform, then adding constraints back in after the transform, I ended up converting from a UITableView to UICollectionView.
I've tried just about everything I can think of, googled lots, searched SO, and still can't find the solution. Here's the issue:
I have a custom UITableViewCell with several labels in it. The text varies dynamically, and the background color (of the cell, not the labels) should vary as well. The text changes in the labels work fine. However, the BG color won't change no matter what I do. The only upside is that I don't feel that lonely. This is apparently a mystery even to a few high-rep people. I'm hoping someone here has found a solution (or can point out my mistake).
Here's what I have done:
Put the logic inside cellForRowAtIndexPath. Disappointment.
Googled and SO'd some more, then:
Put the logic inside a willDisplayCell call. Nothing.
Googled more, then:
Put the logic back into cellForRowAtIndexPath. Nada.
Put the logic inside the willDisplayCell call again. No go.
Found a post on SO that suggested putting another view in the custom cell to cover the original background and set it to change with logic. It didn't.
Tried putting the logic back into cellForRowAtIndexPath.
Tried using a switch statement in the logic.
Tried using if, else if, else in the logic.
Several other things I can't remember. Still doesn't work.
Yes, the UItableViewdelegate is set.
Here's the current code, which also doesn't work:
EDIT: Made a slight change in the top if statement to reflect the suggestion by #Adrian below. Unfortunately, it didn't cure the problem.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id<NSFetchedResultsSectionInfo> sectionInfo = [[detailFRC sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
NSLog(#"There are %lu objects in the frc",(unsigned long)[sectionInfo numberOfObjects]);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell * cell = [tableView dequeueReusableCellWithIdentifier:#"myCustomCell"];
if (!cell)
{
[tableView registerNib:[UINib nibWithNibName:#"CustomCell" bundle:nil] forCellReuseIdentifier:#"myCustomCell"];
cell = [tableView dequeueReusableCellWithIdentifier:#"myCustomCell"];
}
return cell;
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(CustomCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
thisActivity = [detailFRC objectAtIndexPath:indexPath];
if (self.activityOrCategory == 0)
{
if (thisActivity.name == self.detailFocusItem)
{
[cell.myBGView setBackgroundColor:Rgb2UIColor(255, 215, 215)]; // Light red
cell.backgroundView = cell.myBGView;
}
else if (thisActivity.name == self.detailBenchmarkItem)
{
[cell.myBGView setBackgroundColor:Rgb2UIColor(215, 220, 255)]; // Light blue
}
else
{
cell.myBGView.backgroundColor = [UIColor whiteColor];
}
}
else if (self.activityOrCategory == 1)
{
if (thisActivity.category == self.detailFocusItem)
{
cell.myBGView.backgroundColor = Rgb2UIColor(255, 235, 200);
}
else if (thisActivity.category == self.detailBenchmarkItem)
{
cell.myBGView.backgroundColor = Rgb2UIColor(200, 255, 200);
}
else
{
cell.myBGView.backgroundColor = [UIColor whiteColor];
}
}
NSLog(#"cell.backgroundColor is %#",cell.backgroundColor);
NSLog(#"This row says %#",thisActivity.name);
cell.activityLabel.text = thisActivity.name;
cell.categoryLabel.text = thisActivity.category;
NSDateFormatter *dateFormat = [[NSDateFormatter alloc]init];
[dateFormat setDateFormat: #"MM/dd/yyyy hh:mm:ss"];
cell.fromDateLabel.text = [dateFormat stringFromDate:thisActivity.startTime];
cell.toDateLabel.text = [dateFormat stringFromDate:thisActivity.stopTime];
}
Many thanks for taking the time to look! All help appreciated, even if it's my stupid mistake.
I was under the impression that a UITableViewCell has an actual property of backgroundView, I can see you have something called BGView, but I can't see anywhere from your example where the cell property gets set.
So all I can say is that for my examples where I have done this, I always create a UIView and set it's colour, then assign it to the backgroundView property.
I hope this might be of some help and that I didn't miss you doing that in your example earlier!
// Effectively draws the cell with a red background
UIView *backView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 44)];
backView.backgroundColor = [UIColor redColor];
cell.backgroundView = backView;
Thanks
Adrian_H
I never use Rgb2UIColor before, I don't know how it works.
Try the below code, it works on my app:-
inside willDisplayCell
CGFloat nRed=255/255.f;
CGFloat nGreen= 215/255.f;
CGFloat nBlue = 215/255.f;
UIColor * myColor = [UIColor colorWithRed:nRed green:nGreen blue:nBlue alpha:1]; //Light Red
cell.textLabel.backgroundColor = myColor;
cell.detailTextLabel.backgroundColor = myColor;
cell.backgroundColor =myColor;
[cell.backgroundView setBackgroundColor:myColor];
I hope those who looked at and especially those who took the time to answer this question can have a sense of humor about this:
It turns out that both of the answers graciously contributed above will work (with minor mods). I feel like a bit of a dummy, but the problem I was encountering wasn't with the setting of the background color, it was with the logic itself. Namely, I was using this code in my if statement:
if (thisActivity.name == self.detailFocusItem)
when, since both the objects in question are NSStrings, it should have been:
if ([thisActivity.name isEqualToString:self.detailFocusItem])
Thus, control was simply skipping the color-setting code. :/
I really do apologize for taking your time.
OTOH, had it not been for having been forced to take a new look at it as I implemented your suggestions, I don't know how long it might have taken me to see the forest instead of the trees.
You both get upvotes, and I hope you'll be gentle and chalk it up to the inexperience of a nooby enthusiast.
Many thanks for helping!
How are you all. I'm having a weird issue with my tableviewcell. When I runn this on Simulator. It shows proper layout as in image 1.
but when I run this on device. It has colored lines in it on all tableviews of app, like image 2.
Is this something with iOS 7? I've cleared background color of cell in tablview:willDisplayCell:.
Code is
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
BarsCustomCell *cell= [BarsCustomCell resuableCellForTableView:tableView withOwner:self];
Bars *currentValue= [self.data objectAtIndex:indexPath.row];
if(indexPath.row==(self.data.count-1)){
[cell updateWithBars:currentValue isLast:YES isFirst:NO] ;
}else if (indexPath.row==0){
[cell updateWithBars:currentValue isLast:NO isFirst:YES] ;
}else{
[cell updateWithBars:currentValue isLast:NO isFirst:NO] ;
}
}
and Tableviewcell sublcassm method for updating.
-(void) updateWithBars:(Bars *)bars isLast:(BOOL)isLast isFirst:(BOOL)isFirst{
self.nameLbl.text= bars.name;
self.addressLbl.text= bars.vicinity;
double distance = [[[LOTVLocationManager sharedManager] mockedLocation] distanceFromLocation:bars.location];
self.distanceLbl.text= [NSString stringWithFormat:#"%.2f km",distance/1000];
if(isFirst){
self.bgImageview.image= [UIImage imageNamed:#"sport_top_bg.png"];
self.nameLbl.center= CGPointMake(self.nameLbl.center.x, self.nameLbl.center.y+3);
}
else if(isLast){
self.bgImageview.image= [UIImage imageNamed:#"sport_bottom_bg.png"];
self.addressLbl.center= CGPointMake(self.addressLbl.center.x, self.addressLbl.center.y-3);
}
}
Resolved the issue. It was due to TableviewCell's background color. Some iOS Versions support cell.backgroundColor and some support only cell.contentView.backgroundColor. I wrote both for cell and contentView to fix the issue.