How do you use perform(#selector(setter:)) to set the value of a property using swift 4?

3.2k Views Asked by At

I'm trying to run this code but it's yielding unexpected results.

class Test: NSObject {
    @objc var property: Int = 0
}

var t = Test()

t.perform(#selector(setter: Test.property), with: 100)
print(t.property)

The value being printed is some junk number -5764607523034233277. How can I set the value of a property using the perform method?

2

There are 2 best solutions below

3
rob mayoff On BEST ANSWER

The performSelector:withObject: method requires an object argument, so Swift is converting the primitive 100 to an object reference.

The setProperty: method (which is what #selector(setter: Test.property) evaluates to) takes a primitive NSInteger argument. So it is treating the object reference as an integer.

Because of this mismatch, you cannot invoke setProperty: using performSelector:withObject: in a meaningful way.

You can, however, use setValue:forKey: and a #keyPath instead, because Key-Value Coding knows how to convert objects to primitives:

t.setValue(100, forKey: #keyPath(Test.property))
0
Kamil.S On

You can't use perform(_:with:) to do that since Int is not a NSObject subclass which is necessary for the arg. To specify the type you can workaround it with:

let setterSelector = #selector(setter: Test.property)
let setterIMP = t.method(for: setterSelector)
//Invoking setter
unsafeBitCast(setterIMP,to:(@convention(c)(Any?,Selector,Int)->Void).self)(t, setterSelector,100)

let getterSelector = #selector(getter: Test.property)
let getterIMP = t.method(for: getterSelector)
//Invoking getter
let intValue = unsafeBitCast(getterIMP,to:(@convention(c)(Any?,Selector)->Int).self)(t, getterSelector)

You can find more details and examples in my answer here