NEW: Learn to build the incredible iOS 15 Weather app today! >>

Forced to use var + optional in object property that should be constant; what's the solution?

Forums > Swift

I love Swift. I hate this:

class PixieModel: ObservableObject {
    let radiusObserver: AnyCancellable

    init(_ radiusPublisher: PassthroughSubject<Double, Never>) {
        radiusObserver = radiusPublisher.sink {
            self.setRadius($0)
        }
    }

    func setRadius(_ newRadius: Double) { /* do stuff */ }
}

From Xcode: 'self' captured by a closure before all members were initialized

Yes, I get it. I understand the problem. But now I have to use var and an OPTIONAL 🤦‍♂️ on a property that absolutely should be constant, absolutely IS constant, and that absolutely has no good reason to be an optional. I've always felt that it's best to write your code such that your reader can understand your intentions clearly. It sucks enormously to have to use var and an optional here, as artifacts of the language, not because a var or an optional was required by the app design. I've heard of people using a kind of "lazy let". Are there other solutions?

   

Would making it private(set) var work for you? That way you could only set it from within the PixieModel class.

Otherwise, I'm wondering why you are passing in a PassthroughSubject and sinking its value in PixieModel. Usually subjects are stored as Cancellables where they are defined. I'm thinking your subject should really be a part of PixieModel so that everything is handled internally to the class. Maybe you need to rethink your architecture?

1      

Whoa. I am still struggling to understand the problem, let alone be irritated!

🤷🏽

   

Maybe you need to rethink your architecture?

This! Yes, whenever I find myself fighting the language, I suspect that I have a design issue. But you've illuminated a number of different things that I'd love to get your advice about, while my main original question was just using this as an example of something I run into all the time: having to use var foo: FooModel? rather than let foo: FooModel because of a reference to self in the initializer.

But since you asked about the other, I'll pester you for advice! I'm trying to figure out how to bridge between SwiftUI and SpriteKit. My best guess so far looks like this. I know nothing, I'm all ears.

(Some of the names below aren't right, I'm pasting this stuff from versions from earlier this morning, but the code I'm working on does run, so if it matters I can fix it and show you a running thing.)

// This is the "real" model, the source of truth
class TumblerModel: ObservableObject {
    var radius = TumblerRadius(0.5)
}

// This is the thing that controls the sprite, which is
// kind of a view of the TumblerModel, but also kind of a model
// itself? I'm still not super-strong with the whole view/model thing
class PixieModel: ObservableObject {
    var radiusObserver: AnyCancellable!
    let sprite: SKSpriteNode

    init(radius: TumblerRadius) {
    //...
        radiusObserver = radius.publisher.sink(receiveValue: setRadius)
    }

    func setRadius(_ newRadius: Double) {
        sprite.size = CGSize(width: newRadius * 2, height: newRadius * 2)
    }
}

// This is my best guess about how to get the truth out to the sprites. I can
// use the "dollar" to connect it to a slider, for testing

// 🙏 https://www.swiftbysundell.com/basics/combine/
class TumblerRadius: ObservableObject {
    var publisher: AnyPublisher<Double, Never> {
        subject.eraseToAnyPublisher()
    }

    var dollar: Binding<Double> {
        Binding(
            get: { self.radius }, set: { self.radius = $0 }
        )
    }

    var radius: Double {
        didSet { subject.send(radius) }
    }

    init(_ radius: Double) { self.radius = radius }

    private let subject = PassthroughSubject<Double, Never>()
}

   

Hacking with Swift is sponsored by Sentry

SPONSORED With Sentry’s error and performance monitoring for iOS, you see mobile vitals that actually matter, can solve any latency issues quickly, and learn how each release is performing over time.

Learn More

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.