Journal

2022-03-03 Xcode Dependencies could not be resolved

Today, Xcode gave me the following error:

    Dependencies could not be resolved because root depends on 'customerkit' 13.0.0..<14.0.0 and root depends on 'customerkit' 11.0.0..<12.0.0.

The project had built correctly, then I wanted to edit code in a package so I added it as a local package.

The error was confusing to me, because it specifies that root (which means the current project, I assume) depends on both version 11.x and 13.x which is obviously not the case. So what this error message actually means, is: you added a local package, and both the main project and your local package rely on the same package (customerkit in this case), but they require different versions.

The fact that the error twice mentions "root depends on xxx", is thus wrong. If you get it, select your project in the left navigation, select the project again in the middle pane, select the Package Dependencies and look up the version of the dependency. In my case, that was CustomerKit, version "11.0.1 - Next Major". Now for the other packages, check their own dependencies and make sure these are equal.

2021-12-16 Switch with multiple cases with associated values

Lots of people know about switch cases with associated values, for example as follows:

    enum Emoji {
        case lol(String)
        case ohnoes(String)
        case nothing
    }

Some code that uses the above enum:

    let testcases: [Emoji] = [
        .lol("🙂"),
        .ohnoes("😒"),
        .nothing
    ]
    for testcase in testcases {
        switch testcase {
        case .lol(let emoji):
            print("Happy emoji: " + emoji)
        case .ohnoes(let emoji):
            print("Sad emoji: " + emoji)
        case .nothing:
            print("No emoji")
        }
    }

If however, you have common code that must run for both happy and sad emoji, it's possible to combine them into one case. However inside that case, you can still test for one specific case. The example below shows how you can print common code for both happy and sad emoji, but still detect happy emoji:

    for testcase in testcases {
        switch testcase {
        case .lol(let emoji), .ohnoes(let emoji):
            if case .lol = testcase {
                print("Happy emoji detected: \(emoji)")
            }
            print("This is code that runs on any emoji")
        case .nothing:
            print("No emoji")
        }
    }

2021-12-02 SwiftUI NavigationLink Extraneous argument label isActive in call

Today, in Xcode 13.1, I got the following error:

    Extraneous argument label 'isActive:' in call

Accompanied by:

    Type '() -> EmptyView' cannot conform to 'StringProtocol'

This can be easily reproduced with the following code:

    struct ContentView: View {
        @State private var navigate = false
        var body: some View {
            NavigationLink(isActive: self.$navigate,
                           destination: Text("Hello, world!")) {
                EmptyView()
            }
        }
    }

Can you spot the problem above? I couldn't.

An alternative is when you try and specify the label parameter:

    struct ContentView: View {
        @State private var navigate = false
        var body: some View {
            NavigationLink(isActive: self.$navigate,
                           destination: Text("Hello, world!"),
                           label: {
                EmptyView()
            })
        }
    }

Then your errors become somewhat more clear:

    Generic parameter 'Destination' could not be inferred
    Cannot convert value of type 'Text' to expected argument type '() -> Destination'

Namely: the expected argument type to the destination parameter is a closure. As follows:

    destination: { Text("Hello, world!") }

2021-10-20 Generic parameter Destination could not be inferred

Xcode 13.0. If you're banging out SwiftUI code, and you got the following error message:

    Generic parameter 'Destination' could not be inferred

and it'll follow up with the following error as well (if you tried to navigate to a Text view):

    Cannot convert value of type 'Text' to expected argument type '() -> Destination'

then you probably tried to create a NavigationLink and let auto-complete add the following code:

    NavigationLink(tag: Hashable, selection: Binding<Hashable?>, destination: () -> _, label: () -> _)

The solution is to not use the auto-complete version of NavigationLink, but instead use a different sequence of parameters:

    NavigationLink(destination: () -> _, tag: Hashable, selection: Binding<Hashable?>, label: () -> _)

More...