The API for this is long-established by NSUserDefaults
, and should be your starting point for designing your API:
- (BOOL)boolForKey:(NSString *)defaultName;
If a boolean value is associated with defaultName in the user defaults, that value is returned. Otherwise, NO is returned.
You should avoid creating a different API for fetching bools from a keystore unless you have a strong reason. In most ObjC interfaces, fetching a non-exixtant key returns nil
and nil
is interpreted as NO
in a boolean context.
Traditionally, if one wants to distinguish between NO
and nil
, then call objectForKey
to retrieve the NSNumber
and check for nil
. Again, this is behavior for many Cocoa key stores and shouldn't be changed lightly.
However, it is possible that there is a strong reason to violate this expected pattern (in which case you should definitely note it carefully in the docs, because it is surprising). In that case, there are several well established patterns.
First, you can consider fetching an unknown key to be a programming error and you should throw an exception with the expectation that the program will soon crash because of this. It is very unusual (and unexpected) to create new kinds of exceptions for this. You should raise NSInvalidArgumentException
which exists exactly for this problem.
Second, you can distinguish between nil
and NO
by correctly using a get
method. Your method begins with get
, but it shouldn't. get
means "returns by reference" in Cocoa, and you can use it that way. Something like this:
- (BOOL)getBool:(BOOL *)value forKey:(NSString *)key {
id result = self.values[key];
if (result) {
if (value) {
// NOTE: This throws an exception if result exists, but does not respond to
// boolValue. That's intentional, but you could also check for that and return
// NO in that case instead.
*value = [result boolValue];
}
return YES;
}
return NO;
}
This takes a pointer to a bool and fills it in if the value is available, and returns YES
. If the value is not available, then it returns NO
.
There is no reason to involve NSError
. That adds complexity without providing any value here. Even if you are considering Swift bridging, I wouldn't use NSError
here to get throws
. Instead, you should write a simple Swift wrapper around this method that returns Bool?
. That's a much more powerful approach and simpler to use on the Swift side.