从子视图更改@IBOutlet
Change @IBOutlet from a subview
我正在尝试从 UIView 启用或禁用工具栏的 @IBOutlet UIButton 项。
当我在 EraseView.Swift 中使用的数组为空时,按钮 应该被禁用。
我尝试创建视图控制器的实例,但它给了我错误(展开时发现 nil):
在擦除视图中:
class EraseView: UIView {
...
let editViewController = EditImageViewController()
//array has item
editViewController.undoEraseButton.enabled = true //here I get the error
...
}
我尝试放置一个全局 Bool,它在 EditImageViewController 中使用它更改了值,但它不起作用:
var enableUndoButton = false
class EditImageViewController: UIViewController {
@IBOutlet weak var undoEraseButton: UIBarButtonItem!
viewDidLoad() {
undoEraseButton.enabled = enableUndoButton
}
}
class EraseView: UIView {
...
//array has item
enableUndoButton = true //here I get the error
...
}
我知道这很简单,但我不能让它起作用。
情况如下:
问题的根源在于以下行:
let editViewController = EditImageViewController()
EditImageViewController()
表示 "ignore what the storyboard has already instantiated for me, but rather instantiate another view controller with no outlets hooked up and use that." 显然,这不是您想要的。
您需要为 EraseView
提供一些方法来通知现有的视图控制器其 "is empty" 状态是否发生了一些变化。而且,理想情况下,您希望以保持这两个 类 松散耦合的方式来执行此操作。 EraseView
应该只通知视图控制器 "is empty" 状态的变化,视图控制器应该启动其他子视图(即按钮)的更新。一个视图真的不应该更新另一个视图的出口。
您可以通过两种方式做到这一点:
关闭:
你可以给 EraseView
一个可选的闭包,当它从 "empty" 和 "not empty" 切换时调用它:
var emptyStateChanged: ((Bool) -> ())?
然后状态改变的时候就可以调用这个了。例如,当您删除视图中的最后一项时,EraseView
可以调用该闭包:
emptyStateChanged?(true)
最后,为了真正执行任何操作,视图控制器应提供实际的闭包以在状态更改时启用和禁用按钮:
override func viewDidLoad() {
super.viewDidLoad()
eraseView.emptyStateChanged = { [unowned self] isEmpty in
self.undoEraseButton.enabled = !isEmpty
}
}
注意,我使用 unowned
来避免强引用循环。
委托协议模式:
所以你可以定义一个协议来做到这一点:
protocol EraseViewDelegate : class {
func eraseViewIsEmpty(empty: Bool)
}
然后给EraseView
一个delegate
属性:
weak var delegate: EraseViewDelegate?
请注意,这是 weak
以避免强引用循环。 (这也是我将协议定义为 class
协议的原因,这样我就可以在此处将其设为 weak
。)
当视图的 "is empty" 状态发生变化时,EraseView
将调用此委托。例如,当它变空时,它会相应地通知它的委托:
delegate?.eraseViewIsEmpty(true)
然后,为了使这一切正常工作,视图控制器应该 (a) 声明它符合协议; (b) 将自己指定为 EraseView
的 delegate
; (c) 实施 eraseViewIsEmpty
方法,例如:
class EditImageViewController: UIViewController, EraseViewDelegate {
@IBOutlet weak var undoEraseButton: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
eraseView.delegate = self
}
func eraseViewIsEmpty(empty: Bool) {
undoEraseButton.enabled = !empty
}
}
这两种模式都使两个 类 保持松散耦合,但允许 EraseView
将某些事件通知其视图控制器。它还消除了对任何全局的需要。
还有其他方法也可以解决这个问题(例如通知、KVN 等),但希望这能说明基本思想。视图应将任何关键事件通知其视图控制器,而视图控制器应负责其他视图的更新。
我正在尝试从 UIView 启用或禁用工具栏的 @IBOutlet UIButton 项。
当我在 EraseView.Swift 中使用的数组为空时,按钮 应该被禁用。
我尝试创建视图控制器的实例,但它给了我错误(展开时发现 nil):
在擦除视图中:
class EraseView: UIView {
...
let editViewController = EditImageViewController()
//array has item
editViewController.undoEraseButton.enabled = true //here I get the error
...
}
我尝试放置一个全局 Bool,它在 EditImageViewController 中使用它更改了值,但它不起作用:
var enableUndoButton = false
class EditImageViewController: UIViewController {
@IBOutlet weak var undoEraseButton: UIBarButtonItem!
viewDidLoad() {
undoEraseButton.enabled = enableUndoButton
}
}
class EraseView: UIView {
...
//array has item
enableUndoButton = true //here I get the error
...
}
我知道这很简单,但我不能让它起作用。
情况如下:
问题的根源在于以下行:
let editViewController = EditImageViewController()
EditImageViewController()
表示 "ignore what the storyboard has already instantiated for me, but rather instantiate another view controller with no outlets hooked up and use that." 显然,这不是您想要的。
您需要为 EraseView
提供一些方法来通知现有的视图控制器其 "is empty" 状态是否发生了一些变化。而且,理想情况下,您希望以保持这两个 类 松散耦合的方式来执行此操作。 EraseView
应该只通知视图控制器 "is empty" 状态的变化,视图控制器应该启动其他子视图(即按钮)的更新。一个视图真的不应该更新另一个视图的出口。
您可以通过两种方式做到这一点:
关闭:
你可以给
EraseView
一个可选的闭包,当它从 "empty" 和 "not empty" 切换时调用它:var emptyStateChanged: ((Bool) -> ())?
然后状态改变的时候就可以调用这个了。例如,当您删除视图中的最后一项时,
EraseView
可以调用该闭包:emptyStateChanged?(true)
最后,为了真正执行任何操作,视图控制器应提供实际的闭包以在状态更改时启用和禁用按钮:
override func viewDidLoad() { super.viewDidLoad() eraseView.emptyStateChanged = { [unowned self] isEmpty in self.undoEraseButton.enabled = !isEmpty } }
注意,我使用
unowned
来避免强引用循环。委托协议模式:
所以你可以定义一个协议来做到这一点:
protocol EraseViewDelegate : class { func eraseViewIsEmpty(empty: Bool) }
然后给
EraseView
一个delegate
属性:weak var delegate: EraseViewDelegate?
请注意,这是
weak
以避免强引用循环。 (这也是我将协议定义为class
协议的原因,这样我就可以在此处将其设为weak
。)当视图的 "is empty" 状态发生变化时,
EraseView
将调用此委托。例如,当它变空时,它会相应地通知它的委托:delegate?.eraseViewIsEmpty(true)
然后,为了使这一切正常工作,视图控制器应该 (a) 声明它符合协议; (b) 将自己指定为
EraseView
的delegate
; (c) 实施eraseViewIsEmpty
方法,例如:class EditImageViewController: UIViewController, EraseViewDelegate { @IBOutlet weak var undoEraseButton: UIBarButtonItem! override func viewDidLoad() { super.viewDidLoad() eraseView.delegate = self } func eraseViewIsEmpty(empty: Bool) { undoEraseButton.enabled = !empty } }
这两种模式都使两个 类 保持松散耦合,但允许 EraseView
将某些事件通知其视图控制器。它还消除了对任何全局的需要。
还有其他方法也可以解决这个问题(例如通知、KVN 等),但希望这能说明基本思想。视图应将任何关键事件通知其视图控制器,而视图控制器应负责其他视图的更新。