-2

I'm brand new to Swift and unable to wrap my head around a code snippet that uses Optional binding. Here is the code:

struct AWorkingView: View {
    var frameSize: CGSize?
    
    init(frameSize: CGSize? = nil) {
        self.frameSize = frameSize
    }
    
    var body: some View {
        GeometryReader { geometry in
            if let frameSize, let frameRect = getframeRect(geometrySize: geometry.size, frameSize: frameSize){
                ZStack {
                    VStack {
                        }
                }
                .frame(maxWidth: .infinity, maxHeight: .infinity)
            } else {
                
            }
        }
    }

    func getframeRect(geometrySize: CGSize, frameSize: CGSize) -> CGRect {
        CGRect(x: 10, y: 10, width: 10, height: 10)
    }
}

The above throws an error: Initializer for conditional binding must have Optional type, not 'CGRect' for that let frameRect = ... conditional binding.

But works when I do this:


    ...
    var body: some View {
        GeometryReader { geometry in
            if let frameSize {
                let frameRect = getframeRect(geometrySize: geometry.size, frameSize: frameSize)
                ZStack {
                    ...
}

Why is frameRect expected to be CGRect? and not just CGRect in the conditional binding?

Thanks in advance!

borarak
  • 1,130
  • 1
  • 13
  • 24
  • 2
    What do you mean by "Why"? That's just what `if let ...` expects. You *have* to put something of an optional type there. – Sweeper May 27 '23 at 11:59
  • See [this](https://meta.stackoverflow.com/a/323382/5133585) for how to clarify your question. – Sweeper May 27 '23 at 12:04
  • 1
    Why is `frameSize` optional at all? A *working* view without a size seems pretty pointless. – vadian May 27 '23 at 12:26
  • @Sweeper, I guess what you mentioned makes sense. I thought the second `let` in `if let frameSize, let frameRect` doesn't read as `if let frameRect = ...` but as a normal initialisation. Thanks – borarak May 27 '23 at 12:47
  • @borarak `if let frameSize` is just shorthand for `if case let frameSize? = frameSize`. See answer below for how to use non-optionals along with optional binding. –  May 27 '23 at 15:08

2 Answers2

1

if let is incorrectly formatted.

    GeometryReader { geometry in
        if let frameSize = frameSize{ //optional check

            let frameRect = getframeRect(geometrySize: geometry.size, frameSize: frameSize) 
            // Not optional, it will never be nil so it doesn't need the check.
            // It is just a regular assignment.

            ZStack {
                VStack {
                    }
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
        } else {
            EmptyView()
        }
    } 
lorem ipsum
  • 21,175
  • 5
  • 24
  • 48
0

I would recommend against using an unwrapped frameSize constant, because it's not used elsewhere. Only frameRect is needed.

if let frameRect = frameSize.map({ getframeRect(geometrySize: geometry.size, frameSize: $0) }) {

If you feel that you must, and don't like the way that you've already learned worked, you can either use case.

if let frameSize, case let frameRect = …