Search code examples
swiftuicombine

Is this delegate pattern still valid in SwiftUI?


I have been developing apps using Swift for a couple of years now. I always used Cocoa but recently decided to finally port them over to SwiftUI. I fell in love with SwiftUI pretty quickly, but whenever I develop using SwiftUI, I also ask myself the same question - is this old code still valid when using SwiftUI or this my delegate pattern no longer best practice when using it in a MVVM based app?

I am now porting my apps to SwiftUI that use a controller that hosts a timer. The timer will fire once a second and updates its model.

I wrote a small example, so let's consider this code:

// Controller that hosts the timer.
protocol ControllerDelegate : AnyObject {
    func controller(didRefresh value: Double)
}

class Controller {
    private var timer: Timer?

    weak var delegate: ControllerDelegate?

    @Published var value: Double = 0.0

    init() {
        self.timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.refresh), userInfo: nil, repeats: true)
    }

    @objc private func refresh() {
        // Do some stuff.
        self.delegate?.controller(didRefresh: 10.0) // Pass the result of whatever we just did to the ViewModel. Values are just an example, this could be anything.
    }
}

I have a Main View Model that could look like this:

// View Model
class ViewModel : ObservableObject {
    private var controller = Controller()

    @Published var value: Double = 0.0

    init() {
        self.controller.delegate = self
    }
}

extension Controller : ControllerDelegate {
    func controller(didRefresh value: Double) {
        self.value = value
    }
}

The View Model has an instance of the controller and acts as a delegate. It also has a Published property that will be bound to views, like this:

// View
struct ExampleView : View {
    @ObservedObject var viewModel: ViewModel

    var body: some View {
        Text(self.viewModel.value.description)
    }
}

While this works quite well - is this really the way to go? Is this what Combine is for, i.e. could Combine replace the delegate pattern? What would this code look like when using Combine? Or does Combine serve another purpose?

Regards


Solution

  • There are no delegates or view model objects in SwiftUI the View struct already encapsulates view data that SwiftUI uses to init/deinit/update UIView objects, i.e. the actual V layer, automatically for you, so MVVM is irrelevant.

    For a View struct that recomputes via a timer try TimelineView.

    TimelineView A view that updates according to a schedule that you provide.

    Overview A timeline view acts as a container with no appearance of its own. Instead, it redraws the content it contains at scheduled points in time