Swift: типизация объектов, имеющих идентичные селекторы - PullRequest
0 голосов
/ 07 марта 2019

Ситуация

Предположим, у меня есть два класса:

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);
}

Как я могу подойти к этомув Свифте?Я не могу добавить общий суперкласс к 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")
    } 
}

Будет ли работать sel в случаях Bar, даже если я сказал Swift, что тип селектора был Foo.?Кажется, что так и должно быть, потому что механизму селектора Objective-C не важно, что это за класс Object;это не часть подписи селектора.Но я не уверен, что во взаимодействии Swift-ObjectiveC есть что-то, что я пропускаю.


Context

Я переношу это приложение из Objective-C.

Ответы [ 3 ]

4 голосов
/ 07 марта 2019

Правильный подход к этому, как в Цели 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" 
}
3 голосов
/ 07 марта 2019

Я думаю, вы также можете рассмотреть этот подход

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"
}
0 голосов
/ 07 марта 2019

Помимо использования протокола, я полагаю, что это также может быть сделано с использованием опционального приведения

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
    } 
}
...