Analyzer warning in Facebook API for iOS
-
09-06-2021 - |
Question
here's the code from the APICallsViewController file and a couple of screenshots. my app is crashing and I'm not sure if this is the cause.
thanks for any help
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UILabel *textLabel;
UILabel *detailTextLabel;
UIButton *button;
UIFont *cellFont = [UIFont boldSystemFontOfSize:14.0];
UIFont *detailCellFont = [UIFont fontWithName:@"Helvetica" size:12.0];
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// Initialize API title UILabel
textLabel = [[[UILabel alloc] initWithFrame:CGRectZero] autorelease];
textLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin;
textLabel.tag = TITLE_TAG;
textLabel.font = cellFont;
[cell.contentView addSubview:textLabel];
// Initialize API description UILabel
detailTextLabel = [[[UILabel alloc] initWithFrame:CGRectZero] autorelease];
detailTextLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin;
detailTextLabel.tag = DESCRIPTION_TAG;
detailTextLabel.font = detailCellFont;
detailTextLabel.textColor = [UIColor darkGrayColor];
detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
detailTextLabel.numberOfLines = 0;
[cell.contentView addSubview:detailTextLabel];
// Initialize API button UIButton
button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin;
[button setBackgroundImage:[[UIImage imageNamed:@"MenuButton.png"]
stretchableImageWithLeftCapWidth:9 topCapHeight:9]
forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button addTarget:self action:@selector(apiButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:button];
} else {
textLabel = (UILabel *)[cell.contentView viewWithTag:TITLE_TAG];
detailTextLabel = (UILabel *)[cell.contentView viewWithTag:DESCRIPTION_TAG];
// For the button cannot search by tag since it is not constant
// and is dynamically used figure out which button is clicked.
// So instead we loop through subviews of the cell to find the button.
for (UIView *subview in cell.contentView.subviews) {
if([subview isKindOfClass:[UIButton class]]) {
button = (UIButton *)subview;
}
}
}
CGSize constraintSize = CGSizeMake(280.0f, MAXFLOAT);
// The API title
NSString *cellText = [[apiMenuItems objectAtIndex:indexPath.row] objectForKey:@"title"];
CGSize labelSize = [cellText sizeWithFont:cellFont
constrainedToSize:constraintSize
lineBreakMode:UILineBreakModeWordWrap];
textLabel.frame = CGRectMake(20, 2,
(cell.contentView.frame.size.width-40),
labelSize.height);
textLabel.text = cellText;
// The API description
NSString *detailCellText = [[apiMenuItems objectAtIndex:indexPath.row] objectForKey:@"description"];
CGSize detailLabelSize = [detailCellText sizeWithFont:detailCellFont
constrainedToSize:constraintSize
lineBreakMode:UILineBreakModeWordWrap];
detailTextLabel.frame = CGRectMake(20, (labelSize.height + 4),
(cell.contentView.frame.size.width-40),
detailLabelSize.height);
detailTextLabel.text = detailCellText;
// The API button
CGFloat yButtonOffset = labelSize.height + detailLabelSize.height + 15;
button.frame = CGRectMake(20, yButtonOffset, (cell.contentView.frame.size.width-40), 44);
[button setTitle:[[apiMenuItems objectAtIndex:indexPath.row] objectForKey:@"button"]
forState:UIControlStateNormal];
// Set the tag that will later identify the button that is clicked.
button.tag = indexPath.row;
return cell;
}
Solution
in the else
statement the UIButton *button
is not initialized. Look how in the if statement it is:
button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
but in the else
initialization is missing. You may put after:
} else {
textLabel = (UILabel *)[cell.contentView viewWithTag:TITLE_TAG];
detailTextLabel = (UILabel *)[cell.contentView viewWithTag:DESCRIPTION_TAG];
button = (UIButton *)[cell.contentView viewWithTag:indexPath.row]; // <---- add this
And move this:
button.tag = indexPath.row;
before
[cell.contentView addSubview:button];
in the end of the if statement...
OTHER TIPS
The button
variable is a local variable. Unless you are using ARC, it's not guaranteed to be initialised to anything. It could be nonsense. The analyser is warning you that it's not clear it has had a meaningful address assigned to by the time you attempt to send a message to it (the setter for the frame
property is the message you are sending it).
Consider this: cell
is not nil
, and you don't find a button in its subviews. If this is the case, the application will reach the line in question without ever having assigned to the button
variable. It could contain a pointer to absolutely anywhere. If you try to dereference the pointer to send a message to the object, you could be scribbling over memory anywhere in your application.
Now, it may be the case that you know it is guaranteed to find a subclass that is a button. But the analyser can't figure that out. So it warns you regardless.
You should initialise the button
variable to nil
. If there is the possibility of not finding a button, you should handle that case.