继承具有“依赖关系”的 CustomViewController 的正确方法

Posted

技术标签:

【中文标题】继承具有“依赖关系”的 CustomViewController 的正确方法【英文标题】:The proper way to inherit a CustomViewController with "dependencies" 【发布时间】:2019-04-29 13:17:41 【问题描述】:

最近我写了一个应用程序,只有一个场景和ViewController。我必须为View 管理的View 设置自定义背景图片(即我的顶视图包含UIImageView)。后来我不得不在ViewController 中实现一些逻辑,以便在屏幕旋转时正确旋转/更改图片。我还必须为ViewController 覆盖一些属性,例如preferredStatusBarStyle

现在我必须在我的应用程序中实现更多的场景/屏幕,事实证明它们都必须与当前存在的屏幕具有相同的设计,所以我认为如果我创建一个 CommonViewController 包含这个常见的背景图片旋转相关逻辑,这样我就可以从这个CommonViewController继承我所有的其他ViewControllers。我唯一的问题是CommonViewController“要求”它管理的视图具有backgroundPicture: UIView 属性,我不知道如何确保。

如果我与 XIB 文件一起创建一个新文件 CommonViewController,我可以在 XIB 中添加 backgroundPicture 图像视图并将其与代码连接(通过常规的“控制拖动”方法),但显然这不会t 工作,因为不能保证继承 CommonViewController 的视图将具有此属性。在 Swift 中没有 hack 的情况下解决这个问题的正确方法是什么?

不幸的是,我找不到解决方案,也许我一直在寻找错误的东西。似乎我需要为每个场景(每个CustomViewController)继承一个CommonViewController,但我还必须以某种方式将每个控制器的顶视图设置为等于一些CommonView,以便@当我尝试访问@IBOutlet weak var backgroundPicutre: UIImageView! 时,987654339@ 不会崩溃。


显而易见的方法是在 CommonViewController 中定义一些方法或属性,以便继承它的控制器可以实现/覆盖它,但这似乎有点 hacky,因为它仍然需要在每个 @ 中复制粘贴987654342@ 继承CommonViewController

我如何想象解决方案:我创建CustomViewController: CommonViewController,然后在我的 Storyboard 中创建一个视图控制器并将“Class”属性更改为“CustomViewController”(在属性编辑器中),然后选择与此相对应的视图新添加的控制器并将“Class”属性更改为“BackgroundImageView. But I'm not sure if it's the correct way to do (also I doubt thatCustomViewControllerwill properly "connect" itsIBOutletfieldbakcgroundImageViewwith the correspondingUIViewfromBackgroundImageView`,这就是为什么我想问专家他们对此有何看法。

【问题讨论】:

【参考方案1】:

我认为您应该完全在代码中定义您的基本控制器 (CommonViewController),即不要为基本控制器使用任何 xibs / storyboards。这并不意味着您应该完全摆脱故事板/ xib。除了CommonViewController 之外的所有其他视图控制器的接口仍然可以使用 xibs / storyboards 实现。

在这种情况下,CommonViewController 的实现可能如下所示:

import UIKit

class CommonViewController: UIViewController 
    // use this property every time you need to 
    // manipulate backgroundPicture
    var backgroundPicture: UIImageView  = 
        // Replace with your image name
        let image = UIImage(named: "BackgroundPicture")!
        let imageView = UIImageView()
        imageView.image = image
        return imageView
    ()

    override func viewDidLoad() 
        // If subclass overrides viewDidLoad() 
        // it should contain super.viewDidLoad()
        super.viewDidLoad()

        view.addSubview(backgroundPicture)

        // Align backgroundPicture to bounds of superview
        // You can remove this code and implement
        // your own alignment with frames or Autolayout
        backgroundPicture.frame = view.bounds

        // Send backgroundPicture to back of the view
        // Otherwise backgroundPicture may overlap views added in subclasses
        view.sendSubviewToBack(backgroundPicture)
    
    
    override func viewDidLayoutSubviews() 
        // If subclass overrides viewDidLayoutSubviews()
        // It should contain super.viewDidLayoutSubviews() 
        super.viewDidLayoutSubvews()

        // Align backgroundPicture to bounds of superview
        // You can remove this code and implement
        // your own alignment with frames or Autolayout
        backgroundPicture.frame = view.bounds
    

【讨论】:

感谢您的想法;但是在你的方法中......做self.view = commonView是否安全?在这种情况下,我将无法使用CommonViewController 管理任何其他视图,对吧? (因为它覆盖了loadView() 中的视图,并且将使用一些内部视图,而不是它要管理的“真实”视图? 我读得更仔细了,你是对的。如果控制器或其子类使用 nib 文件,则重写 loadView 是个坏主意。我更新了我的答案,所以它不再使用 loadView

以上是关于继承具有“依赖关系”的 CustomViewController 的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

Spring04-----DI

Spring学习:DI的配置

spring05----DI的配置使用

Java学习8——类(对象)之间的关系

依赖关联聚合和组合之间区别

bean之间的继承和依赖关系