標籤:
今天在一個ios培訓網站上看到一篇部落格,講的是在NS_OPTIONS在Swift中的實現,寫得還算比較深刻全面,小編對其進行整理後,分享出來,希望對大家在iOS應用開發上有所協助吧。
在iOS開發中,我們常常需要定義一個枚舉,以替代C語言枚舉的定義方式,常用的方法就是在Objective-C中使用NS_ENUM和NS_OPTIONS。其中,NS_ENUM用於定義普通的枚舉,NS_OPTIONS用於定義選項類型的枚舉。
不同於Objective-C語言,Swift中的枚舉增加了更多特性,它可以包含原始類型(不再局限於整型)以及相關值。正是由於這些新增的特性,枚舉在Swift中得到了更廣泛的應用。在Foundation中,Objective-C中的NS_ENUM類型的枚舉,都會自動轉換成Swift中enum,並且更加精鍊。以Collection View的滾動方向為例,在Objective-C中,其定義如下:
typedef NS_ENUM(NSInteger, UICollectionViewScrollDirection) {
UICollectionViewScrollDirectionVertical,
UICollectionViewScrollDirectionHorizontal
};
而在Swift中,其定義如下:
enum UICollectionViewScrollDirection : Int {
case Vertical
case Horizontal
}
從上面這兩段代碼中,也可以看出swift中的實現確實精練了很多,在以後代碼的維護上也方便。在編碼中,定義枚舉時,採用哪種方式,你應該清楚了吧。
不過對於Objective-C中NS_OPTIONS類型的枚舉,Swift中的實現似乎就沒有那麼美好了。我們再來對比一下UICollectionViewScrollPosition的定義吧,在Objective-C中,其定義如下:
typedef NS_OPTIONS(NSUInteger, UICollectionViewScrollPosition) {
UICollectionViewScrollPositionNone = 0,
// The vertical positions are mutually exclusive to each other, but are bitwise or-able with the horizontal scroll positions.
// Combining positions from the same grouping (horizontal or vertical) will result in an NSInvalidArgumentException.
UICollectionViewScrollPositionTop = 1 << 0,
UICollectionViewScrollPositionCenteredVertically = 1 << 1,
UICollectionViewScrollPositionBottom = 1 << 2,
// Likewise, the horizontal positions are mutually exclusive to each other.
UICollectionViewScrollPositionLeft = 1 << 3,
UICollectionViewScrollPositionCenteredHorizontally = 1 << 4,
UICollectionViewScrollPositionRight = 1 << 5
};
而在Swift 2.0中,其定義如下:
struct UICollectionViewScrollPosition : OptionSetType {
init(rawValue: UInt)
static var None: UICollectionViewScrollPosition { get }
// The vertical positions are mutually exclusive to each other, but are bitwise or-able with the horizontal scroll positions.
// Combining positions from the same grouping (horizontal or vertical) will result in an NSInvalidArgumentException.
static var Top: UICollectionViewScrollPosition { get }
static var CenteredVertically: UICollectionViewScrollPosition { get }
static var Bottom: UICollectionViewScrollPosition { get }
// Likewise, the horizontal positions are mutually exclusive to each other.
static var Left: UICollectionViewScrollPosition { get }
static var CenteredHorizontally: UICollectionViewScrollPosition { get }
static var Right: UICollectionViewScrollPosition { get }
}
光看代碼,不看實現,這也是化簡為繁的節奏。
為什麼要在swift中這樣做呢?Mattt給我們的解釋是:
由於Swift不支援C語言中枚舉值的整型掩碼操作的技巧,在Swift中,一個枚舉可以表示一組有效選項的集合,但卻沒有辦法支援這些選項的組合操作(“&”、”|”等)。理論上,一個枚舉可以定義選項值的任意組合值,但對於n > 3這種操作,卻無法有效支援。
為了支援類NS_OPTIONS的枚舉,Swift 2.0中定義了OptionSetType協議,它的聲明如下:
/// Supplies convenient conformance to `SetAlgebraType` for any type
/// whose `RawValue` is a `BitwiseOperationsType`. For example:
///
/// struct PackagingOptions : OptionSetType {
/// let rawValue: Int
/// init(rawValue: Int) { self.rawValue = rawValue }
///
/// static let Box = PackagingOptions(rawValue: 1)
/// static let Carton = PackagingOptions(rawValue: 2)
/// static let Bag = PackagingOptions(rawValue: 4)
/// static let Satchel = PackagingOptions(rawValue: 8)
/// static let BoxOrBag: PackagingOptions = [Box, Bag]
/// static let BoxOrCartonOrBag: PackagingOptions = [Box, Carton, Bag]
/// }
///
/// In the example above, `PackagingOptions.Element` is the same type
/// as `PackagingOptions`, and instance `a` subsumes instance `b` if
/// and only if `a.rawValue & b.rawValue == b.rawValue`.
protocol OptionSetType : SetAlgebraType, RawRepresentable {
/// An `OptionSet`‘s `Element` type is normally `Self`.
typealias Element = Self
/// Convert from a value of `RawValue`, succeeding unconditionally.
init(rawValue: Self.RawValue)
}
從字面上來看,OptionSetType是選項集合類型,它定義了一些基本操作,包括集合操作(union, intersect, exclusiveOr)、成員管理(contains, insert, remove)、位操作(unionInPlace, intersectInPlace, exclusiveOrInPlace)以及其它的一些基本操作。
作為樣本,我們來定義一個表示方向的選項集合,通常我們是定義一個實現OptionSetType協議的結構體,如下所示:
struct Directions: OptionSetType {
var rawValue:Int
init(rawValue: Int) {
self.rawValue = rawValue
}
static let Up: Directions = Directions(rawValue: 1 << 0)
static let Down: Directions = Directions(rawValue: 1 << 1)
static let Left: Directions = Directions(rawValue: 1 << 2)
static let Right: Directions = Directions(rawValue: 1 << 3)
}
所需要做的基本上就是這些。然後我們就可以建立Directions的執行個體了,如下所示:
let direction: Directions = Directions.Left
if direction == Directions.Left {
// ...
}
如果想同時支援兩個方向,則可以如上處理:
let leftUp: Directions = [Directions.Left, Directions.Up]
if leftUp.contains(Directions.Left) && leftUp.contains(Directions.Up) {
// ...
}
如果leftUp同時包含Directions.Left和Directions.Up,則返回true。
這裡還有另外一種方法來達到這個目的,就是我們在Directions結構體中直接聲明聲明Left和Up的靜態常量,如下所示:
struct Directions: OptionSetType {
// ...
static let LeftUp: Directions = [Directions.Left, Directions.Up]
static let RightUp: Directions = [Directions.Right, Directions.Up]
// ...
}
這樣,我們就可以以如下方式來執行上面的操作:
if leftUp == Directions.LeftUp {
// ...
}
當然,如果單一選項較多,而要去組合所有的情況,這種方法就顯示笨拙了,這種情況下還是推薦使用contains方法。
總體來說,雖然Swift中的對選項的支援沒有Objective-C中的NS_OPTIONS來得簡潔方便,但相比Swift 1.2,Swift 2.0已經有了很大的改善。Swift作為一門新的iOS開發語言,其很多方面在Objective-C的基礎上都有了很大的改善,且swift成為今後iOS開發主流語言是必然,所以對於NS_OPTIONS的實現,大家還是需要嘗試用Swift語言,慢慢習慣就好了。
NS_OPTIONS在swift中怎麼實現?