如何检查对象是否具有存储属性?

时间:2016-02-14 22:42:44

标签: ios swift reflection

我需要检查一个对象的类是否有一个可用于赋值的成员。我们假设有一个班级:

class MyClass: NSObject {

  var myVar : AnyObject!

  // ...
}

我尝试了这种objC风格,但属性在Swift中是一个不同的野兽,第二行总是返回false:

let myClass: MyClass = MyClass()
let hasClassMember = myClass.respondsToSelector(Selector("setMyVar:"))

if hasClassMember {

  myClass.performSelector("setMyVar:", withObject: "Context" as! AnyObject)
} 

我认为Swift没有像ObjC那样强大的反射,但有没有解决方案?

UPDATE 事实证明我的代码有效,但我已将其简化为演示目的。奇怪的是,一旦我将myVar的类型更改为某个自定义类的实例,respontsToSelector就会停止工作,比方说ClassB。感觉有点神奇...... :)

UPDATE2 最后我发现了问题。我还没有编写完整的代码,认为问题出在其他地方,无论如何,这里是完整的代码。 MyClass变量实际上是一个实现AnotherClassProtocol

的其他AnotherClass的类型
protocol AnotherClassProtocol {
  //…
}

class AnotherClass: AnotherClassProtocol {
  //…
}

class MyClass: NSObject {

  var myVar : AnotherClass!
  // ...
}

这导致myClass.respondsToSelector(Selector(“setMyVar:”))总是返回false。原来问题是因为我在AnotherClass声明中省略了NSObject的扩展。在我修复了它之后,它开始按预期工作:

class AnotherClass: NSObject, AnotherClassProtocol {
  //…
}

我还在学习Swift并且认为不需要NSObject,因为编译器没有抱怨并且无论如何都从NSObject扩展(至少在ObjC中)。好吧,我很高兴我发现了这个讨厌的错误。

4 个答案:

答案 0 :(得分:7)

比检查选择器稍微好一点的方法就是使用协议。

protocol MyClassProtocol {
    var myVar : AnyObject! {get set}
}

class MyClass: NSObject, MyClassProtocol {
     var myVar : AnyObject!
     // ...
}

...

let c = MyClass()

if let conformingMyClass = c as? MyClassProtocol { // returns true
    print("yay")
    conformingMyClass.myVar = "Context"
} else {
    print("nay")
}

通过这种方式,可以更清楚地了解哪些课程有并且没有你的财产,而且你不必与选择者混淆(更多的是Swift-y)。

答案 1 :(得分:5)

import Foundation
class MyClass: NSObject {

    var myVar1 : AnyObject!

    // ...
}

let myClass: MyClass = MyClass()
let hasClassMemberMyVar1 = myClass.respondsToSelector(Selector("setMyVar1:")) // true
let hasClassMemberMyVar2 = myClass.respondsToSelector(Selector("setMyVar2:")) // false

它对我有用......

更新,基于OP备注

import Foundation
class C:NSObject {}
class MyClass: NSObject {
    var myVar1 : C? // Objective-C representable
    var i: Int = 0  // Objective-C representable
    var j: Int? = 10
}

let myClass: MyClass = MyClass()
let hasClassMemberMyVar1 = myClass.respondsToSelector(Selector("setMyVar1:")) // true
let hasClassMemberMyVar2 = myClass.respondsToSelector(Selector("setMyVar2:")) // false
let hasClassMemberI = myClass.respondsToSelector(Selector("setI:")) // true
let hasClassMemberJ = myClass.respondsToSelector(Selector("setJ:")) // false, because Optional<Int> is not representable in Objective-C !!!
print(myClass.i.dynamicType, myClass.j.dynamicType) // Int Optional<Int>

仅限类型属性

import Foundation
class C:NSObject {}
class C1 {}
class MyClass: NSObject {
    var c : C?
    var cO1: C = C()
    var cO2: C!
    var c1: C1 = C1()
    var c2: C1?
    var c3: C1!
}

let myClass: MyClass = MyClass()
let hasClassMemberC = myClass.respondsToSelector(Selector("setC:")) // true
let hasClassMemberCO1 = myClass.respondsToSelector(Selector("setCO1:")) // true
let hasClassMemberCO2 = myClass.respondsToSelector(Selector("setCO2:")) // true
let hasClassMemberC1 = myClass.respondsToSelector(Selector("setC1:")) // false, class C1 is not Objective-C representable ...
let hasClassMemberC2 = myClass.respondsToSelector(Selector("setC2:")) // false, Optional<C1> is not Objective-C representable ...
let hasClassMemberC3 = myClass.respondsToSelector(Selector("setC3:")) // false, ImplicitlyUnwrappedOptional<C1> is not Objective-C representable ...

答案 2 :(得分:3)

Swift 3版Ryan Huubert的回答:

class MyClass: NSObject {

    var myVar : AnyObject!
    // ...
}

let myClass = MyClass()

myClass.responds(to: Selector("myVar")) // returns true
myClass.responds(to: Selector("myVar:")) // returns false

答案 3 :(得分:1)

class MyClass: NSObject {

    var myVar : AnyObject!
    // ...
}

let myClass = MyClass()

myClass.respondsToSelector("myVar") // returns true
myClass.respondsToSelector("myVar:") // returns false