【问题标题】:Swift: Subclassing UITextView or UICollectionView and proper initializationSwift:继承 UITextView 或 UICollectionView 并正确初始化
【发布时间】:2014-06-29 14:38:36
【问题描述】:

子类化 UITextView(和 UICollectionView)的问题是指定的构造函数是“initWithFrame”。但在现实生活中,当它从 storyboard 加载时,会调用 initWithCoder。

class BorderedTextView: UITextView {
    //will be called
    init(coder: NSCoder?){
       //constant values here is not an option
       super.init(frame: CGRectMake(0,0,100,100), textContainer: nil)
    }
    //will not be called
    init(frame: CGRect, textContainer: NSTextContainer!) {
        super.init(frame: frame, textContainer: textContainer)
    }
}

因此,我无法在 init 上调用任何 UI 自定义代码并为 Swift 变量提供任何初始化值,但默认值除外。

我想这个问题可以通过从“coder”中提取帧大小来临时解决,但是我没有找到它的关键。

有什么比硬编码帧值更好的想法吗?

【问题讨论】:

  • 我希望super.init(coder: coder) 可以工作——并且对于 UIView 或 UILabel 的子类它可以(至少编译器不会抱怨)。但是对于UITextView 的子类,它会失败并显示错误消息“必须调用指定的初始化程序...”。一个 Swift 错误?
  • 一种可能的解决方法是在 awakeFromNib 中进行初始化。
  • 没错,看起来它适用于 UIView(我更新了问题)。但是我对 UICollectionView 也有同样的问题,所以问题不仅在于 UITextView。
  • 不同之处似乎在于 UITextView 和 UICollectionView 都有自己的“自己的”指定初始化程序(与例如 UILabel 相比)。我仍然认为这是一个 Swift 错误(应该向 Apple 报告),因为相同的模式在 Objective-C 中也适用。
  • 提交给苹果。感谢awakeFromNib 的解决方法,它完全符合我目前的要求。

标签: ios uiview uitextview swift


【解决方案1】:

(来自我上面的 cmets:) 这看起来像一个 Swift 错误。 initWithCoder: 被调用时 视图(或视图控制器)从 Storyboard 或 Nib 文件中实例化,并覆盖 该方法在 Objective-C 中有效:

- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        // Initialization code
    }
    return self;
}

但等效的 Swift 代码

class BorderedTextView: UITextView {
    init(coder: NSCoder!) {
        super.init(coder: coder)
    }
}

失败并显示错误消息“必须调用超类 'UITextView' 的指定初始化程序”。

UIView 的所有子类都会出现此问题 他们自己指定的初始化程序(例如UITextViewUICollectionView)。 另一方面,UILabel 的子类不会出现该问题, 没有指定的初始化器。 Swift 语言对于调用超类的指定初始化器非常严格, 但是应该有一种方法可以为所有自定义 UIView 子类覆盖 initWithCoder:,所以我认为这是一个 Swift 错误。

作为一种解决方法,您可以在

中进行自定义初始化
override func awakeFromNib() {
    super.awakeFromNib()
    // ...
}

Swift 1.2 更新: 这显然已得到修复。参数 改变了,它不再是一个隐式展开的可选项。所以这 按预期编译和工作(使用 Xcode 6.4 测试):

class BorderedTextView: UITextView {
    required init(coder: NSCoder) {
        super.init(coder: coder)

        // ...
    }
}

Swift 2 (Xcode 7) 的更新: init(coder:) 是失败的 现在初始化:

class BorderedTextView: UITextView {
    required init?(coder: NSCoder) {
        super.init(coder: coder)

        // ...
    }
}

【讨论】:

    【解决方案2】:

    Swift 3 的更完整答案:

    class ValidatedTextField:UITextField, UITextFieldDelegate
    {
        required override init(frame: CGRect)
        {
            super.init(frame: frame)
            //custom code
            self.delegate = self
        }
    
        required init?(coder: NSCoder)
        {
            super.init(coder: coder)
            //custom code
            self.delegate = self
        }
    

    【讨论】:

    • OP 询问的是 UITextView 而不是 UITextField。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    相关资源
    最近更新 更多