[解決済み] Swiftで失敗しないイニシャライザーを実装するためのベストプラクティス
質問
以下のコードで、シンプルなモデルクラスと、(json-)辞書をパラメータとする失敗しないイニシャライザーを定義しようと思います。イニシャライザーは
nil
を返すようにします。
1. なぜコードがコンパイルされないのですか?エラーメッセージにはこうあります。
クラスインスタンスの保存されたプロパティは、イニシャライザからnilを返す前にすべて初期化する必要があります。
それは意味がありません。を返す予定なのに、なぜこれらのプロパティを初期化しなければならないのでしょうか?
nil
?
2. 私のアプローチは正しいのでしょうか、それとも私の目標を達成するために他のアイデアや共通のパターンがあるのでしょうか?
class User: NSObject {
let userName: String
let isSuperUser: Bool = false
let someDetails: [String]?
init?(dictionary: NSDictionary) {
if let value: String = dictionary["user_name"] as? String {
userName = value
}
else {
return nil
}
if let value: Bool = dictionary["super_user"] as? Bool {
isSuperUser = value
}
someDetails = dictionary["some_details"] as? Array
super.init()
}
}
どのように解決するのですか?
更新しました。 より Swift 2.2 変更履歴 (2016年3月21日リリース)を参照してください。
failable または throwing と宣言された指定クラスイニシャライザーは、オブジェクトが完全に初期化される前に、それぞれ nil を返したり、エラーをスローしたりすることができるようになりました。
Swift 2.1 以前のバージョン用です。
Appleのドキュメント(とコンパイラーエラー)によると、クラスは、その保存されたプロパティをすべて初期化してから
nil
を返す前に、すべての保存されたプロパティを初期化しなければなりません。
しかし、クラスでは、フェイルイニシャライザは、そのクラスによって導入されたすべての保存されたプロパティの後にのみ、初期化の失敗を引き起こすことができます。 初期化の失敗を引き起こすことができるのは、そのクラスによって導入されたすべての保存されたプロパティが初期値に設定された後だけです。 そのクラスによって導入されたすべての保存されたプロパティが初期値に設定され、すべてのイニシャライザーの委譲が行われた後にのみ、初期化の失敗を引き起こすことができます。 の委譲が行われた後でのみ、初期化の失敗を引き起こすことができます。
注意 実際には、構造体や列挙についてはうまく動作しますが、クラスについてはそうではありません。
イニシャライザーが失敗する前に初期化できないストアドプロパティを処理するために提案された方法は、暗黙的にラップされていないオプショナルとしてそれらを宣言することです。
docsからの例です。
class Product {
let name: String!
init?(name: String) {
if name.isEmpty { return nil }
self.name = name
}
}
上記の例では、Product クラスの name プロパティは は暗黙のうちにアンラップされたオプションの文字列型を持つものとして定義されています。 (String!)と定義されています。オプション型であるため、これは、name プロパティは、初期化時に特定の値が割り当てられる前に、デフォルト値として nil を持つことを意味します。 を持つことになります。このnilというデフォルト値は、つまり このnilというデフォルト値は、Productクラスが導入するすべてのプロパティが有効な初期値を持つことを意味します。 有効な初期値を持っていることを意味します。その結果、Product のフェイル可能なイニシャライザ のフェイル可能なイニシャライザは、イニシャライザの開始時に初期化の失敗を引き起こすことができます。 に特定の値を代入する前に、空文字列が渡された場合、初期化の失敗を引き起こすことができます。 イニシャライザー内の name プロパティに特定の値を割り当てる前に
しかし、あなたの場合、単に
userName
を
String!
としても、コンパイルエラーは修正されません。なぜなら、ベース・クラスのプロパティの初期化についてまだ心配する必要があるからです。
NSObject
. 幸いなことに
userName
として定義されています。
String!
として定義されている場合、実際に呼び出すことができるのは
super.init()
の前に
return nil
を開始します。
NSObject
を初期化し、コンパイルエラーを修正します。
class User: NSObject {
let userName: String!
let isSuperUser: Bool = false
let someDetails: [String]?
init?(dictionary: NSDictionary) {
super.init()
if let value = dictionary["user_name"] as? String {
self.userName = value
}
else {
return nil
}
if let value: Bool = dictionary["super_user"] as? Bool {
self.isSuperUser = value
}
self.someDetails = dictionary["some_details"] as? Array
}
}
関連
-
[解決済み] SwiftからObjective-Cのコードを呼び出すにはどうしたらいいですか?
-
[解決済み] Swiftで#pragmaマーク?
-
[解決済み] Swift 3でカスタム通知を作成するには?
-
[解決済み] Swiftのリバースレンジ
-
[解決済み] Swift - 複数条件でオブジェクトの配列を並べ替える
-
[解決済み] 固定サイズのオブジェクトの配列を作成する方法
-
[解決済み] ビルド入力ファイルが見つかりません」Swift 4.2、Xcode 10.0
-
[解決済み] Optional Boolの値をチェックする
-
[解決済み] Swiftの数学関数
-
[解決済み] SwiftUIでビューを動的に隠す
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Swift の Optional 値 && Optional のアンラップ時に予期せず nil が検出された場合の説明
-
[解決済み] Swift: インデックスで文字列配列を置換する
-
[解決済み] プロパティの型が内部型を使用しているため、publicを宣言することができない
-
[解決済み] Swiftの変数に"?"(クエスチョンマーク)と"!"(エクスクラメーションマーク)の装飾を施す。
-
[解決済み] SwiftUIのForEachでインデックスを取得する
-
[解決済み] Swift- Remove Push Notification Badge number?
-
[解決済み] swiftでオプションのクロージャを作るにはどうしたらいいですか?
-
[解決済み] SwiftUIでビューを動的に隠す
-
[解決済み] XcodeでFirebase Analyticsをオンにする
-
[解決済み] NSDateを使用して曜日を取得する