混编中的枚举
在 Apple|Grouping Related Objective-C Constants 中,Apple 详细列举了 NS_ENUM、NS_CLOSED_ENUM、NS_OPTIONS、NS_TYPED_ENUM、NS_TYPED_EXTENSIBLE_ENUM 等宏的使用场景,用好它们以改善在混编时在 Swift 中的编程体验。另外,Apple 建议弃用 NS_STRING_ENUM/NS_EXTENSIBLE_STRING_ENUM 而改用 NS_TYPED_ENUM/NS_TYPED_EXTENSIBLE_ENUM。
各种宏
NS_ENUM
// Declare in Objective-C
typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
UITableViewCellStyleDefault,
UITableViewCellStyleValue1,
UITableViewCellStyleValue2,
UITableViewCellStyleSubtitle
};
// In Swift, the UITableViewCellStyle enumeration is imported like this:
enum UITableViewCellStyle : Int {
case `default` = 0
case value1 = 1
case value2 = 2
case subtitle = 3
}
// Use it in Swift
let style = UITableViewCellStyle.default
这是基操, 但是如果是下面这种写法呢?
// Declare in Objective-C
typedef enum: NSUInteger {
UITableViewCellStyleDefault,
UITableViewCellStyleValue1,
UITableViewCellStyleValue2,
UITableViewCellStyleSubtitle
} UITableViewCellStyle;
// Generated Swift Interface
struct UITableViewCellStyle : Equatable, RawRepresentable {
init(_ rawValue: UInt)
init(rawValue: UInt)
var rawValue: UInt
}
// Use it in Swift
let style = UITableViewCellStyleDefault
可见, 不用NS_ENUM宏
- Swift 也会自动生成一个枚举, 但是类型是
struct而不是enum。 - 连名称也需要写全称, 一点也不
Swift。
NS_CLOSED_ENUM
NS_CLOSED_ENUM用于声明不会变更枚举成员的简单的枚举(简称 “冻结枚举” ),对应 Swift 中的 @frozen 关键字,将作为 @frozen enum 导入到 Swift 中。冻结枚举对于希望在 switch 语句中匹配有限状态集的时候非常有用,这个有限状态集是一个完整的集合,覆盖了所有情况,将来不会再有其他新的情况。
// Declare in Objective-C
typedef NS_CLOSED_ENUM(NSInteger, NSComparisonResult) {
NSOrderedAscending = -1L,
NSOrderedSame,
NSOrderedDescending
};
// In Swift, the NSComparisonResult enumeration is imported like this:
@frozen enum NSComparisonResult : Int {
case orderedAscending = -1
case orderedSame = 0
case orderedDescending = 1
}
使用 NS_ENUM 和 NS_CLOSED_ENUM 枚举宏在导入到 Swift 时生成的是 Enum 类型,而其它枚举宏都是生成 Struct 类型。
注:
冻结枚举降低了灵活性,但提升了性能。一旦枚举被标记为冻结枚举,那么在未来版本的库中就不能通过添加、删除或重新排序枚举的 case,否则会破坏 ABI 兼容性。
@unknown default不能用于冻结枚举,因为冻结枚举的 case 是固定的,不会发生改变。也就是说, 它用于非冻结枚举中的"未来加入的"枚举- 普通的"其它"是
default
NS_OPTIONS
// Declare in Objective-C
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
// In Swift, the UIViewAutoresizing type is imported like this:
public struct UIViewAutoresizing: OptionSet {
public init(rawValue: UInt)
public static var flexibleLeftMargin: UIViewAutoresizing { get }
public static var flexibleWidth: UIViewAutoresizing { get }
public static var flexibleRightMargin: UIViewAutoresizing { get }
public static var flexibleTopMargin: UIViewAutoresizing { get }
public static var flexibleHeight: UIViewAutoresizing { get }
public static var flexibleBottomMargin: UIViewAutoresizing { get }
}
// Use it in Swift
let style = UIViewAutoresizing([.flexibleWidth, .flexibleHeight])
可见, 要使用OPTIONS, 最好是在Objective-C中声明, 然后在Swift中使用。
NS_TYPED_ENUM
- 它是
NS_STRING_ENUM的替代品, 用来声明一个字符串类型的枚举 - 在OC中并不是枚举, 是普通的String
- 在Swift中则是一个Struct, 但可以把它当枚举来使用
// Store the three traffic light color options as 0, 1, and 2.
typedef long TrafficLightColor NS_TYPED_ENUM;
FOUNDATION_EXTERN TrafficLightColor const TrafficLightColorRed;
FOUNDATION_EXTERN TrafficLightColor const TrafficLightColorYellow;
FOUNDATION_EXTERN TrafficLightColor const TrafficLightColorGreen;
// In Swift, the TrafficLightColor type is imported like this:
struct TrafficLightColor : Hashable, Equatable, RawRepresentable {
init(rawValue: Int)
}
extension TrafficLightColor {
static let red: TrafficLightColor
static let yellow: TrafficLightColor
static let green: TrafficLightColor
}
// Use it in Swift
let color = TrafficLightColor.red
// 在能做类型推断的场景, 直接用点语法
let color: TrafficlightColor = .red
使用 NS_STRING_ENUM 宏,在逻辑上你不能在 Swift 中使用 extension 扩展新的常量集,虽然这是允许的。如果你需要做此支持,请使用
NS_TYPED_EXTENSIBLE_ENUM。
NS_TYPED_EXTENSIBLE_ENUM
用于声明可扩展的类型常量枚举。与 NS_TYPED_ENUM 的区别是生成的 struct 多了一个忽略参数标签的构造器。
// declared
typedef long FavoriteColor NS_TYPED_EXTENSIBLE_ENUM;
FOUNDATION_EXTERN FavoriteColor const FavoriteColorBlue;
// imported
struct FavoriteColor : Hashable, Equatable, RawRepresentable {
// 多生成了个构造器
init(_ rawValue: Int)
init(rawValue: Int)
}
extension FavoriteColor {
static let blue: FavoriteColor
}
// extended
extension FavoriteColor {
static var green: FavoriteColor {
return FavoriteColor(1) // blue is 0, green is 1, and new favorite colors could follow
}
}
小结
仔细看下苹果的#define, 可以发现其实最终都落在NS_TYPED_ENUM和NS_TYPED_EXTENSIBLE_ENUM上了.
#define _NS_TYPED_ENUM _CF_TYPED_ENUM
#define _NS_TYPED_EXTENSIBLE_ENUM _CF_TYPED_EXTENSIBLE_ENUM
// Note: NS_TYPED_ENUM is preferred to NS_STRING_ENUM
#define NS_STRING_ENUM _NS_TYPED_ENUM
// Note: NS_TYPED_EXTENSIBLE_ENUM is preferred to NS_EXTENSIBLE_STRING_ENUM
#define NS_EXTENSIBLE_STRING_ENUM _NS_TYPED_EXTENSIBLE_ENUM
#define NS_TYPED_ENUM _NS_TYPED_ENUM
#define NS_TYPED_EXTENSIBLE_ENUM _NS_TYPED_EXTENSIBLE_ENUM
via: source
Backlinks