Journal

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

2020-07-16 Error in SwiftUI preview

Today, one SwiftUI Preview would not show anything. The Diagnostics button showed the following error:

    GenericHumanReadableError: unexpected error occurred
    noPreviewInfos(arch: "x86_64", sdkRoot: "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.6.sdk")

After a bit of fiddling, I found out the cause. This project had multiple targets. And the file was not a member of the currently selected target.

Edit 2021-01-15: the above solution was only temporary. Another attempt involved removing all unittests also temporarily "fixed" this problem. At the moment, this seems to be a very rare error and I have not been able to find a definitive cause or solution.

More...