0

私はUIViewControllerサブクラスを持っています。遅延ロードしたい定数があります。これを行うには、関数を使用してデフォルト値を設定しました。以前は値を設定するためにそれらを使用していたので、ここに 2 つのinitメソッドがあります。次に、値を設定するための一般的なメソッドを呼び出すことができないことがわかりました。クラス定数の値を設定できるのは init メソッドだけのようです。デフォルト値を設定する関数を作成したとき、init(nibName, bundle) 関数から目的の関数を繰り返し呼び出す無限ループがあることがわかりました。私はswiftが初めてで、何が間違っているのかわかりません。

class ViewController: UIViewController {

  let goal: Goal =
  {
    return Goal()
  }()

  override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)
  {
    super.init()
  }

  required init(coder decoder: NSCoder)
  {
    super.init()
  }
}
4

1 に答える 1

1

メソッドをオーバーライドするときは、このメソッドのスーパー実装を呼び出す必要があります。

required override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
  super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}

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

let数値は初期化子でのみ設定できます。複数の初期化子がある場合は、それらを連鎖させる方法を考えてください。1 つの指定された初期化子と多くの便利さがあると便利です。このようにして、変数を 1 か所だけに設定します。

class A {

  let age: Int
  let name: String
  let type: String

  init(age: Int, name: String, type: String) {
    self.age = age
    self.type = type
    self.name = name
  }

  convenience init() {
    self.init(age: 0, name: "", type: "")
  }
  convenience init(age: Int) {
    self.init(age: age, name: "", type: "")
  }
  convenience init(age: Int, name: String) {
    self.init(age: age, name: name, type: "")
  }

Swift では、init メソッドでクラスを完全に初期化する必要があります。これは、すべてのプロパティに値を設定し、存在する場合は super init を呼び出す必要があることを意味します。その後、自分自身にアクセスしてメソッドを呼び出すことができます。

Cocoa フレームワークでは、クラスをインスタンス化する方法が 1 つ以上あり、多くの初期化子があります。例 UIViewController には
init(nibName: String?, bundle: NSBundle?)init(coder :NSCoder) このクラスをどのように初期化しますか?

  1. 変数の値を設定する

このソリューションには 1 つの大きな欠点があります。DRY
ではありません 。2 つの場所に同じコードがあります。変更または修正する必要がある場合は、2 か所で同じ操作を行う必要があります。本当に悪いアーキテクチャとコードの匂い。

var name: String

  required init(coder aDecoder: NSCoder) {
    name = "Name"
    super.init(coder: aDecoder)    
  }

  override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
    name = "Name"
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
  }

もっとうまくやれるでしょうか?解決策は明白に見えます-別の方法で名前の初期化を抽出します。しかし、 Swift クラスの安全規則の初期化ステップのため、それはできません。

  1. すべてのプロパティを設定する
  2. super.init(...) を呼び出す
  3. これで、クラスとスーパー クラスの両方が完全に初期化されました。ここでのみ、自分自身にアクセスして自分自身のメソッドを呼び出すことができます

コード:

 required init(coder aDecoder: NSCoder) {
    setDefaultName() // Error. Can't access self yet
    super.init(coder: aDecoder)
  }

 func setDefaultName() {
    name = "Name"
  }
  1. デフォルト値

変数のデフォルト値を設定します。
プロパティを 1 か所だけで初期化するため、これは見栄えがよくなります。

 var name: String = ""

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

  override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
  }

変数を初期化するためにより複雑なロジックが必要な場合は、そのためにクロージャーを使用できます。
クラス変数宣言にロジック(関数と同じクロージャー)があるため、私はそれが好きではありません。
もっとうまくやれるでしょうか?はい、できます!

 var name: String = {
    var name = "Name"
    // ....
    // Other complicated logic
    name + " Is Best"
    return name
  }()
  1. ファクトリ メソッド

そのクロージャーをクラス変数定義の外に移動する方が良い
ので、そのようなことができますvar name = Factory.defaultName()

Swift は内部クラスをサポートします。クラスの中にクラスを作成できます。このようにして、クラス内でいくつかの機能をグループ化できます。これは、初期化メソッドを Factory クラスにグループ化するのに最適なサウンド
です 最終的な例:

var name: String = Factory.defaultName()

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

  override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
  }


  class Factory {
    class func defaultName () -> String {
      return "Name"
    }
  }
于 2014-10-19T15:13:06.130 に答える