0

Has anyone noticed with the changes added to UISwitch in Beta 4, that if you set a switches tag, for some reason it doesn't respect it? I add a switch programmatically to the accessory view of a TableView cell and once the cell is selected I access the switch to get it's tag to know which switch it was and the state that was changed.

Here are the code examples:

if (_showSwitch) {
    if (cell.accessoryView == nil) {
       cell.selectionStyle = UITableViewCellSelectionStyleNone;
       switchview = [[UISwitch alloc]initWithFrame:CGRectZero];
       switchview.tag = indexPath.row;
       cell.accessoryView = switchview;
       [switchview addTarget:self action:@selector(switchChanged:) 
       forControlEvents:UIControlEventValueChanged];
        cell.backgroundColor = UIColor.systemGray2Color;
    }

    NSArray *strArray = [_tableDataSource[indexPath.row] componentsSeparatedByString:@"/"]; 
    _row = indexPath.row;
    _cellLabel = strArray[0];

    cell.textLabel.text =  _cellLabel;
    _cellArray =    [_cellArray arrayByAddingObject:(NSString *)_cellLabel];

    if (_level >= 1) {
        _deviceID =   strArray[1];
        _deviceArray =   [_deviceArray arrayByAddingObject:_deviceID];
        _lowcaseDeviceID = _deviceID = _deviceID.lowercaseString;    
        dictLookup =     _statusDict[_lowcaseDeviceID];
        if (_row >= 1) {
            mycmdString = [mycmdString stringByAppendingString:@","];
        }
        mycmdString =    [mycmdString stringByAppendingString:_deviceID];

        UISwitch *switchView = (UISwitch *)cell.accessoryView;

        [switchView setOn:NO animated:NO];
        if ([dictLookup isEqualToString:@"ON"]) {
            cell.textLabel.textColor = UIColor.systemGreenColor;
            [switchView setOn:YES animated:YES];
        }
        _callForStatus = TRUE;
    } else {
        cell.accessoryType = UITableViewCellAccessoryNone;
        cell.accessoryView = nil;
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }

- (IBAction)ControlView:(UISwitch *)sender {
    ControlViewController *flController = [[ControlViewController alloc]
                                           initWithNibName:@"ControlViewController" bundle:nil];
    (flController.navigationItem).title = [NSString stringWithFormat:@"%@ - %@", _deviceName, _device];
    _level = _level += 1;
    flController.deviceID = _device;
    flController.deviceName = _deviceName;
    flController.deviceState = @"OFF";
    if ((sender.isOn) == YES) {
        flController.deviceState = @"ON";
    }
    double delayInSeconds = 0.1;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
        [self presentViewController:flController animated:YES completion:nil];
    });
}


    - (void)switchChanged:(UISwitch *)sender {
        bool mode;
        UISwitch *switchControl = sender;
        if (switchControl.isOn == YES) {
            [switchControl setOn:YES animated:YES];
            mode = TRUE;
            [General playSound:@"Button Up.mp3"];
        } else {
            [switchControl setOn:NO animated:NO];
            mode = FALSE;
            [General playSound:@"Button Down.mp3"];
        }
        sender.highlighted = YES;
        _callForStatus = TRUE;
        [self executeSwitchAtRow:switchControl.tag forMode:mode];
      //  if (_level >= 1) [self startStepperTimer];
    }

    - (void)executeSwitchAtRow:(NSInteger)row forMode:(BOOL)onoff {
        NSString *mode = @"OFF";
        if (onoff) {
            mode = @"ON";
        }
        NSString *device = _deviceArray[row];
        Debug_1(@"Send Switch Change for device %@ %@",device,mode);
    
        NSString *execCommand = [NSString stringWithFormat:@"device %@ %@", mode, device];
    
        [[NSNotificationCenter defaultCenter] postNotificationName:@"sendMessageFromExternal" object:self
                                                          userInfo:@{ @"cmd": execCommand }];
        if (_level >= 1) [self startStepperTimer];
    
    }

...

Bookworm
  • 1
  • 2
  • sure `_level !=0` (`_level >=1`) so cell.accessoryView is not set to nil? You don't add `switchview` to as subview here, instead you did set it as accessoryView. The question is, can accessoryView become nil before the target action is send to switchChanged and is _level guaranteed not to nil the switchview from accessoryView? – Ol Sen Aug 11 '20 at 18:38
  • The level is because the view controller pushes itself. The 1st level is a list of rooms to select. Once in a room the devices in the room are then listed with their status. You can tap on the device to enter another controller that lets fine control like dim levels, etc. But if you tap on the switch it just toggles the on/off for the device. This all worked perfectly in IOS 13 but XCode Beta 4 introduced UISwitch attributes. As for the nil question, that might be what has changed as it works great on my wife's IOS 13 compiled with Beta 2. It has been working this way since iOS 11. – Bookworm Aug 11 '20 at 20:02
  • then maybe subclassing UISwitch and making a custom property to hold an Integer could be a workaround for the moment. As you describe the behaviour possibly a bug worth reporting indeed. – Ol Sen Aug 11 '20 at 21:02
  • As an aside, we often don’t use the `tag` because that breaks when you insert or delete a row (without reloading the whole table). For a more general solution, we will (a) hook up our actions to the cell and then (b) have the _cell_ tell the view controller that its switch (or whatever sort of control you are using) has been updated. When the cell does this, it can pass a reference to itself, and the view controller dynamically can deduce which row’s switch has been updated. https://stackoverflow.com/a/39566554/1271826 is Swift demonstration of the pattern. – Rob Aug 12 '20 at 16:49
  • That's a good idea and I'll look into it, translating it to Obj-C of course. But in this application, the rows never change or get added to once the screen is presented. They are constant as the number of rooms in the house hardly ever change and the number of devices per room also hardly change. But either way, at launch time, I poll the server to get all the Room and Device per/room (Name, Features, Status) and populate. So I just reuse the existing cells. Thanks. I'm going to file a bug issue with Apple sometime today. – Bookworm Aug 12 '20 at 19:10

0 Answers0