Contents

Updating views automatically with observation tracking in AppKit

Use Swift Observation and automatic tracking to update your views in response to model data updates.

Overview

Swift Observation provides the Observable macro to mark your models for automatic change tracking. When you combine Observable models with AppKit, the system automatically watches for property changes and updates your views. You don’t need to manually invalidate anything — AppKit handles it for you.

AppKit provides methods in several objects where automatic observation tracking happens. In a view subclass, updateConstraints(), layout(), and draw(_:) are examples of methods that automatically track any Observable properties you read, and AppKit updates your views when those properties change.

Update view properties automatically

The viewWillLayout() method automatically tracks Observable properties and updates views when they change. For example, to show a message list with a status label that displays unread message information, start by creating an Observable model with the properties your view needs:

@Observable
class MessageModel {
    var showStatus: Bool
    var statusText: String
}

Then, use these properties in your view controller’s viewWillLayout() method:

override func viewWillLayout() {
    super.viewWillLayout()
    statusLabel.alphaValue = model.showStatus ? 1.0 : 0.0
    statusLabel.stringValue = model.statusText
}

When the view first appears, AppKit runs viewWillLayout() and tracks that you read showStatus and statusText. If either property changes later, AppKit automatically runs viewWillLayout() again to update the label.

You can also automatically track changes in a custom view using layout().

Draw views automatically

AppKit automatically tracks any Observable properties you read inside your draw(_:) override. When those properties change, AppKit invalidates and redraws the view.

This automatic tracking also covers any methods that draw(_:) calls. This means that if you override drawing methods in a cell subclass, such as drawKnob(_:) and drawBar(inside:flipped:), AppKit also tracks those overrides.

For example, to draw a custom slider cell that responds to model changes, start by creating an Observable model with the visual properties your cell needs:

@Observable
class SliderAppearance {
    var knobColor: NSColor
    var trackColor: NSColor
}

Then, override the drawing methods in your NSSliderCell subclass and read from the model inside each override:

class CustomSliderCell: NSSliderCell {
    var appearance: SliderAppearance

    override func drawKnob(_ knobRect: NSRect) {
        appearance.knobColor.setFill()
        NSBezierPath(ovalIn: knobRect).fill()
    }

    override func drawBar(inside rect: NSRect, flipped: Bool) {
        appearance.trackColor.setFill()
        NSBezierPath(roundedRect: rect, xRadius: 2, yRadius: 2).fill()
    }
}

When drawKnob(_:) and drawBar(inside:flipped:) run, AppKit tracks that they read knobColor and trackColor. If either property changes later, AppKit automatically redraws the slider.

See Also

Related Documentation

Observing data in views