【问题标题】:Can't change UIView attributes in the parent class / viewcontroller?无法更改父类/viewcontroller 中的 UIView 属性?
【发布时间】:2015-10-08 13:50:45
【问题描述】:

我已经使用 Swift 几个月了,但是我的主视图控制器文件太大了。

有没有办法把这个文件分成很多子类?

例如:1 个文件来处理约束。 1个文件来处理用户行为。 1 个文件来处理按钮...

我尝试过这样做,但没有成功连接这些文件并相互通信。 这是示例代码:

class KeyboardViewController: UIInputViewController {
 var btn = UIButton();
 func DoTask() {
    // call child class to do task ChildTask()
    Child.ChildTask()
 }
}
class Child: KeyboardViewController {
 func ChildTask() {
   self.btn.setTitle("abc", forState: .Normal)
 }
}

在这个例子中,子类不能改变 UIButton(来自父类)的属性。 怎么办?

【问题讨论】:

  • 阅读MVVM。它应该有帮助
  • @R.K.你能给我一个关于它的示例代码吗?特别是在这种情况下?

标签: ios swift class model-view-controller parent-child


【解决方案1】:

您可以在Objc.io article by Chris Eidhof 中很好地了解一些可以用来制作视图控制器的策略。

更具体地说,对于您的情况,您可能倾向于拥有一个视图控制器层次结构,其中有一个父视图控制器和子视图控制器。

为了让他们交流,我认为最好的方法是:

1 - 让父控制器拥有一个“模型”类;此类对您的 UI 属性进行建模(按钮是否突出显示?什么是文本字段内容?等等)

2 - 当您从父级创建子控制器时,将共享模型传递给它。

3 - 使用 KVO (tutorial here) 确保您的 UI 对模型更改做出反应。

在代码中,它看起来像这样(Swift 2.0):

private var myContext = 0

class MyModel : NSObject {

  dynamic var buttonTitle : String = "default title"
}

class MyChildVC : UIViewController {

  let model : MyModel
  @IBOutlet var button : UIButton?

  init(m : MyModel) {
    model = m
    super.init(nibName: nil, bundle: nil)
  }

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

  override func viewDidLoad() {
    super.viewDidLoad()

    self.model.addObserver(self, forKeyPath: "buttonTitle", options: .New, context: &myContext)

  }

  deinit {
    self.model.removeObserver(self, forKeyPath: "buttonTitle", context: &myContext)
  }

  override func observeValueForKeyPath(keyPath: String?,
    ofObject object: AnyObject?,
    change: [String : AnyObject]?,
    context: UnsafeMutablePointer<Void>) {

        if (keyPath == "buttonTitle") {
            button?.titleLabel?.text = self.model.buttonTitle
        }
  }

}


class MyParentVC : UIViewController {

  let model = MyModel()
  let vc1 : MyChildVC

  init() {
    self.vc1 = MyChildVC(m: model)
    super.init(nibName: nil, bundle: nil)

  }

  func someOp() {

    self.model.buttonTitle = "NewTitle"
  }

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

一开始可能会让人望而生畏,但一旦你习惯了它(以及 KVO 特质),它就会变得很有魅力。

如果您选择视图控制器层次结构,请不要忘记阅读有关 view controllers containment 的信息。

【讨论】:

  • 非常感谢您的回答。我正在查看它。今天,我有一个新的解决方案。如果我创建一个 viewcontroller 的实例,它像 var kvc: KeyboardViewController! 这样位于父类之外。在父类内部,在viewDidLoad 函数中,我分配了kvc = self,所以在任何类中,我都可以通过它的这个实例轻松访问父视图控制器?这是一个好的解决方案吗?
  • 嗯,这是一种替代方法。您应该确保通过init 参数或分配属性告诉子控制器哪个是其父控制器...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多