David Findlay
David Findlay

Reputation: 1356

Subscribing to a property

I have a singleton service class which maintains a value of heading it gets from the compass. I have a UIView which draws some custom graphics based on this. I'm trying to do something like an Observable in javascript, where my code gets executed when there's a change in the value.

final class LocationService: NSObject {

static let shared = LocationService()

public var heading:Int

public func getHeading() -> Int {

    return self.heading

}

Then in my UIView subclass:

var ls:LocationService = LocationService.shared

var heading: Int = ls.getHeading() {
    didSet {
        setNeedsDisplay()
    }
}

I tried also just directly accessing the property via ls.heading but this doesn't get accepted either. It's telling me I cannot use the instance member within the property initialiser. What's a proper swift method of doing this?

Edit:

I've been working with Christian's answer below and some other documentation and now got to here where it all compiles nicely, but doesn't actually work. Here's my delegator and protocol:

final class LocationService: NSObject {

    static let shared = LocationService()

    weak var delegate: CompassView?

    var heading:Int

    func headingUpdate(request:HeadingRequest, updateHeading:CLHeading) {

        print ("New heading found: \(updateHeading)")

        self.heading = Int(updateHeading.magneticHeading)
        self.delegate?.setHeading(newHeading: Int(updateHeading.magneticHeading))

    }

    public func getHeading() -> Int {

        return self.heading

    }

}

protocol LSDelegate: class {

    func setHeading(newHeading:Int)

}

Then in the delegate:

class CompassView: UIView, LSDelegate {

    func setHeading(newHeading:Int) {
        self.heading = newHeading

        print("heading updated in compass view to \(self.heading)")

        setNeedsDisplay()
    }

}

So I get the print message that the heading has been updated in the headingUpdate function. The print message in the setHeading function in the delegate CompassView never gets displayed.

Upvotes: 1

Views: 76

Answers (1)

Christian Abella
Christian Abella

Reputation: 5797

You can use the delegation pattern and have that class that wants to consume your events implement the functions in your protocol.

protocol MyDelegate {
  func setNeedsDisplay()
}

class LocationService: NSObject {
  var myDelegate : MyDelegate?

  var heading: Int = ls.getHeading() {
    didSet {
        myDelegate?.setNeedsDisplay()
    }
  } 

  ...
  func assignDelegate() {
    self.myDelegate = MyConsumer()
  }
}

class MyConsumer : MyDelegate {
  func setNeedsDisplay()
  {
  }
}

Upvotes: 2

Related Questions