Michael Berk
Michael Berk

Reputation: 435

SwiftUI preview crashes when extending View

I have a project that needs to support an old version of iOS and I'm trying to use SwiftUI for a view that will only appear when the user is on iOS 13 or later. The SwiftUI Preview in Xcode works just fine, but when I extend a SwiftUI struct (such as View), the project will compile and run on a device, but the Preview Canvas crashes, stating that it Failed to build myView.swift. When I click on the "diagnostics" button, it tells me that 'View' is only available in iOS 13.0 or newer and add @available attribute to enclosing extension. However, the extension in question already has @available(iOS 13.0, *) before it. For example:

@available(iOS 13.0, *)
extension View {
    func myFunc() {

    }
}

In an effort to find the root of this problem, I noticed that the preview won't crash if it's completely empty. Only once I add a function or static property to it will the canvas crash. I have also tried adding the @available line before each function in the extension, rebooting my computer, and deleting the DerivedData folder, but it doesn't seem to have made a difference.

Upvotes: 2

Views: 1445

Answers (2)

Jeremy Pearson
Jeremy Pearson

Reputation: 716

Discussion

The following code example works well for me. Please note the @available(iOS 13.0, *) declaration attributes for not only the View extension, but also for:

  1. The ContentView struct, which conforms to the View protocol,

and

  1. The ContentView_Previews struct, which conforms to the PreviewProvider protocol.

FYI: I set my Xcode Project's deployment target to iOS 12.4 for my test.

Code Example

import SwiftUI

@available(iOS 13.0, *)
extension View {
    func overlayText<Content>(_ content: Content) -> some View where Content : StringProtocol {
        overlay(Text(content))
    }
}

@available(iOS 13.0, *)
struct ContentView: View {
    static private var initialGreeting = "Hello World!"
    static private var greetings: [String] {
        [
            initialGreeting,
            "Hey Everyone!",
            "Hi Everybody!",
            "Hello Friends!"
            
        ]
    }
    @State private var greeting = initialGreeting
    
    var body: some View {
        Button(action: { [greeting] in
            while self.greeting == greeting {
                self.greeting = Self.greetings.randomElement()!
            }
        }) {
            Color.green
                .overlayText(greeting)
                .cornerRadius(30)
                .padding(5)
        }
        .background(Color.black)
        .frame(height: 50)
        .foregroundColor(.white)
        .font(.system(size: 28, weight: .bold))
        .cornerRadius(30)
        .padding()
    }
}

@available(iOS 13.0, *)
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Upvotes: 0

Muhand Jumah
Muhand Jumah

Reputation: 1958

You don't need @available(iOS 13.0, *) your app won't run on any device below version 13.0 so basically the error is stating this is redundant. Removing it should fix your issue.

However if you are doing SwiftUI weak linking and this issue is there then it's a known bug with xCode. If no weak linking then please remove @available(iOS 13.0, *)

EDIT: it seems like you have weak linking.

  1. Make sure SwiftUI.framework is set to optional in Build Phases -> Link Binary With Libraries

  2. Make sure your @available(iOS 13.0, *) is on top of your body not on top of your extension

example:

struct TestView2: View {
    @available(iOS 13.0, *)
    var body: some View {
        Text("test")
    }
}

extension TestView2 {
    func abc() {

    }
}

struct TestView2_Previews: PreviewProvider {
    @available(iOS 13.0, *)
    static var previews: some View {
        TestView2()
    }
}

Upvotes: 2

Related Questions