假设我有两个班级:
class Foo: NSObject {
var specialProperty: String = "hello"
}
class Bar: NSObject {
var specialProperty: String = "goodbye"
}
现在假设我正在使用一个我知道的集合,其中仅包含Foo
和Bar
个实例。我知道数组中的每个对象都会响应specialProperty
选择器,因此在Objective-C中,我可以像这样进行投射:
for id thing in arrayOfThings
{
NSLog(@"specialProperty: %@", ((Foo *)thing).specialProperty);
}
如何在Swift中解决这个问题?我无法向Foo
和Bar
添加通用超类,也不能向它们添加协议。实际上,Foo
和Bar
是NSManagedObject
的子类,代表我的应用程序中的模型项。
我已经考虑过这种方法:
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迁移此应用。
答案 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
}
}