3

Swift 2, I have a class inherits from objc's UIView and it has 'on' variable, and related methods 'setOn:animated' and 'setOn:' like below:

public class AView: UIView {
var on: Bool = false

public func setOn(on: Bool, animated: Bool) {
    self.on = on
    // do something more about animating
}

public func setOn(on: Bool) {
    setOn(on, animated: false)
}

And I got an error message: method 'setOn' with Objective-C selector 'setOn:' conflicts with setter for 'on' with the same Objective-C selector

I think willSet or didSet is not a solution because setOn:animated: is called twice even if I add some guard conditions:

var on: Bool = false {
    willSet {
        if self.on != newValue {
            setOn(self.on, animated: false)
        }
    }
}
....
....
let a = AView()
a.setOn(true, animated: true) // setOn:animated: is called twice

Is there a solution without changing a variable name and methods name?


Workaround: My solution is add extra internal variable and expose it with computed property. I don't like adding extra variable and definitely there will be a better solution.

private var isOn: Bool = false
var on: Bool {
    set(newOn) {
        setOn(newOn, animated: false)
    }
    get {
        return isOn
    }
}

public func setOn(on: Bool, animated: Bool) {
    self.isOn = on
    // do something ...
}
ccoroom
  • 699
  • 9
  • 23
  • Make it `setOn(isOn on: Bool) ...` instead? – Will Richardson Jan 10 '16 at 08:28
  • @JavaNut13 It works. But, need extra named parameter. I want to keep both a vriable and method name. I can avoid this issue by adding extra variable but I want to know is there a better solution. – ccoroom Jan 10 '16 at 08:35

2 Answers2

5

Similarly as in Compiler error: Method with Objective-C selector conflicts with previous declaration with the same Objective-C selector, you can also hide properties from the Objective-C runtime with @nonobjc:

public class AView: UIView {
    @nonobjc var on: Bool = false

    public func setOn(on: Bool, animated: Bool) {
        self.on = on
        // do something more about animating
    }

    public func setOn(on: Bool) {
        setOn(on, animated: false)
    }
}

which prevents a conflicting Objective-C setter from being auto-generated.

Community
  • 1
  • 1
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Thank you for your answer. Then do I have to provide `isOn`(getter for on) to access this property in Objective C? – ccoroom Jan 10 '16 at 09:34
  • @ccoroom: If you want to access the property from Objective-C as well then your solution with a `private var isOn` is probably the better one. – Martin R Jan 10 '16 at 10:10
0

Instead of willSet you need to use didSet

var on: Bool = false
{
    didSet
   {
        if self.on != oldValue
        {
            setOn(self.on, animated: false)
        }
    }
}
Midhun MP
  • 103,496
  • 31
  • 153
  • 200
  • 'didSet' has no difference. setOn:animated: called twice. – ccoroom Jan 10 '16 at 08:38
  • @ccoroom: Check the if condition I'm using, did you tried the same code ? Is the same issue happening ? – Midhun MP Jan 10 '16 at 08:45
  • Yes, I did. Because I called `a.setOn(true, animated: true)` and `self.on = on` is inside `setOn:animated:`. the oldValue is false, so calls `setOn:animated:` once more. – ccoroom Jan 10 '16 at 08:49