简体   繁体   中英

Swift property observer issue

I've an issue with my property observer and would like to know a little bit more about the Swift behaviour.

I've the following architecture which use callbacks:

A higher lever class

class MyFirstClass : NSScrollView {

var colorDidUpdate: (() -> ())?

var color = NSColor.black {
  didSet { 
    colorDidUpdate?()
  }
 }


override init(frame frameRect: NSRect) {
    super.init(frame: frameRect)
    /* Some init */
    var mySecondClass = MySecondClass(frame: frame)
    colorDidUpdate = mySecondClass.enclosingViewDidUpdateColor
    mySecondClass.color = color
    documentView = mySecondClass
    /* Some other init */
  }

}

Then a second class that act like a link between the first and third class

class MySecondClass {
  var viewColorDidUpdate: (() -> ())?
  var color: NSColor?

  var myThirdClass = MyThirdClass(frame: frame)

  init(frame frameRect: NSRect) {
    /* Some init */
    viewColorDidUpdate = myThirdClass.updateColor
    myThirdClass.color = color
    /* Some other init */
  }

  func enclosingViewDidUpdateColor() {
    viewStyleDidUpdate?()
  }
}

And finally a third class where the draw is done.

class MyThirdClass {
  var color: NSColor?

  func draw(_ dirtyRect: NSRect) {
    guard let color = color else { return }
    // The color is black instead of green.
  }

  /* proerties and functions... */
  func updateColor() {
    functionThatWillTriggerTheDrawFunction() // Will trigger draw function
  }
}

If I set a new color to MyClass property like

var myClass = MyClass()
myClass.color = .green

The printed color is not "green" but it still black...

I thought that when we were in the didSet scope the variable was already set, am I wrong?

Should I use an other pattern?

I thought that when we were in the didSet scope the variable was already set, am I wrong?

No that's true, but something else is happening I guess (although the relevant code doesn't seem to be included)

A closure as the name suggests closes over variables it uses at the time of its definition. So you are most likely defining/using the closure at the time where your color still is black. You can not use a closure to give you the current value of a variable that is captured but you could pass the value into the closure as a parameter. I hope this makes sense.

If you provide a more complete code sample I can get a better idea about what the problem in your case might be.

Update (after you provided more code):

You are only ever setting the colors of the second and third classes on their init methods. You are never updating their color properties when you update the first classes color property.

I am sure the simplification of your presented code is partly to blame, but there are a few things you might want to consider to make things easier to follow:

  • Try not saving the color in each and every component separately but rather pass it along as parameters of your functions/methods. This makes it easier to see, what is happening. For example, you could call your change handler colorDidUpdate(to color: NSColor) and pass in the new value. This way, at least your second class doesn't need to store the color but rather pass it along into updateColor(_ color: NSColor) which could set the third class' color property and trigger a redraw.

  • In general I think it is beneficial to pass in any change to a change handler and not read it from a global state. Try not to store everything but pass along the information you need without storing it in between (if possible). This makes it easier to see where and how the data and information flows in your app and might indicate problems with the architecture.

It is a bit hard suggesting to architect the entire thing differently since the code is just fragments here, but it looks like you could improve and simplify a bit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM