简体   繁体   中英

issue with UIButton image in UITableCellView

I am making a simple timer app. I have a uitable with multiple rows. In that table I have put a UIButton. Everything works and so far so good ie I see the button appear in each row. What I needed to do next was to set an image for the UIButton eg if the timer was running I wanted to show stop_button_image in the UIButton and if the timer had started I wanted to set the UIImage on the button to start_button_image

The problem is that if the table gets refreshed then I get a nasty traceback depending upon where I had put the UIButton setimage code. Here is my code for reference.

//WORKING CODE: (NOT THAT I WANT)
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        //TESTING - Button
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];

        // Try to retrieve from the table view a now-unused cell with the given identifier.
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

        // If no cell is available, create a new one using the given identifier.
        if (cell == nil)
        {
            // Use the default cell style.
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];

            //TESTING - Button
            [button addTarget:self
                       action:@selector(timerStopStart:)
             forControlEvents:UIControlEventTouchDown];
            [button setTitle:@"Start/Stop" forState:UIControlStateNormal];
            button.frame = CGRectMake(5.0f, 5.0f, 72.0f, 77.0f);
            button.tag = indexPath.row;
            [cell addSubview:button];

    //THIS WORKS IF I PUT THIS HERE
            [button setImage:[UIImage imageNamed:@"button_pause.png"] forState:UIControlStateNormal];

        }
        else 
        {
             //NSLog(@"went here 2");
             button = (UIButton *) [cell viewWithTag:indexPath.row];
        }

//some other logic
    }

//CODE BREAKS HERE

        - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
        {
            //TESTING - Button
            UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];

            // Try to retrieve from the table view a now-unused cell with the given identifier.
            UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

            // If no cell is available, create a new one using the given identifier.
            if (cell == nil)
            {
                // Use the default cell style.
                cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];

                //TESTING - Button
                [button addTarget:self
                           action:@selector(timerStopStart:)
                 forControlEvents:UIControlEventTouchDown];
                [button setTitle:@"Start/Stop" forState:UIControlStateNormal];
                button.frame = CGRectMake(5.0f, 5.0f, 72.0f, 77.0f);
                button.tag = indexPath.row;
                [cell addSubview:button];


            }
            else 
            {
                 //NSLog(@"went here 2");
                 button = (UIButton *) [cell viewWithTag:indexPath.row];
            }

//CODE BREAKS HERE
[button setImage:[UIImage imageNamed:@"button_pause.png"] forState:UIControlStateNormal];

    //some other logic
        }

The problem is that when the table gets refreshed it calls the section with code button = (UIButton *) [cell viewWithTag:indexPath.row]; which I know is just a reference.

Here is the error I get in iOS simulator. I really want to put that image code outside the cell==null check. Any clues how this can be done?

Here is the error that I get in the simulator

2012-06-14 12:39:27.246 Timers[5381:10a03] -[UITableViewCell setImage:forState:]: unrecognized selector sent to instance 0x73706e0
2012-06-14 12:39:27.247 Timers[5381:10a03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITableViewCell setImage:forState:]: unrecognized selector sent to instance 0x73706e0'
*** First throw call stack:
(0x150b052 0x16bbd0a 0x150cced 0x1471f00 0x1471ce2 0x136c6 0x7b5e0f 0x7b6589 0x7a1dfd 0x7b0851 0x75b322 

The problem is probably when the indexPath.row is zero. In that case, you call viewWithTag:0 but as the tag of any UIView is 0 by default, there are chances that a lot of your cell's subview have a tag with the value 0, not only your UIButton.

To avoid this issue, try adding a constant (like 100) to your indexPath.row before affecting it to the tag, so that your button at row 0 will have the tag 100 and not 0 (and button at row 1 will have the tag 101, and so on…), avoiding it to be confused with any other subview with tag 0.

Yeah, this will fail for row 0.

button = (UIButton *) [cell viewWithTag:indexPath.row];

will return cell when indexPath.row is 0, because cell.tag is 0.


As a general note, this approach will not work. The first time you reuse a cell the button will have the wrong tag. For example, if you reuse the cell from row 2 in row 18, then the tag on the button will be 2, but the tag you look for is 18. It will return nil .

why not define a constant #define kMyStopStartButtonTag 12345 and use that constant the whole time.

if (cell == nil)
{
    …
    button.tag = kMyStopStartButtonTag;
    [cell addSubview:button];
    …
} else {
    button = (UIButton *) [cell viewWithTag:kMyStopStartButtonTag];
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM