如何将 Parent 委派给多个不同的孩子?
How to Delegate from Parent to Multiple Different Childs?
我有这个方案:
- 家庭控制器
- 导航控制器
- Step1(NavigationController 的child)
- Step2(NavigationController 的child)
我的问题是我不知道如何将信息从 Parent 传递给所有不同的 childs,因为当我将委托分配给 childs 时,总是需要最后一个一。因此,如果我调用委托,只有最后添加的 child 会收到信息
一些基本代码:
class HomeController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
addSubview(showSteps)
}
@objc func showSteps() {
let controller = NavigationController()
self.present(controller, animated: true, completion: nil)
}
}
protocol UserProtocol: AnyObject {
func userHasChanged(_ user: User?)
}
class NavigationController: UIViewController {
var user: User?
weak var delegate: UserProtocol?
override func viewDidLoad() {
// all step childs are differents
let step1 = Step1()
addStep(step: step1)
delegate = step1
let step2 = Step2()
addStep(step: step2)
delegate = step2
let step3 = Step3()
addStep(step: step3)
delegate = step3
let step4 = Step4()
addStep(step: step4)
delegate = step4
}
func addStep(step: UIViewController){
self.addChild(step)
step.willMove(toParent: self)
view.addSubview(step.view)
step.didMove(toParent: self)
}
func userHasChanged(_ user: User?){
// this observe new user data from firebase
Service.shared.fetchUserData(uid: "XXX") { user in
self.user = user
// send new data to childs
// ONLY SEND TO CHILD4, (THE LAST ONE OBVIOUSLY)
self.delegate?.userHasChanged(user)
}
}
}
// that is a child example
class Step1: UIViewController, UserProtocol {
var user: User?
override func viewDidLoad() {
super.viewDidLoad()
}
func tripHasChanged(_ new_user: User?) {
print("changed1")
self.user = new_user
}
}
class Step2: UIViewController, UserProtocol {
var user: User?
override func viewDidLoad() {
super.viewDidLoad()
}
func tripHasChanged(_ new_user: User?) {
print("changed2")
self.user = new_user
}
}
class Step3: UIViewController, UserProtocol {
var user: User?
override func viewDidLoad() {
super.viewDidLoad()
}
func tripHasChanged(_ new_user: User?) {
print("changed3")
self.user = new_user
}
}
class Step4: UIViewController, UserProtocol {
var user: User?
override func viewDidLoad() {
super.viewDidLoad()
}
func tripHasChanged(_ new_user: User?) {
print("changed4")
self.user = new_user
}
}
*只打印“changed4”
我的问题:
我怎样才能通过一个委托(也许是数组?)将数据发送到所有不同的 child?。有可能,属于好的做法?
谢谢!
您可以创建委托数组...但这实际上不是委托/协议设计模式。
您也可以采用 NotificationCenter
addObserver / post 通知方法...但这更适合多个对象,这些对象不一定在当前 class.
对于您的情况 - 多个子视图控制器都需要基于同一事件“做某事”,更好的方法可能是创建一个“基础”视图控制器并使每个“步骤”子class那个基地的。
这是一个简单的例子...
// this is our "Step" base view controller
// creates the "user" property
// defines the "userHasChanged()" method
class StepBaseViewController: UIViewController {
var user: String?
func userHasChanged(_ new_user: String) {
user = new_user
}
override func viewDidLoad() {
super.viewDidLoad()
// we can do anything that may be
// "common" to all "Steps"
}
}
您创建 StepBaseViewController
的子 class 的任何视图控制器现在将具有 user
属性 和处理 userHasChanged
的默认方法。此外,可以在 viewDidLoad()
.
中设置对步骤“通用”的任何内容(例如标签、按钮等 UI 元素)
现在你的第 4 个“步骤”class 变成:
class Step1: StepBaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
// setup specific to this "Step"
}
override func userHasChanged(_ new_user: String) {
super.userHasChanged(new_user)
print("User changed to:", self.user, "in:", self)
// do something specific to Step 1
}
}
class Step2: StepBaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
// setup specific to this "Step"
}
override func userHasChanged(_ new_user: String) {
super.userHasChanged(new_user)
print("User changed to:", self.user, "in:", self)
// do something specific to Step 2
}
}
class Step3: StepBaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
// setup specific to this "Step"
}
override func userHasChanged(_ new_user: String) {
super.userHasChanged(new_user)
print("User changed to:", self.user, "in:", self)
// do something specific to Step 3
}
}
class Step4: StepBaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
// setup specific to this "Step"
}
override func userHasChanged(_ new_user: String) {
super.userHasChanged(new_user)
print("User changed to:", self.user, "in:", self)
// do something specific to Step 4
}
}
这里是您的 NavigationController
的修改版本,展示了如何使用此方法:
class NavigationController: UIViewController {
// we'll simulate the user changing
// so on first tap the user will become "User 1"
// on next tap user will become "User 2"
// on next tap user will become "User 3"
// and so on
var n: Int = 0
var user: String = ""
override func viewDidLoad() {
// all step childs are differents
let step1 = Step1()
addStep(step: step1)
let step2 = Step2()
addStep(step: step2)
let step3 = Step3()
addStep(step: step3)
let step4 = Step4()
addStep(step: step4)
}
func addStep(step: UIViewController){
self.addChild(step)
step.willMove(toParent: self)
view.addSubview(step.view)
step.didMove(toParent: self)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// simulate the "user changed" event
n += 1
self.user = "User \(n)"
self.children.forEach { child in
if let vc = child as? StepBaseViewController {
vc.userHasChanged(self.user)
}
}
}
}
加载 NavigationController
后,点击 3 次会导致此调试控制台输出:
User changed to: Optional("User 1") in: <MyProj.Step1: 0x7fbd7a21caf0>
User changed to: Optional("User 1") in: <MyProj.Step2: 0x7fbd7a21c480>
User changed to: Optional("User 1") in: <MyProj.Step3: 0x7fbd7a21d480>
User changed to: Optional("User 1") in: <MyProj.Step4: 0x7fbd7a21dca0>
User changed to: Optional("User 2") in: <MyProj.Step1: 0x7fbd7a21caf0>
User changed to: Optional("User 2") in: <MyProj.Step2: 0x7fbd7a21c480>
User changed to: Optional("User 2") in: <MyProj.Step3: 0x7fbd7a21d480>
User changed to: Optional("User 2") in: <MyProj.Step4: 0x7fbd7a21dca0>
User changed to: Optional("User 3") in: <MyProj.Step1: 0x7fbd7a21caf0>
User changed to: Optional("User 3") in: <MyProj.Step2: 0x7fbd7a21c480>
User changed to: Optional("User 3") in: <MyProj.Step3: 0x7fbd7a21d480>
User changed to: Optional("User 3") in: <MyProj.Step4: 0x7fbd7a21dca0>
我有这个方案:
- 家庭控制器
- 导航控制器
- Step1(NavigationController 的child)
- Step2(NavigationController 的child)
- 导航控制器
我的问题是我不知道如何将信息从 Parent 传递给所有不同的 childs,因为当我将委托分配给 childs 时,总是需要最后一个一。因此,如果我调用委托,只有最后添加的 child 会收到信息
一些基本代码:
class HomeController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
addSubview(showSteps)
}
@objc func showSteps() {
let controller = NavigationController()
self.present(controller, animated: true, completion: nil)
}
}
protocol UserProtocol: AnyObject {
func userHasChanged(_ user: User?)
}
class NavigationController: UIViewController {
var user: User?
weak var delegate: UserProtocol?
override func viewDidLoad() {
// all step childs are differents
let step1 = Step1()
addStep(step: step1)
delegate = step1
let step2 = Step2()
addStep(step: step2)
delegate = step2
let step3 = Step3()
addStep(step: step3)
delegate = step3
let step4 = Step4()
addStep(step: step4)
delegate = step4
}
func addStep(step: UIViewController){
self.addChild(step)
step.willMove(toParent: self)
view.addSubview(step.view)
step.didMove(toParent: self)
}
func userHasChanged(_ user: User?){
// this observe new user data from firebase
Service.shared.fetchUserData(uid: "XXX") { user in
self.user = user
// send new data to childs
// ONLY SEND TO CHILD4, (THE LAST ONE OBVIOUSLY)
self.delegate?.userHasChanged(user)
}
}
}
// that is a child example
class Step1: UIViewController, UserProtocol {
var user: User?
override func viewDidLoad() {
super.viewDidLoad()
}
func tripHasChanged(_ new_user: User?) {
print("changed1")
self.user = new_user
}
}
class Step2: UIViewController, UserProtocol {
var user: User?
override func viewDidLoad() {
super.viewDidLoad()
}
func tripHasChanged(_ new_user: User?) {
print("changed2")
self.user = new_user
}
}
class Step3: UIViewController, UserProtocol {
var user: User?
override func viewDidLoad() {
super.viewDidLoad()
}
func tripHasChanged(_ new_user: User?) {
print("changed3")
self.user = new_user
}
}
class Step4: UIViewController, UserProtocol {
var user: User?
override func viewDidLoad() {
super.viewDidLoad()
}
func tripHasChanged(_ new_user: User?) {
print("changed4")
self.user = new_user
}
}
*只打印“changed4”
我的问题:
我怎样才能通过一个委托(也许是数组?)将数据发送到所有不同的 child?。有可能,属于好的做法?
谢谢!
您可以创建委托数组...但这实际上不是委托/协议设计模式。
您也可以采用 NotificationCenter
addObserver / post 通知方法...但这更适合多个对象,这些对象不一定在当前 class.
对于您的情况 - 多个子视图控制器都需要基于同一事件“做某事”,更好的方法可能是创建一个“基础”视图控制器并使每个“步骤”子class那个基地的。
这是一个简单的例子...
// this is our "Step" base view controller
// creates the "user" property
// defines the "userHasChanged()" method
class StepBaseViewController: UIViewController {
var user: String?
func userHasChanged(_ new_user: String) {
user = new_user
}
override func viewDidLoad() {
super.viewDidLoad()
// we can do anything that may be
// "common" to all "Steps"
}
}
您创建 StepBaseViewController
的子 class 的任何视图控制器现在将具有 user
属性 和处理 userHasChanged
的默认方法。此外,可以在 viewDidLoad()
.
现在你的第 4 个“步骤”class 变成:
class Step1: StepBaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
// setup specific to this "Step"
}
override func userHasChanged(_ new_user: String) {
super.userHasChanged(new_user)
print("User changed to:", self.user, "in:", self)
// do something specific to Step 1
}
}
class Step2: StepBaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
// setup specific to this "Step"
}
override func userHasChanged(_ new_user: String) {
super.userHasChanged(new_user)
print("User changed to:", self.user, "in:", self)
// do something specific to Step 2
}
}
class Step3: StepBaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
// setup specific to this "Step"
}
override func userHasChanged(_ new_user: String) {
super.userHasChanged(new_user)
print("User changed to:", self.user, "in:", self)
// do something specific to Step 3
}
}
class Step4: StepBaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
// setup specific to this "Step"
}
override func userHasChanged(_ new_user: String) {
super.userHasChanged(new_user)
print("User changed to:", self.user, "in:", self)
// do something specific to Step 4
}
}
这里是您的 NavigationController
的修改版本,展示了如何使用此方法:
class NavigationController: UIViewController {
// we'll simulate the user changing
// so on first tap the user will become "User 1"
// on next tap user will become "User 2"
// on next tap user will become "User 3"
// and so on
var n: Int = 0
var user: String = ""
override func viewDidLoad() {
// all step childs are differents
let step1 = Step1()
addStep(step: step1)
let step2 = Step2()
addStep(step: step2)
let step3 = Step3()
addStep(step: step3)
let step4 = Step4()
addStep(step: step4)
}
func addStep(step: UIViewController){
self.addChild(step)
step.willMove(toParent: self)
view.addSubview(step.view)
step.didMove(toParent: self)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// simulate the "user changed" event
n += 1
self.user = "User \(n)"
self.children.forEach { child in
if let vc = child as? StepBaseViewController {
vc.userHasChanged(self.user)
}
}
}
}
加载 NavigationController
后,点击 3 次会导致此调试控制台输出:
User changed to: Optional("User 1") in: <MyProj.Step1: 0x7fbd7a21caf0>
User changed to: Optional("User 1") in: <MyProj.Step2: 0x7fbd7a21c480>
User changed to: Optional("User 1") in: <MyProj.Step3: 0x7fbd7a21d480>
User changed to: Optional("User 1") in: <MyProj.Step4: 0x7fbd7a21dca0>
User changed to: Optional("User 2") in: <MyProj.Step1: 0x7fbd7a21caf0>
User changed to: Optional("User 2") in: <MyProj.Step2: 0x7fbd7a21c480>
User changed to: Optional("User 2") in: <MyProj.Step3: 0x7fbd7a21d480>
User changed to: Optional("User 2") in: <MyProj.Step4: 0x7fbd7a21dca0>
User changed to: Optional("User 3") in: <MyProj.Step1: 0x7fbd7a21caf0>
User changed to: Optional("User 3") in: <MyProj.Step2: 0x7fbd7a21c480>
User changed to: Optional("User 3") in: <MyProj.Step3: 0x7fbd7a21d480>
User changed to: Optional("User 3") in: <MyProj.Step4: 0x7fbd7a21dca0>