app crashes when i try to scroll the tableview - objective-c

when i try to scroll my tableview it crashes the app,below shown is my code please help me to fix this issue
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{
NSLog(#"indexPath.row---%d",indexPath.row);
UILabel *skuLbl;
// *cellImgView;
static NSString *cellIdentifier=#"Cell";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell==nil){
NSLog(#"indexPath cell");
cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]autorelease];
UIImageView *cellImgView=[[UIImageView alloc]initWithFrame:CGRectMake(25,20,717,125)];
cellImgView.image=[UIImage imageNamed:#"cell.png"];
[cell.contentView addSubview:cellImgView];
skuLbl=[[UILabel alloc]initWithFrame:CGRectMake(62,20,680,125)];
skuLbl.backgroundColor=[UIColor clearColor];
skuLbl.font=[UIFont fontWithName:#"helvetica" size:40];
skuLbl.textColor=[UIColor blackColor];
[cell.contentView addSubview:skuLbl];
cell.selectionStyle=NO;
tableView.separatorColor=[UIColor whiteColor];
}
// NSLog(#"inside cell--%#",[[appDelegateObj.parsedRowsSku objectAtIndex:indexPath.row]objectForKey:#"SKU"]);
// skuLbl.text=[[appDelegateObj.parsedRowsSku objectAtIndex:indexPath.row]objectForKey:#"SKU"];
skuLbl.text=[NSString stringWithFormat:#"%d",indexPath.row];
return cell;
}

When you scroll your table view it tries to reuse its cells so
if(cell==nil){
...
}
may not get called and your skuLbl pointer remains not initialized. So later you're trying to access that invalid pointer and that results in crash.
You need to get reference to label outside of initialization block to make sure it is always valid:
UILabel *skuLbl = nil;
static NSString *cellIdentifier=#"Cell";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell==nil){
...
skuLbl.tag = 100;
...
}
skuLbl = (UILabel*)[cell.contentView viewWithTag:100];
...

make sure your number of rows are equals to the size of your array or whatever you're using with this method:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [self.myArray count]; }

Edit your code as below::
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
UILabel *skuLbl = nil;
static NSString *cellIdentifier=#"Cell";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell==nil) {
cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]autorelease];
UIImageView *cellImgView=[[UIImageView alloc]initWithFrame:CGRectMake(25,20,717,125)];
cellImgView.image=[UIImage imageNamed:#"cell.png"];
[cell.contentView addSubview:cellImgView];
skuLbl=[[UILabel alloc]initWithFrame:CGRectMake(62,20,680,125)];
skuLbl.tag = 100;
skuLbl.backgroundColor=[UIColor clearColor];
skuLbl.font=[UIFont fontWithName:#"helvetica" size:40];
skuLbl.textColor=[UIColor blackColor];
[cell.contentView addSubview:skuLbl];
cell.selectionStyle=NO;
tableView.separatorColor=[UIColor whiteColor];
} else {
// This method called at creation and scrolling of tableview for every individual cell.
// Due to creation and scrolling of tableview skuLbl refrence get nil
// So get new refrence of skuLbl from cell's contentView as below
skuLbl = (UILabel*)[cell.contentView viewWithTag:100];
}
skuLbl.text=[NSString stringWithFormat:#"%d",indexPath.row];
return cell;
}

Related

How to add uiview in uitableviewcell

Hope all of you'll be fine.
I have a little issue in my application. I have a tableview with custom-cell. In my custom-cell class i made a uiview
UIView* cellView = [[UIView alloc] initWithFrame:self.contentView.frame];
cellView.backgroundColor = [UIColor grayColor];
[self.contentView addSubview:cellView];
Problem is uiview is not fitting in my cell frame properly. Cellforrow is as :
- (SummaryViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cell";
SummaryViewCell *cell = (SummaryViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell == nil)
{
cell = [[SummaryViewCell alloc] init];
}
cell.backgroundColor = [UIColor blueColor];
return cell;
}
I have tried initWithFrame:self.contentView.frame] but same problem happened (uiview appear in cell but cover only half of the cell), I also have tried cellView = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.frame.size.width and same as for height) but failed. Need your valuable advise and ideas. Many Thanks.
Where did you creating subview?
Try to do it in -layoutSubviews method.
- (void)layoutSubviews {
[super layoutSubviews];
UIView* cellView = [[UIView alloc] initWithFrame:self.contentView.frame];
cellView.backgroundColor = [UIColor grayColor];
[self.contentView addSubview:cellView];
}
All frames for subviews are already calculated inside this method and you should receive correct width\height for your subview.
Can you try setting clip to bounds
[cellView setClipsToBounds:YES];

Name is not displayed in UITableView

I am trying to do an example on https://github.com/singhson/Expandable-Collapsable-TableView where a storyboard is used. I am trying to do it using xib files. What changes should I make in cellForRowAtIndexPath so that I can get the desired output? I tried something like this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier=#"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if(cell==nil)
{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
NSString *Title= [[self.itemsInTable objectAtIndex:indexPath.row] valueForKey:#"Name"];
[self createCellWithTitle:Title image:[[self.itemsInTable objectAtIndex:indexPath.row] valueForKey:#"Image name" ] indexPath:indexPath];
// return [self createCellWithTitle:Title image:[[self.itemsInTable objectAtIndex:indexPath.row] valueForKey:#"Image name"] indexPath:indexPath];
return cell;
}
- (UITableViewCell*)createCellWithTitle:(NSString *)title image:(UIImage *)image indexPath:(NSIndexPath*)indexPath
{
NSString *CellIdentifier = #"Cell";
ExpandableTableViewCell* cell = [self.menuTableView dequeueReusableCellWithIdentifier:CellIdentifier];
UIView *bgView = [[UIView alloc] init];
bgView.backgroundColor = [UIColor grayColor];
cell.selectedBackgroundView = bgView;
cell.lblTitle.text = title;
cell.lblTitle.textColor = [UIColor blackColor];
[cell setIndentationLevel:[[[self.itemsInTable objectAtIndex:indexPath.row] valueForKey:#"level"] intValue]];
cell.indentationWidth = 25;
float indentPoints = cell.indentationLevel * cell.indentationWidth;
cell.contentView.frame = CGRectMake(indentPoints,cell.contentView.frame.origin.y,cell.contentView.frame.size.width - indentPoints,cell.contentView.frame.size.height);
NSDictionary *d1=[self.itemsInTable objectAtIndex:indexPath.row] ;
if([d1 valueForKey:#"SubItems"])
{
cell.btnExpand.alpha = 1.0;
[cell.btnExpand addTarget:self action:#selector(showSubItems:) forControlEvents:UIControlEventTouchUpInside];
}
else
{
cell.btnExpand.alpha = 0.0;
}
return cell;
}
Now I am getting the table which can be expanded or collapsed but I it doesn't show the name in table view. What other changes should I make for it to work? Please help.
My suggestions:
Use dequeueReusableCellWithIdentifier:forIndexPath: (to be noticed in case you did´t register the class) instead of dequeueReusableCellWithIdentifier: because the last one doesn´t crash if you didn't register a class or nib for the identifier, only returns nil.
Ensure you linked correctly " lblTitle" of your ExpandableTableViewCell class with the xib in the interface builder.
Check in this instruction : cell.lblTitle.text = title; if the title is nil or even if your lblTitle is nil.
Check if lblTitle is out of bounds (you are changing the contentView in this line: cell.contentView.frame = CGRectMake(indentPoints,cell.contentView.frame.origin.y,cell.contentView.frame.size.width - indentPoints,cell.contentView.frame.size.height);)
Are you registering ExpandableTableViewCell using ´registerClass:forCellReuseIdentifier:´ in viewDidLoad?
Hope it helps.

Cell shows on top of section header

I have an UITableView with custom cells and custom headers. When I move one cell upon editing, it pops up on to of the header view.
How can I keep the header view on top of all the cells?
The app uses storyboard, in case that makes a difference.
This is how it looks? https://www.dropbox.com/s/wg8oiar0d9oytux/iOS%20SimulatorScreenSnapz003.mov
This is my code:
[...]
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ListCell";
ListCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
int handleSection = [self sectionToHandle:indexPath.section];
switch (handleSection)
{
case PrivateLists:
{
if (tableView.isEditing && (indexPath.row == self.privateLists.count))
{
cell.textField.text = NSLocalizedString(#"Lägg till ny lista", nil);
cell.textField.enabled = NO;
cell.textField.userInteractionEnabled = NO;
cell.accessoryType = UITableViewCellAccessoryNone;
cell.editingAccessoryView.hidden = YES;
}
else
{
List *list = [self.privateLists objectAtIndex:indexPath.row];
cell.textField.text = list.name;
cell.textField.enabled = YES;
cell.textField.userInteractionEnabled =YES;
cell.backgroundColor = [UIColor clearColor];
cell.onTextEntered = ^(NSString* enteredString){
list.name = enteredString;
UpdateListService *service = [[UpdateListService alloc]initServiceWithList:list];
[service updatelistOnCompletion:
^(BOOL success){
DLog(#"Updated list");
NSIndexPath *newPath = [NSIndexPath indexPathForRow:0 inSection:indexPath.section];
[self.tableView moveRowAtIndexPath:indexPath toIndexPath:newPath];
[self moveListToTop:list.ListId newIndexPath:newPath];
justMovedWithoutSectionUpdate = YES;
}
onError:
^(NSError *error){
[[ActivityIndicator sharedInstance] hide];
[[ErrorHandler sharedInstance]handleError:error fromSender:self];
}];
};
}
}
break;
default:
return 0;
break;
}
return cell;
}
-(UIView *)tableView:(UITableView *)aTableView viewForHeaderInSection:(NSInteger)section
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 22)];
UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, 300, 21)];
[textLabel setFont:[[AXThemeManager sharedTheme]headerFontWithSize:15.0]];
[textLabel setTextColor:[[AXThemeManager sharedTheme]highlightColor]];
[textLabel setText:#"SECTION TITLE"];
[textLabel setBackgroundColor:[UIColor clearColor]];
UIImageView *backgroundView = [[UIImageView alloc]initWithImage:[AXThemeManager sharedTheme].tableviewSectionHeaderBackgroundImage];
[backgroundView setFrame:view.frame];
[view addSubview:backgroundView];
[view sendSubviewToBack:backgroundView];
[view addSubview:textLabel];
return view;
}
- (float)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 22;
}
- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 44;
}
[...]
Good news! I was able to fix/workaround your problem in two different ways (see below).
I would say this is certainly an OS bug. What you are doing causes the cell you have moved (using moveRowAtIndexPath:) to be placed above (in front of) the header cell in the z-order.
I was able to repro the problem in OS 5 and 6, with cells that did and didn't have UITextFields, and with the tableView in and out of edit mode (in your video it is in edit mode, I noticed). It also happens even if you are using standard section headers.
Paul, you say in one of your comments:
I solved it badly using a loader and "locking" the table while
preforming a reloadData
I am not sure what you mean by "using a loader and locking the table", but I did determine that calling reloadData after moveRowAtIndexPath: does fix the problem. Is that not something you want to do?
[self.tableView moveRowAtIndexPath:indexPath toIndexPath:newPath];
//[self.tableView reloadData];
// per reply by Umka, below, reloadSections works and is lighter than reloadData:
[self reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationNone];
If you dont want to do that, here is another solution that feels a little hacky to me, but seems to work well (iOS 5+):
__weak UITableViewCell* blockCell = cell; // so we can refer to cell in the block below without a retain loop warning.
...
cell.onTextEntered = ^(NSString* sText)
{
// move item in my model
NSIndexPath *newPath = [NSIndexPath indexPathForRow:0 inSection:indexPath.section];
[self.itemNames removeObjectAtIndex:indexPath.row];
[self.itemNames insertObject:sText atIndex:0];
// Then you can move cell to back
[self.tableView moveRowAtIndexPath:indexPath toIndexPath:newPath];
[self.tableView sendSubviewToBack:blockCell]; // a little hacky
// OR per #Lombax, move header to front
UIView *sectionView = [self.tableView headerViewForSection:indexPath.section];
[self.tableView bringSubviewToFront:sectionView];
It's a bug.
You can quickly solve it by adding, after the line:
[self.tableView moveRowAtIndexPath:indexPath toIndexPath:newPath];
this lines:
UIView *sectionView = [self.tableView headerViewForSection:indexPath.section];
[self.tableView bringSubviewToFront:sectionView];
Not a solution but your code has number of issues. Who knows what happens if you fix them ;)
(1) Your cell may be nil after this line:
ListCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
It should look like this:
ListCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[ListCell alloc] initWithStyle:style
reuseIdentifier:cellIdentifier] autorelease];
}
(2) Two memory leaks in
-(UIView *)tableView:(UITableView *)aTableView viewForHeaderInSection:(NSInteger)section
->>Fix (When you add the label as subview it gets +1 ref).
UILabel *textLabel = [[[UILabel alloc] initWithFrame:CGRectMake(10, 0, 300, 21)] autorelease];
->>Fix (When you add the view as subview it gets +1 ref).
UIImageView *backgroundView = [[[UIImageView alloc]initWithImage:[AXThemeManager sharedTheme].tableviewSectionHeaderBackgroundImage] autorelease];
(3) Not a defect but this may help you. Try using this instead of [table reloadData]. It allows to animate things nicely and is not such a hardcore way to update the table. I'm sure it is much more lightweight. Alternatively try to look for other "update" methods. Given you don't delete rows in your example, something like [updateRowsFrom:idxFrom to:idxTo] would help.
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0]
withRowAnimation:UITableViewRowAnimationAutomatic];
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
float heightForHeader = 40.0;
if (scrollView.contentOffset.y<=heightForHeader&&scrollView.contentOffset.y>=0) {
scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0);
} else if (scrollView.contentOffset.y>=heightForHeader) {
scrollView.contentInset = UIEdgeInsetsMake(-heightForHeader, 0, 0, 0);
}
}
What I did to solve this problem was to set the zPosition of the view in the section header.
headerView.layer.zPosition = 1000 //just set a bigger number, it will show on top of all other cells.

UITableView scroll is choppy

Here is my cellForRowAtIndexPath method. Using ARC in my project.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
static NSString* cellIdentifier = #"ActivityCell";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
Activity* activityToShow = [self.allActivities objectAtIndex:indexPath.row];
//Cell and cell text attributes
cell.textLabel.text = [activityToShow name];
//Slowing down the list scroll, I guess...
LastWeekView* lastWeekView = [[LastWeekView alloc] initWithFrame:CGRectMake(10, 39, 120, 20)];
[lastWeekView setActivity:activityToShow];
lastWeekView.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:lastWeekView];
return cell;
}
LastWeelView allocation is slowing down the scroll i guess. In the lastWeekView, I fetch relationships of an entity from CoreData, perform a calculation on those values and draw some colors inside its drawRect method.
Here is the drawRect of LastWeekView
- (void)drawRect:(CGRect)rect
{
NSArray* activityChain = self.activity.computeChain; //fetches its relationships data
for (id item in activityChain) {
if (marking == [NSNull null])
{
[notmarkedColor set];
}
else if([(NSNumber*)marking boolValue] == YES)
{
[doneColor set];
}
else if([(NSNumber*)marking boolValue] == NO)
{
[notdoneColor set];
}
rectToFill = CGRectMake(x, y, 10, 10);
CGContextFillEllipseInRect(context, rectToFill);
x = x + dx;
}
}
What can I do to smoothen the scroll of tableView? If I have to asynchronously add this lastWeekView to each cell's contentView, how can i do it? please help.
I'd suggest allocating LastWeekView in cell's allocation scope. Also - fetch all core data objects in viewDidLoad so that in cellForRowAtIndexPath: method would retrieve it from array and not from the store. It should look something like this:
- (void)viewDidLoad
...
_activities = [Activity fetchAllInContext:managedObjectContext];
...
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCell];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
LastWeekView* lastWeekView = [[LastWeekView alloc] initWithFrame:CGRectMake(10, 39, 120, 20)];
lastWeekView.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:lastWeekView];
}
Activity *activityToShow = [_activities objectAtIndex:[indexPath row]];
LastWeekView *lastWeekView = (LastWeekView *)[[[cell contentView] subviews] lastObject];
[lastWeekView setActivity:activityToShow];
return cell;
}
Note that you may also subclass the UITableViewCell to replace contentView with your LastWeekView to quickly access the activity property.

Graphics in UITableView cells disappearing

Got a strange problem where I'm putting some text into a cell (using cell.textLabel) and a small "tick" graphic to the right of the cell. When I select the cell, the tick is supposed to appear, or disappear if it's already there. What actually happens is the tick appears then fades out again almost instantly. It's all pretty standard code, so if anyone's got any idea what's going on I'd be pleased to hear!
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
} else {
while ([[cell.contentView subviews] count] > 0) {
UIView *labelToClear = [[cell.contentView subviews] objectAtIndex:0];
[labelToClear removeFromSuperview];
}
}
NSString *theName = [[contacts objectForKey:[contactsKeys objectAtIndex:section]] objectAtIndex:row];
cell.textLabel = theName;
if (section == 0) {
cell.textLabel.textAlignment = UITextAlignmentCenter;
} else {
cell.textLabel.textAlignment = UITextAlignmentLeft;
}
if ([selectedContacts containsObject:theName]) {
CGFloat cellRight = tableView.frame.size.width - 70;
UIImage *theTickImage = [UIImage imageNamed:#"Tick.png"];
UIImageView *theTickImageView = [[[UIImageView alloc] initWithImage:theTickImage] autorelease];
theTickImageView.frame = CGRectMake(cellRight, 10, theTickImage.size.width, theTickImage.size.height);
[cell.contentView addSubview:theTickImageView];
}
return cell;
}
Many thanks for any help!
Well, I've figured it out - the cell.textLabel was sitting on top of my graphic, so obscuring it. I just set the backgroundColor property of the textLabel to [UIColor clearColor] and all was well - maybe I could have made my graphic sit on top of the textLabel, I haven't tried that yet.