user3069232
user3069232

Reputation: 8995

Understanding UIViewRepresentable

Swift 5.0 iOS 13

Trying to understand how UIViewRepresentable works, and put together this simple example, almost there, but maybe its complete nonsense. Yes, I know there is already a tapGesture in SwiftUI, this is just a test.

Won't compile cause it says 'super.init' isn't called on all paths before returning from initialiser, which I try and set but obviously not correctly.

import SwiftUI

struct newView: UIViewRepresentable {

typealias UIViewType = UIView
var v = UIView()

func updateUIView(_ uiView: UIView, context: Context) {
  v.backgroundColor = UIColor.yellow
}


func makeUIView(context: Context) -> UIView {
  let tapGesture = UITapGestureRecognizer(target: self, action: #selector(Coordinator.handleTap(sender:)))
  v.addGestureRecognizer(tapGesture)
  return v
}

func makeCoordinator() -> newView.Coordinator {
  Coordinator(v)
}

final class Coordinator: UIView {
  private let view: UIView

init(_ view: UIView) {
    self.view = view
}

required init?(coder: NSCoder) {
  fatalError("init(coder:) has not been implemented")
}

@objc func handleTap(sender: UITapGestureRecognizer) {
    print("tap")
  }
 }

}

Upvotes: 2

Views: 4022

Answers (2)

Asperi
Asperi

Reputation: 258345

Just make your Coordinator is a NSObject, it usually plays bridge/controller/delegate/actor role, but not presentation, so should not be is-a-UIView

final class Coordinator: NSObject {
  private let view: UIView

init(_ view: UIView) {
    self.view = view
}

and one more...

func makeUIView(context: Context) -> UIView {
  // make target a coordinator, which is already present in context !!
  let tapGesture = UITapGestureRecognizer(target: context.coordinator, 
        action: #selector(Coordinator.handleTap(sender:)))
  v.addGestureRecognizer(tapGesture)
  return v
}

Upvotes: 3

Mojtaba Hosseini
Mojtaba Hosseini

Reputation: 119917

Thats because your Coordinator is a subclass of the UIView and you

Must call a designated initializer of the superclass 'UIView'

before returning from the init:

init(_ view: UIView) {
    self.view = view
    super.init(frame: .zero) // Or any other frame you need
}

Upvotes: 1

Related Questions