【问题标题】:How to pass value to superclass's init bypassing the designated initalizer that is required by its superclass?如何绕过超类所需的指定初始化程序将值传递给超类init?
【发布时间】:2016-02-03 10:38:40
【问题描述】:

我有一个继承UITableViewCell 的基类,它声明了一个变量来存储类型值,该类型值将在init 和其他函数中使用:

class CellBase: UITableViewCell {
    var type: Int
    init(theType: Int) {
        type = theType
        if (type == 100) {  // more init code based on 'type'
        } else {  
        }
    } 
    // other functions
}

我有继承CellBase的子类:

class Cell1: CellBase {
    init() {
        super.init(type: 100)
    }
}
class Cell2: CellBase {
    init() {
        super.init(type: 200)
    }
}

我想将type 的值传递给CellBase。但是我想不出办法来做到这一点。 XCode 显示一些错误:

'required'初始化器'init(coder:)'必须由'UITableViewCell'的子类提供

如果我修改代码以覆盖所需的初始化程序:

class CellBase2 : UITableViewCell {
    var type: Int

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

我无法将类型值从子类传递给CellBase。如何解决这个问题?

【问题讨论】:

  • 如果单元格是从 NIB 中解压缩的,您将如何提供类型?你可以吗?因此fatal error...
  • @Wain 我没有使用 NIB。所有视图都是以编程方式创建的。我的问题不在于fatalError。谢谢。
  • 重点是您已经有了解决问题的代码

标签: swift


【解决方案1】:

Vadian 打败了我,但由于我已经编写了代码,这里有一个替代方案,在子类中有两个不同的自定义初始化器,并在超类中为 type 使用惰性变量。这里实际上并不需要惰性 var,但为了避免在 aDecoder init 中也必须初始化 type(除非你在那里使用 fatalError),你可以确保所有非惰性/非CellBase 中的计算属性使用默认值进行初始化。

超类:

class CellBase: UITableViewCell {
    var defaultType = 100
    lazy var type: Int = { return self.defaultType }()

    init(reuseIdentifier: String?, theType: Int) {
        defaultType = theType

        super.init(style: .Default, reuseIdentifier: reuseIdentifier)

        if (type == 100) {  // more init code based on 'type'
            print("Intialized Cell1")
        }
        else {
            print("Intialized Cell2")
        }
    }

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

子类:

/* Style: .Default */
class Cell1: CellBase {

    /* Allow for caller to specify reuse identifier */
    init(reuseIdentifier: String?) {
        super.init(reuseIdentifier: reuseIdentifier, theType: 100)
    }

    /* No reuse identifier (nil) */
    init() {
        super.init(reuseIdentifier: nil, theType: 100)
    }

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

class Cell2: CellBase {
    init(reuseIdentifier: String?) {
        super.init(reuseIdentifier: reuseIdentifier, theType: 200)
    }

    init() {
        super.init(reuseIdentifier: nil, theType: 200)
    }

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

示例用法:

let c1A = Cell1(reuseIdentifier: "SomeCell1")   // "Intialized Cell1"
let c1B = Cell1()                               // "Intialized Cell1"
let c2A = Cell2(reuseIdentifier: "SomeCell2")   // "Intialized Cell2"
let c2B = Cell2()                               // "Intialized Cell2"

【讨论】:

  • 该单元格最终被registerClassdequeueReusableCellWithIdentifier 使用。我想知道是否需要任何修改/调整?
【解决方案2】:

由于您必须调用 init(style:reuseIdentifier:),因此声明一个包含您的参数的自定义 init 方法并调用指定的初始化程序

class CellBase: UITableViewCell {
  var type: Int

  init(style: UITableViewCellStyle, reuseIdentifier: String?, type: Int) {
    self.type = type
    super.init(style: style, reuseIdentifier: reuseIdentifier)
  }

  required init?(coder aDecoder: NSCoder) {
      fatalError("init(coder:) has not been implemented")
  }
  // other functions
}

class Cell1: CellBase {

  init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier, type: 100)
  }

  required init?(coder aDecoder: NSCoder) {
      fatalError("init(coder:) has not been implemented")
  }
}

let cell = Cell1(style: .Default, reuseIdentifier: "cell1")
cell.type // 100

【讨论】:

  • 是否可以在 Cell1 类中创建(style: .Default, reuseIdentifier: "cell1", type: 100)?是否可以不指定.Default"cell1"? (因为单元格最终被dequeueReusableCellWithIdentifier使用)
  • 非常感谢。但我仍然对一件事感到困惑。由于单元格最终被dequeueReusableCellWithIdentifier使用。我之前从未指定style: .DefaultresueIndentifier: "cell1",是否可以不指定它们?
  • 如果单元格是在 Interface Builder 中设计的,则使用适当的设置调用初始化程序。
  • 该单元不是在 IB 中设计的。我的应用中没有使用 IB。
  • 您可以在超级传递自定义默认参数中调用指定的初始化程序,就像 dfri 在他的回答中部分所做的那样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-12
  • 2016-06-30
  • 2016-03-11
  • 2016-05-10
  • 1970-01-01
相关资源
最近更新 更多