Swift Optional binding behaviour unclear

71 Views Asked by At

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!

2

There are 2 best solutions below

0
lorem ipsum On

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()
        }
    } 
0
AudioBubble On

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 = …