Don't be confused. We are talking about Options instead of Optional. Optional is widely discussed and I don't think I can add anything.
So, for Options, in Objective-C we have NS_OPTIONS
. But how to use it in Swift?
There are quite a lot of APIs needs options. They are used to control the behaviors of that API. Take an example, we can pass some options to UIView
's animation API:
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationOptionCurveEaseIn |
UIViewAnimationOptionAllowUserInteraction
animations:^{
// ...
} completion:nil];
We could use bit operator like |
or &
to make combination on these options. In Objective-C, options always defined in a a bit offset way:
typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) {
UIViewAnimationOptionLayoutSubviews = 1 << 0,
UIViewAnimationOptionAllowUserInteraction = 1 << 1,
UIViewAnimationOptionBeginFromCurrentState = 1 << 2,
//...
UIViewAnimationOptionTransitionFlipFromBottom = 7 << 20,
}
By using a typedef
definition, we could use NS_OPTIONS
to map UIViewAnimationOptions
to a series NSUInteger
, with the bit of which is different from other options. If there is no need to pass an option, you can just use kNilOptions
, which is defined to number 0.
enum {
kNilOptions = 0
};
In Swift, NS_ENUM
could be replaced well with the new enum
type. However, the NS_OPTIONS
is not so lucky since there is no corresponding type for it. The option values are now defined as a struct
which conforms OptionSetType
protocol, with a set of static properties as its values. Take the popular UIViewAnimationOptions
as an example:
struct UIViewAnimationOptions : OptionSetType {
init(rawValue: UInt)
static var LayoutSubviews: UIViewAnimationOptions { get }
static var AllowUserInteraction: UIViewAnimationOptions { get } // turn on user interaction while animating
//...
static var TransitionFlipFromBottom: UIViewAnimationOptions { get }
}
By doing this, we can use a similar syntax to set options for a method. The UIView
animation code above in Swift would be:
UIView.animateWithDuration(0.3,
delay: 0.0,
options: [.CurveEaseIn, .AllowUserInteraction],
animations: {},
completion: nil)
Since the OptionSetType conforms SetAlgebraType
protocol, which defines basic logic calculation on options, we can use an array literal conversion to construct the options set. Beside of that, there are also some additional operations defined in that protocol, such as contains
and intersect
.
If there is no need to pass an option, you can simply use nil
for it.
To implement our own option set, we can refer to the existing ones and create a structure conforming to the OptionSetType
. We are required to explicitly point out the type of rawValue
of the option. It should be following the BitwiseOperationsType
protocol so the bit logic could be performed on the option. UInt
is an ideal type for the option set, and a customized option set could be like this:
struct MyOptions : OptionSetType {
let rawValue: UInt
init(rawValue: UInt) {
self.rawValue = rawValue
}
static let None = MyOptions(rawValue: 0)
static let Option1 = MyOptions(rawValue: 1 << 0)
static let Option2 = MyOptions(rawValue: 1 << 1)
}
So simple, isn't it?