Reputation: 341
I need to extract data from a dictionary (attributes from NSXMLParser, but I don't think that matters). The below works but is this really the "easiest" why to do it? The attribute may or may not exist in the dictionary. The value of the attribute may or may not convert to an integer (i.e. toInt() returns an optional). 'mandatory' is a Bool and 'minimumLength' is an Int and are class properties.
func decodeDataRestrictions(#attributeDictionary: [NSObject: AnyObject]!) {
var stringValue: String?
var intValue: Int?
// Extract data restrictions from the element attributes
self.mandatory = false
stringValue = attributeDictionary["mandatory"] as String?
if stringValue != nil {
if stringValue! == "true" {
self.mandatory = true
}
}
self.minimumLength = 1
stringValue = attributeDictionary["minimumLength"] as String?
if stringValue != nil {
intValue = stringValue!.toInt()
if intValue != nil {
self.minimumLength = intValue!
}
}
in Objective-C it was much easier:
self.mandatory = NO;
if ([[attributeDict objectForKey:@"mandatory"] isEqualToString:@"true"]) {
self.mandatory = YES;
}
self.minimumLength = 1;
if ([attributeDict objectForKey:@"minimumLength"] != nil) {
self.minimumLength = [NSNumber numberWithInteger:[[attributeDict objectForKey:@"minimumLength"] integerValue]];
}
Upvotes: 2
Views: 1142
Reputation: 40963
You ought to be able to write that whole function as follows:
func decodeDataRestrictions(#attributeDictionary: [NSObject: AnyObject]!) {
if (attributeDictionary["mandatory"] as? String) == "true" {
self.mandatory == true
}
if let minimumLength = (attributeDictionary["minimumLength"] as? String)?.toInt() {
self.minimumLength = minimumLength
}
}
If you need to check an optional for nil-ness, and then use the value if it isn’t nil, then if let
combines these two things, setting a local variable to the unwrapped value if non-nil. This is what’s happening with minimumLength
, along with some optional chaining (i.e. if the value is non-nil, move on to do toInt()
else nil).
In the case of mandatory
, you can compare an optional value to a non-optional value with ==
, so there’s no need to check for nil at all.
edit: having read your Objective-C version, you can simplify it even further if you’re happy to default the self
values even in cases of missing dictionary data, as you’re doing there:
func decodeDataRestrictions(#attributeDictionary: [NSObject: AnyObject]!) {
self.mandatory = (attributeDictionary["mandatory"] as? String) == "true"
self.minimumLength = (attributeDictionary["minimumLength"] as? String)?.toInt() ?? 1
}
The minimumLength
version uses the nil-coalescing operator, which substitutes a default value from the right-hand side in case of nil on the left-hand side.
Upvotes: 2
Reputation: 72760
You should use optional binding - the first extraction can be simply written as:
if let mandatory = attributeDictionary["mandatory"] as? String {
self.mandatory = mandatory == "true"
}
whereas the 2nd requires an additional check:
if let minLen = attributeDictionary["minimumLength"] as String? {
if let minLen = minLen.toInt() {
self.minimumLength = minLen
}
}
the first if
verifies that a value for the mandatory
key exists, the second verifies that the value is convertible to an integer.
Upvotes: 1