iOS Tricks: Giving UISwitch's "on" Property Will/Did Change Observable Notifications






4.11/5 (2 votes)
The UISwitch's UIControlEventValueChanged event is pretty useless if you'd like to get a notification only when the switch value actually changes.
Introduction
The UISwitch
's UIControlEventValueChanged
event is pretty useless if you'd like to get a notification only when the switch value actually changes. I have a solution that allows you to attach to the switch's "on"
property's to get accurate change notifications.
Background
UISwitch
inherits from UIControl
which only has a UIControlEventValueChangedbefore
value for you to determine if the value actually did change.
The More Better Class
The MySwitch
class tweaks the UISwitch
control by posting key/value change events when the control's value changes. It stores the previous value so it can determine when the on
property actually changes.
MySwitch Interface
@interface MySwitch : UISwitch
@end
MySwitch Implementation
@implementation MySwitch
{
BOOL _previousValue;
BOOL _returnPreviousValue;
}
- (instancetype) initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder: aDecoder];
if (!self) return nil;
_previousValue = self.isOn; // if constructed via a nib
[self addTarget: self action: @selector(_didChange)
forControlEvents: UIControlEventValueChanged];
return self;
}
- (instancetype) initWithFrame: (CGRect) frame
{
self = [super initWithFrame: frame];
if (!self) return nil;
[self addTarget: self action: @selector(_didChange)
forControlEvents: UIControlEventValueChanged];
return self;
}
- (BOOL) isOn
{
return (_returnPreviousValue) // see [_didChange]
? _previousValue
: [super isOn];
}
- (void) setOn: (BOOL) on animated: (BOOL) animated
{
[super setOn: on animated: animated];
_previousValue = on; // if set manually
}
- (void) _didChange
{
BOOL isOn = self.isOn;
if (isOn == _previousValue) return;
_returnPreviousValue = true; // the will change might query
// the current value. (isOn must then return the previous value)
[self willChangeValueForKey: @"on"];
_returnPreviousValue = false;
_previousValue = isOn;
[self didChangeValueForKey: @"on"];
}
@end
And Then Make Your Codez Sweet
All you need to do is add an observer to the MySwitch
instance. The observer can even get the old and new values in the change
parameter. (See NSKeyValueObservingOptionOld
and NSKeyValueObservingOptionNew
)
- (void) viewDidLoad
{
[super viewDidLoad];
[self.switchView addObserver: self forKeyPath: @"on"
options: NSKeyValueObservingOptionNew context: nil];
}
- (void) observeValueForKeyPath: (NSString *)
keyPath ofObject: (id) object change: (NSDictionary *) change context: (void *) context
{
if ([[change objectForKey: @"new"] boolValue])
{
self.textView.text =
[self.textView.text stringByAppendingString: @"changed to: ON\n"];
}
else
{
self.textView.text =
[self.textView.text stringByAppendingString: @"changed to: OFF\n"];
}
}
- (void) toggleSwitch : (id) sender
{
self.switchView.on = !self.switchView.on;
}
History
- Initial version