Ios 在swift中处理UIView公共初始化

Ios 在swift中处理UIView公共初始化,ios,swift,initialization,Ios,Swift,Initialization,一些特殊类(如UIView)有多个指定的初始值设定项 在Objective-X中,我们可以将公共初始化分解为单独的函数 - (id)initWithCoder:(NSCoder *)aDecoder { if (self = [super initWithCoder:aDecoder]) { [self initialize]; } return self; } - (id)initWithFrame:(CGRect)frame { if (s

一些特殊类(如UIView)有多个指定的初始值设定项

在Objective-X中,我们可以将公共初始化分解为单独的函数

- (id)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        [self initialize];
    }

    return self;
}

- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self initialize];
    }
    return self;
}
在Swift中,这不再是可能的,因为以下代码导致“在super.init调用之前自行使用”

override init(frame: CGRect) {
    self.initialize()
    super.init(frame: frame)
}

required init(coder aDecoder: NSCoder) {
    self.initialize()
    super.init(coder: aDecoder)
}
var X : Int

override init(frame: CGRect) {
    super.init(frame: frame)
    self.initialize()
}

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    self.initialize()
}
将self.initial放在super.init之后也没有帮助,因为我的全部目的就是初始化成员。以下情况将导致“属性self.X未在super.init调用时初始化”

override init(frame: CGRect) {
    self.initialize()
    super.init(frame: frame)
}

required init(coder aDecoder: NSCoder) {
    self.initialize()
    super.init(coder: aDecoder)
}
var X : Int

override init(frame: CGRect) {
    super.init(frame: frame)
    self.initialize()
}

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    self.initialize()
}

如果我想在这种情况下考虑公共初始化,我应该怎么做?请注意,我特别不想使用awakeFromNib,因为我希望我的对象在对象层次结构中的任何相关awakeFromNib实现中都可用。还要注意,选项对我的用例没有意义。

最明显的答案是在调用
super.init
之后调用
initialize

override init(frame: CGRect) {
    super.init(frame: frame)
    self.initialize()
}
但是,您可能需要在
initialize
方法中初始化一些实例变量。事实是:

  • 在调用
    super
    之前,必须初始化所有成员变量
  • 在调用
    super.init
    之前,不能调用
    self
    上的方法(或访问
    self
    上的计算属性)
  • 不可避免的结论是,如果您有要在
    initialize
    中初始化的实例变量,则必须使用
    var
    声明每个此类变量,而不是
    let
    ,并执行以下操作之一:

  • 为实例变量指定默认值:

    var name: String = "Fred"
    
  • 将实例变量
    设置为可选
    ,并将其初始化为nil:

    var name: String?
    
    var name: String!
    
  • 将实例变量
    隐式地设置为appedoptional
    ,并将其初始化为nil:

    var name: String?
    
    var name: String!
    

  • 在这一点上,我的偏好是#2(将其设置为
    可选,并初始化为nil)。

    这里有一个简洁的解决方案:

    基本上,标记两个init函数
    便利性
    ,然后让它们调用第三个
    私有
    init函数,该函数具有您的通用初始化代码

    对于您的情况,您可以使用以下内容:

    class MyView: UIView {
    
        let X: Int // No need to use an optional, as we assign this in an initializer
    
        enum InitMethod {
            case Coder(NSCoder)
            case Frame(CGRect)
        }
    
        override convenience init(frame: CGRect) { // Marking as convenience let's us call out to another constructor
            self.init(.Frame(frame))!
        }
    
        required convenience init?(coder aDecoder: NSCoder) { // Marking as convenience let's us call out to another constructor
            self.init(.Coder(aDecoder))
        }
    
        private init?(_ initMethod: InitMethod) {
            // You can put your common initialization code here:
            X = 1
    
            switch initMethod {
                case let .Coder(coder): super.init(coder: coder)
                case let .Frame(frame): super.init(frame: frame)
            }
        }
    }
    

    这是针对我想要一个非可选变量的情况。在这种情况下,唯一的解决方案似乎是使用默认值。然而,这并不包括违约之间相互依存的情况。例如,如果我有一个非可选Y,它取决于非可选X的默认值是什么?实例变量的初始值设定项表达式(在变量声明中)不能引用
    self
    、任何其他实例变量或任何
    init
    参数。事情就是这样。是的,它很糟糕。所以,如果你想使用非可选的,某些功能是根本不可能的。您必须调整您的类型选择,使之成为您从未真正想要的,只是为了与语言限制保持一致。这些情况的存在也意味着,有时候,在重构或添加功能时,您需要将非可选项更改为可选项,以使其正常工作。因此,在这种情况下,人们最终只会使用optionals,即使是那些总是有保证的东西。就像我说的,这很糟糕。好吧,你能在你的答案中添加关于它如何糟糕的部分,然后我会接受它。基本上,答案是对于所提到的用例没有很好的答案。请为这个特定的问题提供一个解决方案