在 Objective-C 中访问 Swift OptionSetType
Accessing Swift OptionSetType in Objective-C
在我的 Swift class 中,我为履行选项定义了 OptionSetType
。
struct FulfillmentOption : OptionSetType {
let rawValue: Int
static let Pickup = FulfillmentOption(rawValue: 1 << 0)
static let Shipping = FulfillmentOption(rawValue: 1 << 1)
static let UserShipping = FulfillmentOption(rawValue: 1 << 2)
}
然后我为 add/remove 创建一个变量并读取选项。这按预期工作。
var options: FulfillmentOption = []
options.insert(FulfillmentOption.Pickup)
options.contains(FulfillmentOption.Pickup)
但是我需要从我的 Objective-C classes 之一访问 options
变量。由于 OptionSetType
未在 Objective-C 中定义,因此该变量对我的任何 Objective-C classes.
都不可见
我向 Objective-C 公开此内容的最佳方式是什么?我应该完全停止使用 OptionSetType
吗?
我考虑过像这样创建 public
和 private
变量以在两者之间进行转换。我不喜欢这个,但这是迄今为止我想出的最好的。
private var _options: FulfillmentOptions = []
private var options: UInt {
get {
// get raw value from _options
}
set {
// set raw value to _options
}
}
有没有更优雅的方法来完成这个?我想避免编写不必要的代码。
不是您问题的直接答案,但您可以作为替代方案
反过来工作。定义
typedef NS_OPTIONS(NSInteger, FulfillmentOption) {
FulfillmentOptionPickup = 1 << 0,
FulfillmentOptionShipping = 1 << 1,
FulfillmentOptionUserShipping = 1 << 2,
};
在 Objective-C header 中,这将作为
导入到 Swift
public struct FulfillmentOption : OptionSetType {
public init(rawValue: Int)
public static var Pickup: FulfillmentOption { get }
public static var Shipping: FulfillmentOption { get }
public static var UserShipping: FulfillmentOption { get }
}
可以在 "Using Swift with Cocoa and Objective-C" 参考资料中找到更多信息:
- "Interaction with C APIs":
Swift also imports C-style enumerations marked with the
NS_OPTIONS
macro as a Swift option set. Option sets behave similarly to imported
enumerations by truncating their prefixes to option value names.
- "Swift and Objective-C in the Same Project":
You’ll have access to anything within a class or protocol that’s
marked with the @objc
attribute as long as it’s compatible with
Objective-C. This excludes Swift-only features such as those listed
here:
- ...
- Structures defined in Swift
- ...
Objective-C 看不到 struct
,但幸运的是,您可以使用 @objc class
来实现 OptionSet
。
请注意,实现 -hash
和 -isEqual:
非常重要,因为 OptionSet
继承的许多 SetAlgebra
默认实现都依赖它们才能工作。如果你不实现它们,print("\(Ability(.canRead) == Ability(.canRead))")
打印 false
.
@objc
public final class Ability: NSObject, OptionSet {
// Don't use
//
// public static let canRead = Ability(rawValue: 1 << 0)
// public static let canWrite = Ability(rawValue: 1 << 1)
//
// because `Ability` is a `class`, not a `struct`,
// so `let` doesn't enforce immutability, and thus
//
// Ability.canRead.formUnion(Ability.canWrite)
//
// would break `Ability.canRead` for everyone!
public static func canRead(): Ability {
return Ability(rawValue: 1 << 0)
}
public static func canWrite(): Ability {
return Ability(rawValue: 1 << 1)
}
public var rawValue: Int
public typealias RawValue = Int
public override convenience init() {
self.init(rawValue: 0)
}
public init(rawValue: Int) {
self.rawValue = rawValue
super.init()
}
/// Must expose this to Objective-C manually because
/// OptionSet.init(_: Sequence) isn't visible to Objective-C
/// Because Sequence isn't an Objective-C-visible type
@objc
@available(swift, obsoleted: 1.0)
public convenience init(abilitiesToUnion: [Ability]) {
self.init(abilitiesToUnion)
}
// MARK: NSObject
// Note that it is very important to implement -hash and
// -isEqual: because lots of the `SetAlgebra`
// default implementations that `OptionSet` inherits
// rely on them to work. If you don't implement them,
// print("\(Ability(.canRead) == Ability(.canRead))")
// prints `false`
public override var hash: Int {
return rawValue
}
public override func isEqual(_ object: Any?) -> Bool {
guard let that = object as? Ability else {
return false
}
return rawValue == that.rawValue
}
// MARK: OptionSet
public func formUnion(_ other: Ability) {
rawValue = rawValue | other.rawValue
}
public func formIntersection(_ other: Ability) {
rawValue = rawValue & other.rawValue
}
public func formSymmetricDifference(_ other: Ability) {
rawValue = rawValue ^ other.rawValue
}
}
然后,我可以从 Objective-C:
实例化它
Ability *emptyAbility = [Ability new];
Ability *readOnlyAbility = [[Ability alloc] initWithAbilitiesToUnion:@[Ability.canRead]];
Ability *readWriteAbility = [[Ability alloc] initWithAbilitiesToUnion:@[Ability.canRead, Ability.canWrite]];
在我的 Swift class 中,我为履行选项定义了 OptionSetType
。
struct FulfillmentOption : OptionSetType {
let rawValue: Int
static let Pickup = FulfillmentOption(rawValue: 1 << 0)
static let Shipping = FulfillmentOption(rawValue: 1 << 1)
static let UserShipping = FulfillmentOption(rawValue: 1 << 2)
}
然后我为 add/remove 创建一个变量并读取选项。这按预期工作。
var options: FulfillmentOption = []
options.insert(FulfillmentOption.Pickup)
options.contains(FulfillmentOption.Pickup)
但是我需要从我的 Objective-C classes 之一访问 options
变量。由于 OptionSetType
未在 Objective-C 中定义,因此该变量对我的任何 Objective-C classes.
我向 Objective-C 公开此内容的最佳方式是什么?我应该完全停止使用 OptionSetType
吗?
我考虑过像这样创建 public
和 private
变量以在两者之间进行转换。我不喜欢这个,但这是迄今为止我想出的最好的。
private var _options: FulfillmentOptions = []
private var options: UInt {
get {
// get raw value from _options
}
set {
// set raw value to _options
}
}
有没有更优雅的方法来完成这个?我想避免编写不必要的代码。
不是您问题的直接答案,但您可以作为替代方案 反过来工作。定义
typedef NS_OPTIONS(NSInteger, FulfillmentOption) {
FulfillmentOptionPickup = 1 << 0,
FulfillmentOptionShipping = 1 << 1,
FulfillmentOptionUserShipping = 1 << 2,
};
在 Objective-C header 中,这将作为
导入到 Swiftpublic struct FulfillmentOption : OptionSetType {
public init(rawValue: Int)
public static var Pickup: FulfillmentOption { get }
public static var Shipping: FulfillmentOption { get }
public static var UserShipping: FulfillmentOption { get }
}
可以在 "Using Swift with Cocoa and Objective-C" 参考资料中找到更多信息:
- "Interaction with C APIs":
Swift also imports C-style enumerations marked with the
NS_OPTIONS
macro as a Swift option set. Option sets behave similarly to imported enumerations by truncating their prefixes to option value names.
- "Swift and Objective-C in the Same Project":
You’ll have access to anything within a class or protocol that’s marked with the
@objc
attribute as long as it’s compatible with Objective-C. This excludes Swift-only features such as those listed here:
- ...
- Structures defined in Swift
- ...
Objective-C 看不到 struct
,但幸运的是,您可以使用 @objc class
来实现 OptionSet
。
请注意,实现 -hash
和 -isEqual:
非常重要,因为 OptionSet
继承的许多 SetAlgebra
默认实现都依赖它们才能工作。如果你不实现它们,print("\(Ability(.canRead) == Ability(.canRead))")
打印 false
.
@objc
public final class Ability: NSObject, OptionSet {
// Don't use
//
// public static let canRead = Ability(rawValue: 1 << 0)
// public static let canWrite = Ability(rawValue: 1 << 1)
//
// because `Ability` is a `class`, not a `struct`,
// so `let` doesn't enforce immutability, and thus
//
// Ability.canRead.formUnion(Ability.canWrite)
//
// would break `Ability.canRead` for everyone!
public static func canRead(): Ability {
return Ability(rawValue: 1 << 0)
}
public static func canWrite(): Ability {
return Ability(rawValue: 1 << 1)
}
public var rawValue: Int
public typealias RawValue = Int
public override convenience init() {
self.init(rawValue: 0)
}
public init(rawValue: Int) {
self.rawValue = rawValue
super.init()
}
/// Must expose this to Objective-C manually because
/// OptionSet.init(_: Sequence) isn't visible to Objective-C
/// Because Sequence isn't an Objective-C-visible type
@objc
@available(swift, obsoleted: 1.0)
public convenience init(abilitiesToUnion: [Ability]) {
self.init(abilitiesToUnion)
}
// MARK: NSObject
// Note that it is very important to implement -hash and
// -isEqual: because lots of the `SetAlgebra`
// default implementations that `OptionSet` inherits
// rely on them to work. If you don't implement them,
// print("\(Ability(.canRead) == Ability(.canRead))")
// prints `false`
public override var hash: Int {
return rawValue
}
public override func isEqual(_ object: Any?) -> Bool {
guard let that = object as? Ability else {
return false
}
return rawValue == that.rawValue
}
// MARK: OptionSet
public func formUnion(_ other: Ability) {
rawValue = rawValue | other.rawValue
}
public func formIntersection(_ other: Ability) {
rawValue = rawValue & other.rawValue
}
public func formSymmetricDifference(_ other: Ability) {
rawValue = rawValue ^ other.rawValue
}
}
然后,我可以从 Objective-C:
实例化它Ability *emptyAbility = [Ability new];
Ability *readOnlyAbility = [[Ability alloc] initWithAbilitiesToUnion:@[Ability.canRead]];
Ability *readWriteAbility = [[Ability alloc] initWithAbilitiesToUnion:@[Ability.canRead, Ability.canWrite]];