Ios 如何在UI子类中隐藏故事板和Nib特定的初始值设定项 问题:
如果我知道Ios 如何在UI子类中隐藏故事板和Nib特定的初始值设定项 问题:,ios,swift,Ios,Swift,如果我知道init?(编码者:)和其他故事板/nib特定的初始化器将不会被调用,我可以避免在UI子类中实现或调用它们吗 背景 许多UIKit类,包括UIViewController,UIView和UIControl的子类(UIButton,UITextField等)采用NSCoding协议。NSCodinginit?(coder:)方法用于从故事板或nib实例化这些类 NSCoding协议: public protocol NSCoding { func encode(with aCod
init?(编码者:)
和其他故事板/nib特定的初始化器将不会被调用,我可以避免在UI子类中实现或调用它们吗
背景
许多UIKit类,包括UIViewController
,UIView
和UIControl
的子类(UIButton
,UITextField
等)采用NSCoding
协议。NSCoding
init?(coder:)
方法用于从故事板或nib实例化这些类
NSCoding
协议:
public protocol NSCoding {
func encode(with aCoder: NSCoder)
init?(coder aDecoder: NSCoder)
}
采用带有初始值设定项的协议的类必须按照所需的实现该初始值设定项。所有子类都必须实现所需的初始值设定项
internal class BaseButton: UIButton {
// This initializer hides init(frame:) from subclasses
init() {
super.init(frame: CGRect.zero)
}
@available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
}
class CustomButton: BaseButton {
let someProperty: Int
init(someProperty: Int) {
self.someProperty = someProperty
super.init()
}
}
let customButton = CustomButton(someProperty: 1)
我经常构建没有故事板或笔尖的iOS应用程序。我完全在代码中实现UIViewController、UIView和UIControl子类。但是,如果我想提供自己的init
方法(我经常这样做),我必须在子类中实现init?(coder:)
,以安抚编译器。下面的例子说明了这一点
以下内容未编译
class CustomView: UIView {
init() {
super.init(frame: CGRect.zero)
}
}
// Error:'required' initializer 'init(coder:)' must be provided by subclass of 'UIView'
以下代码确实可以编译,因为我提供了init?(coder:)
的一个实现。对于纯代码的UI子类,我通常通过抛出一个致命错误来实现“init(coder:)”,断言我不希望调用它
class CustomView: UIView {
init() {
super.init(frame: CGRect.zero)
}
required init?(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
}
出于上述原因,CustomView的子类还需要实现“init(coder:)”
class SubClassOfCustomView: CustomView {
let someProperty: Int
init(someProperty: Int) {
self.someProperty = someProperty
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
}
UI子类和@可用(*,不可用)
*下面的代码是用Swift 3编写和测试的
此解决方案的关键是创建自定义UI子类继承自的基本子类。在下面的示例中,这些子类被命名为BaseViewController
、BaseView
和BaseButton
。这些子类包括一个初始值设定项,该初始值设定项默认对其子类隐藏的超类指定初始值设定项的参数
internal class BaseButton: UIButton {
// This initializer hides init(frame:) from subclasses
init() {
super.init(frame: CGRect.zero)
}
@available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
}
class CustomButton: BaseButton {
let someProperty: Int
init(someProperty: Int) {
self.someProperty = someProperty
super.init()
}
}
let customButton = CustomButton(someProperty: 1)
init(coder:)
必须在所有子类中实现,因为它是UI超类的必需初始值设定项。您可以通过将属性@available(*,unavailable)
放在该初始值设定项的实现之上来解决此问题
用于“指示声明相对于特定平台和操作系统版本的生命周期”。将此属性与以下参数一起使用:@available(*,unavailable)
使后面的代码块在所有平台的所有版本上都不可用。
UIViewController
UIView
UIButton-UIControl子类
此UIButton示例说明如何对UIControl子类进行子类化
internal class BaseButton: UIButton {
// This initializer hides init(frame:) from subclasses
init() {
super.init(frame: CGRect.zero)
}
@available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
}
class CustomButton: BaseButton {
let someProperty: Int
init(someProperty: Int) {
self.someProperty = someProperty
super.init()
}
}
let customButton = CustomButton(someProperty: 1)
考虑
我不建议定期使用@available(*,unavailable)
来避免实现所需的初始值设定项。这有助于减少在这种情况下不会调用的冗余代码(因为您不打算使用故事板/NIB)。通过在基类中使用@available(*,unavailable)
而不是在每个自定义子类中使用它,可以减少@available(*,unavailable)
的外观
我知道这在Swift 2和3中有效。Swift的未来版本可能不允许这样做。然而,我希望Swift团队能想出一个更好的方法来避免自定义UI子类中的这种冗余代码
internal class BaseButton: UIButton {
// This initializer hides init(frame:) from subclasses
init() {
super.init(frame: CGRect.zero)
}
@available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
}
class CustomButton: BaseButton {
let someProperty: Int
init(someProperty: Int) {
self.someProperty = someProperty
super.init()
}
}
let customButton = CustomButton(someProperty: 1)
出于好奇,我尝试从故事板启动BaseViewController子类。我预计应用程序会因选择器未找到错误而崩溃,但它调用了init?(coder)
方法,尽管它对所有平台都是隐藏的。这可能是因为available
属性没有对目标C隐藏init?(coder)
初始值设定项,而脚本实例化代码就是在这里运行的
UIKit经常使用类和继承,而Swift社区鼓励结构和面向协议的编程。我在我的基本UI类声明上面包含以下标题,以阻止基本UI类成为全局设置和功能的垃圾场
/**
* This base UIViewController subclass removes the requirement to override init(coder:) and hides init(nibName:bundle:) from subclasses.
* It is not intended to create global functionality inherited by all UIViewControllers.
* Alternatively, functionality can be added to UIViewController's via composition and/or protocol oriented programming.
*/
/**
* This base UIView subclass removes the requirement to override init(coder:) and hides init(frame:) from subclasses.
* It is not intended to create global functionality inherited by all UIViews.
* Alternatively, functionality can be added to UIView's via composition and/or protocol oriented programming.
*/
参考:我发现Swift语言指南的章节有助于理解初始值设定者的规则。UI子类和@available(*,available)
*下面的代码是用Swift 3编写和测试的
此解决方案的关键是创建自定义UI子类继承自的基本子类。在下面的示例中,这些子类被命名为BaseViewController
、BaseView
和BaseButton
。这些子类包括一个初始值设定项,该初始值设定项默认对其子类隐藏的超类指定初始值设定项的参数
internal class BaseButton: UIButton {
// This initializer hides init(frame:) from subclasses
init() {
super.init(frame: CGRect.zero)
}
@available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
}
class CustomButton: BaseButton {
let someProperty: Int
init(someProperty: Int) {
self.someProperty = someProperty
super.init()
}
}
let customButton = CustomButton(someProperty: 1)
init(coder:)
必须在所有子类中实现,因为它是UI超类的必需初始值设定项。您可以通过将属性@available(*,unavailable)
放在该初始值设定项的实现之上来解决此问题
用于“指示声明相对于特定平台和操作系统版本的生命周期”。将此属性与以下参数一起使用:@available(*,unavailable)
使后面的代码块在所有平台的所有版本上都不可用。
UIViewController
UIView
UIButton-UIControl子类
此UIButton示例说明如何对UIControl子类进行子类化
internal class BaseButton: UIButton {
// This initializer hides init(frame:) from subclasses
init() {
super.init(frame: CGRect.zero)
}
@available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
}
class CustomButton: BaseButton {
let someProperty: Int
init(someProperty: Int) {
self.someProperty = someProperty
super.init()
}
}
let customButton = CustomButton(someProperty: 1)
考虑
我不建议定期使用@available(*,unavailable)
来避免实现所需的初始值设定项。这有助于减少在这种情况下不会调用的冗余代码(因为您不打算使用故事板/NIB)。@available(*,unavailable)
的外观通过在基类中使用它(并使自定义子类继承自基类)作为操作来减少