Open sunshinejr opened 5 years ago
Hey @fifty8. It's tricky when you use separate files for the preview. I have two editors, both having the Editor + Canvas setting. Then, I open one file that is the proper controller file and one with the extension. On the side with the extension I can see a canvas + editor split in half and then I can make the canvas up to the top so you don't even see the editor anymore!
If you don't see it the same way, then yeah it's probably a bug.
It does require OS X Beta installed just in case for those who are trying on the latest released OS X. Otherwise, the Canvas view just won't show up.
So I wanted to play with this and I got this weird error, could you help me ?
Protocol 'View' requirement '_makeView(view:inputs:)' cannot be satisfied by a non-final class ('ViewController') because it uses 'Self' in a non-parameter, non-result type position
I got this error on every line of the extension...
This is the code :
import UIKit
import SwiftUI
public class ViewController: UIViewController {
override public func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.red
}
}
extension ViewController: UIViewControllerRepresentable {
public typealias UIViewControllerType = ViewController
public func makeUIViewController(context: UIViewControllerRepresentableContext<UIViewControllerType>) -> ViewController.UIViewControllerType {
return ViewController()
}
public func updateUIViewController(_ uiViewController: ViewController, context: UIViewControllerRepresentableContext<UIViewControllerType>) {
//
}
}
What am I doing wrong ?
I could just use some kind of wrapper struct that'd look like :
struct ViewControllerWrapper: UIViewControllerRepresentable {
typealias UIViewControllerType = ViewController
func makeUIViewController(context: UIViewControllerRepresentableContext<ViewControllerWrapper>) -> ViewControllerWrapper.UIViewControllerType {
return ViewController()
}
func updateUIViewController(_ uiViewController: ViewControllerWrapper.UIViewControllerType, context: UIViewControllerRepresentableContext<ViewControllerWrapper>) {
//
}
}
But I wanted to try your approach of making the actual ViewController UIViewControllerRepresentable. But I can't make it work like you do.
@Que20 As a temporary solution, you can make the VC class final
Thanks for your answer. What if I want to initialize my viewController with parameters, say a string or a URL ? I cannot just extend my (now final) UIViewController class, I need to go for that kind of wrapper, right ?
@Que20 You should be fine if you just want to add a custom init to a final class like in the code example below:
final class TestVC: UIViewController {
let number: Int
init(number: Int) {
self.number = number
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
self.number = 0
super.init(coder: aDecoder)
}
}
I managed to reduce the amount of boilerplate to this:
#if canImport(SwiftUI) && DEBUG
import SwiftUI
class ViewController_Previews: Previewer<ViewController>, PreviewProvider {}
#endif
And it looks like in latest Xcode you don't even need to change the deployment target. So IMO there is no need to setup extra schemes, targets, etc., just add those few lines and maybe a setup function to inject fake view model.
I solved the hot reload problem by having an UINavigationController as the main representable, and then swapping the view controller inside it on every hot reload.
More info in my repo: https://github.com/szotp/programmatic_preview
Hi thanks for the intro! Question tho— how did you make the preview canvas show up? I tried switching between Editor Only and Editor and Canvas but it has no effect. Guess it’s an early beta bug? Thanks!