Swift:具有相同选择器的类型转换对象

时间:2019-03-07 02:14:21

标签: objective-c swift casting selector

情况

假设我有两个班级:

class Foo: NSObject {
    var specialProperty: String = "hello"
}

class Bar: NSObject {
    var specialProperty: String = "goodbye"
}

现在假设我正在使用一个我知道的集合,其中仅包含FooBar个实例。我知道数组中的每个对象都会响应specialProperty选择器,因此在Objective-C中,我可以像这样进行投射:

for id thing in arrayOfThings
{
    NSLog(@"specialProperty: %@", ((Foo *)thing).specialProperty);
}

如何在Swift中解决这个问题?我无法向FooBar添加通用超类,也不能向它们添加协议。实际上,FooBarNSManagedObject的子类,代表我的应用程序中的模型项。


选择器?

我已经考虑过这种方法:

let collection: [AnyObject] // Assume this contains Foo and Bar instances.
let sel: Selector = #selector(setter: Foo.specialProperty)

for item in collection 
{
    if item.respondsToSelector(sel) 
    {
        instance.perform(sel, with: "new value")
    } 
}

即使我告诉Swift选择器的类型为sel,也会在Bar实例上调用Foo.吗?似乎应该这样,因为Objective-C选择器机制并不关心Object的类是什么。那不是选择器签名的一部分。但是我不确定在Swift-ObjectiveC交互中是否有我忽略的东西。


上下文

我正在从Objective-C迁移此应用。

3 个答案:

答案 0 :(得分:4)

在Objective C和Swift中,正确的方法是使用协议:

protocol Special {
    var specialProperty { get set }
}

class Foo: NSObject, Special {
    var specialProperty: String = "hello"
}

class Bar: NSObject, Special {
    var specialProperty: String = "goodbye"
}

let collection: [Special] = ...

for item in collection {
    item.specialProperty = "new value" 
}

答案 1 :(得分:3)

我认为您也可以考虑采用这种方法

let collection: [AnyObject] // Assume this contains Foo and Bar instances.

for item in collection 
{
    guard let aFoo = item as? Foo else {
    guard let aBar = item as? Bar else { continue } 

    aBar.specialProperty = "New value"

    continue
    } 

    aFoo.specialProperty = "New value"
}

答案 2 :(得分:0)

除了使用协议外,我相信也可以使用可选的强制转换

for item in collection 
{
    if let foo = item  as? Foo
    {
        // only when casting to Foo successfully
        foo.specialProperty
    } 
    if let bar = item  as? Bar
    {
        // only when casting to Bar successfully
        bar.specialProperty
    } 
}