在Objective-C中访问Swift OptionSetType

Bra*_*ker 5 objective-c ios swift

在我的Swift类中,我为履行选项定义了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)
}
Run Code Online (Sandbox Code Playgroud)

然后我创建一个变量来添加/删除和读取选项.这按预期工作.

 var options: FulfillmentOption = []
 options.insert(FulfillmentOption.Pickup)
 options.contains(FulfillmentOption.Pickup)
Run Code Online (Sandbox Code Playgroud)

但是我需要options从我的一个Objective-C类中访问该变量.由于在Objective-C中未定义OptionSetType,因此该变量对于我的任何Objective-C类都不可见.

我将这个暴露给Objective-C的最佳方式是什么?我应该完全停止使用OptionSetType吗?

我已经考虑过创建这样的公共和私有变量来在两者之间进行转换.我不喜欢这个,但这是迄今为止我提出的最好的.

private var _options: FulfillmentOptions = []
private var options: UInt {
  get {
    // get raw value from _options
  }
  set {
    // set raw value to _options
  }
}
Run Code Online (Sandbox Code Playgroud)

是否有更优雅的方式来实现这一目标?我想避免编写不必要的代码.

Mar*_*n R 11

不能直接回答您的问题,但作为替代方案,您可以反过来工作.限定

typedef NS_OPTIONS(NSInteger, FulfillmentOption) {
    FulfillmentOptionPickup = 1 << 0,
    FulfillmentOptionShipping = 1 << 1,
    FulfillmentOptionUserShipping = 1 << 2,
};
Run Code Online (Sandbox Code Playgroud)

在Objective-C标题中,这将被导入Swift as

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 }
}
Run Code Online (Sandbox Code Playgroud)

更多信息可以在"使用Swift with Cocoa和Objective-C"参考中找到:

  • "与C API交互":

Swift还导入标有NS_OPTIONS 宏的C风格枚举 作为Swift选项集.选项集的行为与导入的枚举类似,方法是将其前缀截断为选项值名称.

  • "Swift和Objective-C在同一个项目中":

@objc只要与Objective-C兼容,您就可以访问使用该属性标记的类或协议中的任何内容 .这不包括仅限Swift的功能,例如此处列出的功能:

  • ...
  • Swift中定义的结构
  • ...

  • @Brandon:我添加了一些参考文献. (2认同)

Hea*_*ers 5

Objective-C中无法看到structS,但幸运的是,你可以实现OptionSet@objc class替代。

请注意,实现非常重要-hash-isEqual:因为继承的许多SetAlgebra默认实现都OptionSet依靠它们来工作。如果不实现它们,则print("\(Ability(.canRead) == Ability(.canRead))")打印false

@objc
public final class Ability: NSObject, OptionSet {
    public static let canRead = Ability(rawValue: 1 << 0)
    public static let canWrite = 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
    }  
}
Run Code Online (Sandbox Code Playgroud)

然后,我可以从Objective-C实例化它:

Ability *emptyAbility = [Ability new];
Ability *readOnlyAbility = [[Ability alloc] initWithAbilitiesToUnion:@[Ability.canRead]];
Ability *readWriteAbility = [[Ability alloc] initWithAbilitiesToUnion:@[Ability.canRead, Ability.canWrite]];
Run Code Online (Sandbox Code Playgroud)