#ios #swift #swiftui #uikit #uihostingcontroller
#iOS #быстрый #свифтуи #уикит #контроллер uihostingcontroller
Вопрос:
Я добавляю UIHostingViewController в свою раскадровку и создаю класс для этого. Загрузите mySwiftUIView в инициализацию контроллера. Все работает хорошо.
Но я хочу сделать хостинг-контроллер похожим на делегат для mySwiftUIView, потому что я хочу обрабатывать нажатие кнопки в представлении.
required init?(coder: NSCoder) {
var mySwiftView = MySwiftUIView()
mySwiftView.delegate = self //self used before super.init call
super.init(coder: coder,rootView: mySwiftView)
}
Идентификатор не работает, потому что я передаю просмотр до полной инициализации контроллера хостинга. Swift показывает сообщение «self используется перед вызовом super.init»
Если я буду использовать обычный UIViewController и помещу HostingController внутрь — это работает. Но это мне не подходит, потому что вызывает проблемы с размерами и навигацией.
Как я могу это сделать с помощью отдельного UIHostingController. Спасибо
Полный код
import UIKit
import SwiftUI
protocol MySwiftUIViewDelegate{
func buttonPressed()
}
struct MySwiftUIView: View {
var delegate: MySwiftUIViewDelegate?
var body: some View {
Button(action: {
delegate?.buttonPressed()
}) {
Text("My button")
}
}
}
class MyHostingViewController: UIHostingController<MySwiftUIView>, MySwiftUIViewDelegate {
required init?(coder: NSCoder) {
var mySwiftView = MySwiftUIView()
//mySwiftView.delegate = self //self used before super.init call
super.init(coder: coder,rootView: mySwiftView)
}
override func viewDidLoad() {
super.viewDidLoad()
}
func buttonPressed() {
performSegue(withIdentifier: "GoToOtherScreenSegue", sender: self)
}
}
Ответ №1:
Поскольку MyHostingViewController
известно, что rootView
это MySwiftUIView
так, вы можете впоследствии назначить контроллер представления в качестве делегата:
required init?(coder: NSCoder) {
var mySwiftView = MySwiftUIView()
super.init(coder: coder, rootView: mySwiftView)
rootView.delegate = self
}
Комментарии:
1. Обратите внимание, что вы не можете этого сделать
mySwiftView.delegate = self
, потому что это структура, скопированная по значению, поэтому для «реального» view (rootView
) не будет установлен делегат. ТакжеmySwiftView
может бытьlet
здесь.
Ответ №2:
Вы можете обернуть делегат в класс
import UIKit
import SwiftUI
protocol MySwiftUIViewDelegate{
func buttonPressed()
}
struct MySwiftUIView: View {
let configuration: Configuration
var body: some View {
Button(action: {
configuration.delegate?.buttonPressed()
}) {
Text("My button")
}
}
}
extension MySwiftUIView {
final class Configuration {
unowned var delegate: MySwiftUIViewDelegate?
}
}
class MyHostingViewController: UIHostingController<MySwiftUIView>, MySwiftUIViewDelegate {
required init?(coder: NSCoder) {
let configuration = MySwiftUIView.Configuration()
let mySwiftView = MySwiftUIView(configuration: configuration)
super.init(coder: coder,rootView: mySwiftView)
configuration.delegate = self
}
override func viewDidLoad() {
super.viewDidLoad()
}
func buttonPressed() {
performSegue(withIdentifier: "GoToOtherScreenSegue", sender: self)
}
}