简体   繁体   English

如何在Swift中使用协议初始化UIViews和UIViewControllers

[英]How to Initialize UIViews and UIViewControllers Using Protocols in Swift

I've been experimenting lately with building iOS views using a trick I learned from René Cacheaux to easily initialize UIViewControllers from code: 我最近一直在尝试使用从RenéCacheaux中学到的技巧来构建iOS视图,以便通过代码轻松初始化UIViewControllers:

class NiblessViewController: UIViewController {
    init() {
        super.init(nibName: nil, bundle: nil)
    }

    @available(*, unavailable, message: "Loading this view controller from a nib is unsupported.")
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }

    @available(*, unavailable, message: "Loading this view controller from a nib is unsupported.")
    required init?(coder aDecoder: NSCoder) {
        fatalError("Loading this view controller from a nib is unsupported")
    }
}

You can then inherit from NiblessViewController in your custom view controller classes without having do the initializer overriding each time: 然后,您可以在自定义视图控制器类中从NiblessViewController继承,而不必每次都进行初始化覆盖:

class CustomViewController: NiblessViewController {
    // ...
}

This works great when working with a vanilla UIViewController , but I can't figure out a nice way to use it with other view controller classes (eg UITableViewController , UINavigationController ) without creating a separate Nibless class for each view controller type (eg NiblessTableViewController , NiblessNavigationController ), containing the exact same code. 在使用普通UIViewController ,此方法效果很好,但我无法找到一种与其他视图控制器类(例如UITableViewControllerUINavigationController )一起使用的好方法,而无需为每种视图控制器类型(例如NiblessTableViewControllerNiblessNavigationController )创建单独的Nibless类),包含完全相同的代码。

One thing I tried was to use a protocol extension like so: 我尝试过的一件事是使用这样的协议扩展:

protocol Nibless {}

extension Nibless where Self: UIViewController {
    // Same initialization code as above
}

Doing it this way, I get three errors saying: 这样,我会遇到三个错误:

  1. 'super' cannot be used outside of class members 'super'不能在班级成员之外使用
  2. 'required' initializer in non-class type 'NiblessViewController' 非类类型“ NiblessViewController”中的“必需”初始化程序
  3. initializer does not override a designated initializer from its superclass 初始化程序不会覆盖其父类中的指定初始化程序

Any ideas on a nice way to do this without having duplicate code? 在没有重复代码的情况下,有什么好主意吗?

I totally get why you are going after what you are (to forbid IB), but it's not possible at the moment. 我完全理解为什么您要追求自己的身份(禁止IB),但目前尚不可能。 It's also not super practical either. 这也不是超级实用。 Let me explain: 让我解释:

  • The init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) method is the class's designated initializer. init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)方法是该类的指定初始化程序。 You should use this whenever initializing a UIViewController and marking it unavailable isn't the proper behavior. 每当初始化UIViewController并将其标记为不正确时,都应使用此方法。
  • For other subclasses of UIViewController they each have their own initializers (like UITableViewController(style:) ), which wouldn't be covered in your protocol. 对于UIViewController其他子类,每个子类都有自己的初始化程序(如UITableViewController(style:) ),但协议中不会涉及它们。
  • You can mark methods as unavailable in protocols but only @objc protocols, and in my brief testing with a playground didn't work like I was hoping it would (that would be very cool if we could do it though). 您可以将方法标记为在协议中不可用,而只能将@objc协议标记为不可用,并且在我的操场上进行的简短测试无法像我希望的那样工作(如果可以的话,那将非常酷)。
  • However even if we were able to mark protocol items as unavailable, I don't believe we could forbid access to existing members on a class through that technique. 但是,即使我们能够将协议项标记为不可用,我也不认为我们可以禁止通过该技术访问班上现有的成员。

I think your best bet might be to make your own "base" subclasses of each UIViewController subclass that you want and expressly forbid IB there. 我认为最好的选择是为每个UIViewController子类创建自己的“基本”子类,并在那里明确禁止IB。 One of the nice things about initialization in code is that you can get rid of Optional<T> properties that have to litter IB-bound view controllers. 关于代码初始化的好处之一是,您可以摆脱Optional<T>属性,这些属性必须乱扔IB绑定的视图控制器。

Here's a gist that I created which has the base UIViewController subclass. 这是我创建的要点,它具有基本的UIViewController子类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM