I have a model object which includes a boolean flag. I want to show the value of the flag using a UISwitch. The value can be changed in two ways:
However, setting the value of the switch in the timer method has the effect that the touchUpInside action is sometimes not triggered even though the user has touched the switch.
So I face the following problem: If I set the switch state in the timer when the state changes externally, I loose some state changes from the user. If I don't use the timer I get all state changes from the user. However, I miss all the external state changes, then.
Now I have run out of ideas. How can I achieve what I want, getting both types of state changes in the model and reflected them correctly in the switch view?
Here is a minimal example that shows the problem. I have replaced the model object by a simple boolean flag, and in the timer I don't change the flag at all, I just call setOn:animated:. I count the invocations of the action method. Like that I can easily find out how many touches were missed:
#import "BPAppDelegate.h"
#import "BPViewController.h"
@implementation BPAppDelegate {
NSTimer *repeatingTimer;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
BPViewController *viewController = [[BPViewController alloc] init];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
[self startTimer];
return YES;
}
- (void) startTimer {
repeatingTimer = [NSTimer scheduledTimerWithTimeInterval: 0.2
target: self.window.rootViewController
selector: @selector(timerFired:)
userInfo: nil
repeats: YES];
}
@end
#import "BPViewController.h"
@implementation BPViewController {
UISwitch *uiSwitch;
BOOL value;
int count;
}
- (void)viewDidLoad
{
[super viewDidLoad];
value = true;
uiSwitch = [[UISwitch alloc] init];
uiSwitch.on = value;
[uiSwitch addTarget:self action:@selector(touchUpInside:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:uiSwitch];
}
- (void)touchUpInside: (UISwitch *)sender {
count++;
value = !value;
NSLog(@"touchUpInside: value: %d, switch: %d, count: %d", value, sender.isOn, count);
}
- (void) timerFired: (NSTimer*) theTimer {
NSLog(@"timerFired: value: %d, switch: %d, count: %d", value, uiSwitch.isOn, count);
// set the value according to some external state. For the example just leave it.
[uiSwitch setOn:value animated:false];
}
@end
My original code works as expected in iOS 7. So it seems to have been a bug in iOS 6.