Weblog entries 2021

Weblog entries 2021

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: () -> _)

2021-10-19 Constrained extension must be declared on the unspecialized generic type

Did you get the following error message in Swift?

    Constrained extension must be declared on the unspecialized generic type 'Optional' with constraints specified by a 'where' clause

I got that one, and I tried to extend an optional string as follows:

    extension Optional<String> {
        func ifEmpty(_ replacementString: String) -> String? {
            (self ?? "").isEmpty ? replacementString : self
        }
    }

The correct syntax is:

    extension Optional where Wrapped == String {
        func ifEmpty(_ replacementString: String) -> String? {
            (self ?? "").isEmpty ? replacementString : self
        }
    }

It's still painful that it must return an optional. That can be avoided by a static function, which isn't as nice of course :)

2021-09-30 CGRect appendInterpolation

In the category of errors that you google but don't get results.

Suppose you have the following state variable in a SwiftUI view:

    @State private var textFieldFrame1 = CGRect()    

And you want to display that somewhere, as follows:

    Text("Frame of textfield 1 = \(textFieldFrame1)")

You'll get the following compiler error:

    No exact matches in call to instance method 'appendInterpolation'

The solution is as follows:

    Text("Frame of textfield 1 = " + String(describing: self.textFieldFrame1))

2021-03-22 Debugging view sizes

Here's a tip if you wish to show the sizes of views in your SwiftUI previews. Add the following struct to your project.

    struct ViewSizePreferenceReader: View {
        private struct ViewSizePreferenceKey: PreferenceKey {
            typealias Value = [CGSize]
            static var defaultValue: [CGSize] = []
            static func reduce(value: inout [CGSize], nextValue: () -> [CGSize]) {
                value.append(contentsOf: nextValue())
            }
        }
        @Binding var sizeString: String
        var body: some View {
            GeometryReader { (geometry: GeometryProxy) in
                Color.clear
                    .preference(key: ViewSizePreferenceKey.self, value: [geometry.size])
            }
            .onPreferenceChange(ViewSizePreferenceKey.self) { preferences in
                if let size = preferences.first {
                    self.sizeString = String(format: "%.1f x %.1f", size.width, size.height)
                }
            }
        }
    }

Then add a @State variable for the string, and use the above view as a background, as follows. The preview below will show how the Dynamic Type setting influences SF Symbol based images.

    struct ContentView: View {
        @State private var sizeString = "0x0"
        var body: some View {
            VStack {
                Image(systemName: "magnifyingglass")
                    .imageScale(.large)
                    .background(ViewSizePreferenceReader(sizeString: self.$sizeString))
                Text("Size of button: \(self.sizeString)")
            }
        }
    }
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            Group {
                ContentView()
                ContentView()
                    .environment(\.sizeCategory,
                                 .accessibilityLarge)
            }
            .previewLayout(.fixed(width: 414, height: 200))
        }
    }

2021-01-22 Error in SwiftUI Previews part deux

Today Xcode refused to show previews for one view, displaying "Cannot preview this file" on top of the previews canvas.

This time it's showing the error "SomeUnitTest.swift must belong to at least one target in the current scheme in order to use previews". I have the feeling that this error is incorrect and masks a problem elsewhere, because unittests most certainly should not belong to any other target than the test target.

I have been able to temporarily fix the problem as follows:

  • Quit Xcode and simulator
  • Delete the ~/Library/Developer/Xcode/DerivedData folder
  • Start Xcode and simulator
  • Remove all unittests from the project (don't move to trash, simply remove references)
  • Compile the project
  • Add the unittests back to the project