Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem with the preview on Apple developers SwiftUI tutorial - Framework Integration Interfacing with UIKit

I’m fairly new to Swift and Xcode. I’ve been following along with Apple’s SwiftUI tutorials and haven’t had much problem, until I got to here: Interfacing with UIKit (https://developer.apple.com/tutorials/swiftui/interfacing-with-uikit)

When I get to step 5, the build is successful but there is no preview. The error I receive is:

“ RemoteHumanReadableError: Failed to update preview.

The preview process appears to have crashed.

Error encountered when sending 'render' message to agent.

==================================

| RemoteHumanReadableError: The operation couldn’t be completed. (BSServiceConnectionErrorDomain error 3.) |
| BSServiceConnectionErrorDomain (3): | ==BSErrorCodeDescription: OperationFailed”

Any help on what I’m doing wrong, and why it’s wrong would be great help :)

Edit: code added


import SwiftUI

struct PageView<Page: View>: View {
    var viewControllers: [UIHostingController<Page>]

    init(_ views: [Page]) {
        self.viewControllers = views.map { UIHostingController(rootView: $0) }
    }

    var body: some View {
        PageViewController(controllers: viewControllers)
    }
}

struct PageView_Previews: PreviewProvider {
    static var previews: some View {
        PageView(features.map { FeatureCard(landmark: $0) })
            .aspectRatio(3/2, contentMode: .fit)
    }
}

like image 595
Joshtralia Avatar asked Sep 24 '20 12:09

Joshtralia


People also ask

Can you use SwiftUI and UIKit together?

SwiftUI works seamlessly with the existing UI frameworks on all Apple platforms. For example, you can place UIKit views and view controllers inside SwiftUI views, and vice versa.

What is the difference between SwiftUI and UIKit?

Compatibility with different iOS versions SwiftUI is limited and works better with iOS 14 and iOS 15. On the contrary, UIKit enables you to support even iOS version 9.0. This makes UIKit more flexible. It surely wins against SwiftUI when it comes to backward compatibility.

Is SwiftUI ready for production?

SwiftUI is more than ready for simple applications, but at the time of this writing (iOS 15, beta 4), I don't think SwiftUI is production-ready yet for complex applications, mainly due to the issues with ScrollViews and the heavy reliance on UIViewRepresentable .

Can I place UIKit views inside SwiftUI views?

For example, you can place UIKit views and view controllers inside SwiftUI views, and vice versa. This tutorial shows you how to convert the featured landmark from the home screen to wrap instances of UIPageViewController and UIPageControl.

What can you do with SwiftUI preview?

Learn how to use SwiftUI to compose rich views out of simple ones, set up data flow, and build the navigation while watching it unfold in Xcode’s preview. Discover how to draw shapes and paths to create a badge that you’ll animate, while also creating seamless transitions between views.

How to use SwiftUI in Xcode 11?

Let’s begin by starting a new Xcode project in Xcode 11. Remember to check “Use SwiftUI” in the project creation window. 2. Xcode Tour Now, let’s take a look at the ContentView.swift file.

How do I create a project in Xcode using UIKit?

If you’re used to using UIKit, this is similar to the ViewController.swift file which is created by default when you start a new Xcode project. Once your project is created, you should see a screen that looks like this: Take note of the editor pane, preview pane, object library, and live preview button in the preview pane.


2 Answers

Using this page as inspiration, I was able to make this work in XCode 12 using the following code:

import SwiftUI

struct PageView<Page: View>: View {
    var viewControllers: [UIHostingController<Page>]

    init(viewControllers: [UIHostingController<Page>]) {
        self.viewControllers = viewControllers
    }
    
    init(_ views: [Page]) {
        self.viewControllers = views.map { UIHostingController(rootView: $0) }
    }
    
    var body: some View {
        PageViewController(controllers: viewControllers)
    }
}

struct PageView_Previews: PreviewProvider {
    // the static in the following line is critical to it working...
    static let controllers = features.map { UIHostingController(rootView: FeatureCard(landmark: $0)) }
    
    static var previews: some View {
        PageView(viewControllers: controllers).aspectRatio(3/2, contentMode: .fit)
    }
}

It appears that you need to pass a fully constructed UIHostingController array from within Preview, so I created an extra init overload to be used for preview mode. The [Page]-based init is to keep the code compatible with the downstream steps in the tutorial. As to why it works with the static let, sadly, I have no clue (i.e. if you put the let statement inside of previews as a non-static let, it will fail to generate the preview.

like image 60
Jason Armstrong Avatar answered Oct 12 '22 14:10

Jason Armstrong


this worked for me. added the @State & $currentPage to make the Preview along with the swipe to change images in the Active Preview finally work!

you need to finish Section 3 of Interfacing With UIKit before it works because you have to add the necessary lines in the PageViewController.swift. keep the Preview pinned to see it finally work once you assign the coordinator as the delegate in Section 3 - step 6.


//  PageView.swift

import SwiftUI

struct PageView<Page: View>: View {
    @State var currentPage = 1
    
    var viewControllers: [UIHostingController<Page>]

    init(viewControllers: [UIHostingController<Page>]) {
        self.viewControllers = viewControllers
    }
    
    init(_ views: [Page]) {
        self.viewControllers = views.map { UIHostingController(rootView: $0) }
    }
    
    var body: some View {
        VStack {
            PageViewController(controllers: viewControllers, currentPage: $currentPage)
            Text("Current Page: \(currentPage)")
        }
    }
}

 struct PageView_Previews: PreviewProvider {
     static let controllers = features.map { UIHostingController(rootView: FeatureCard(landmark: $0)) }
     
     static var previews: some View {
         PageView(viewControllers: controllers).aspectRatio(3/2, contentMode: .fit)
     }
 }


like image 40
DancesWithWoofs Avatar answered Oct 12 '22 13:10

DancesWithWoofs