私はSwiftに次のような単純なPerson
クラスがあります:
class Person {
var name = "John Doe"
var age = 18
var children = [Person]?
\\ init function goes here, but does not initialize children array
}
children
をオプションの配列として宣言する代わりに、次のように宣言して空の配列として初期化するだけです。
var children = [Person]()
私はどちらのアプローチがより良いかを決定しようとしています。配列をオプションの配列として宣言すると、メモリをまったく使用しなくなりますが、空の配列には少なくともある程度のメモリが割り当てられますか?したがって、オプションの配列を使用すると、少なくともある程度のメモリが節約されます。私の最初の質問は次のとおりだと思います:実際にメモリの節約が実際に行われているのですか、それとも私の想定が間違っているのでしょうか。
一方、それがオプションの場合、それを使用しようとするたびに、オブジェクトを追加または削除する前に、それがnil
かどうかを確認する必要があります。したがって、そこには効率のいくらかの損失があります(しかし、私は想像しますが、それほどではありません)。
私はオプションのアプローチが好きです。すべてのPerson
に子供がいるわけではないので、children
が定住して家族を養うことを決定するまで、nil
をPerson
にしないでください。
とにかく、どちらか一方のアプローチに他の特定の利点または欠点があるかどうかを知りたいです。それは何度も何度も出てくるデザインの問題です。
空の配列またはオプションのいずれかを選択する機能により、セマンティックの観点からデータをより適切に説明する配列を適用できます。
私は選択します:
いくつか例を挙げましょう。
私の意見は、コードをより明確で自明にすることのみに関するものであることに注意してください。どちらのオプションを選択しても、パフォーマンス、メモリ使用量などに関して、大きな違いはないと思います。
私はヨルディから反対のケースを作るつもりです-「この人には子供がいません」と明確に言うのと同じように空の配列は、あなたに面倒のトンを節約します。 children.isEmpty
は、子供の存在を簡単に確認できるため、予期しないnil
を解いたり心配したりする必要はありません。
また、メモとして、何かをオプションとして宣言することは、スペースがゼロになることを意味しません。これは、.None
のOptional<Array<Person>>
の場合です。
興味深いことに、私たちは最近、この非常に同じ問題について職場でほとんど議論していません。
微妙な意味の違いがあることを示唆する人もいます。例えば。 nil
は、子供がいないことを意味しますが、0
はどういう意味ですか?それは「子供がいる、それらの0全体」を意味しますか?私が言ったように、純粋なセマンティクス "0の子を持っている"および "子を持たない"このモデルをコードで操作する場合、違いはありません。その場合は、もっと簡単でガードレスなアプローチを選ばないのはなぜですか?
nil
を保持することを示唆する人もいます。たとえば、バックエンドからモデルを取得するときに、何かがうまくいかず、子ではなくエラーが発生したことを示している可能性があります。しかし、私はモデルがこのタイプのセマンティクスを持たないようにし、nil
を過去のエラーの指標として使用しないでください。
私は個人的に、モデルは可能な限りダムである必要があり、この場合のdumbestオプションは空の配列です。
オプションがあると、その?
を最後までドラッグして、guard let
、if let
、または??
を繰り返し使用できます。
NSCoding
実装には追加のアンラップロジックが必要です。モデルをビューコントローラーに表示するときは、単純なperson.children?.count ?? 0
ではなくperson.children.count
を実行する必要があります。
これらすべての操作の最終目標は、UIに何かを表示することです。本当に言いますか
nil
の「この人には子供がいません」と「この人には子供がいない」と空の配列は対応していますか?私はあなたがそうしないことを望みます:)
最後に、これは本当に私が持っている最も強い議論です
subviews
のUIView
プロパティのタイプは何ですか: それはvar subviews: [UIView] { get }
ですchildren
のSKNode
プロパティのタイプは何ですか: それはvar children: [SKNode] { get }
ですCocoaフレームワークには、 UIViewController :: childViewControllers などの例がたくさんあります。
純粋なSwift world: Dictionary :: keys からでも、これは少し遠いかもしれませんが。
人がnil
の子を持つことはできても、SKNode
はできないのはなぜですか?私にとっては、類推は完璧です。ねえ、SKNode
のメソッド名もchildren
です:)
私の見解:これらの配列を本当に良いもののようにオプションとして保持する明らかな理由があるはずです。そうでなければ、空の配列は同じセマンティクスを提供し、アンラップを少なくします。
最後に、非常に良い記事へのいくつかの参照、それらのそれぞれ
Natashaの投稿には、NSHipsterのブログ投稿への リンクがあり 、Swiftificationの段落には、この:
たとえば、NSArrayの戻り値をnull可能としてマークする代わりに、多くのAPIは空の配列を返すように変更されています。つまり、これらは同じ値(つまり、何もない)ですが、オプションではない配列の方がはるかに簡単に処理できます。
時々、存在しないものと空であることに違いがあります。
ユーザーが電話番号のリストを変更できるアプリがあり、その変更をmodifiedPhoneNumberList
として保存するとします。変更が発生していない場合、配列はnilになります。ユーザーが解析済みの数値を削除して変更した場合、すべての配列は空になります。
空は既存の電話番号をすべて削除することを意味し、nilは既存の電話番号をすべて保持することを意味します。違いはここで重要です。
プロパティが空であるか存在しないかを区別できない場合、または空であるかどうかが問題ではない場合は、次の方法に進みます。 Person
が唯一の子を失う場合、count
が1であるかどうかを確認するのではなく、その子を削除して空の配列を作成するだけで、配列全体をnil
に設定する必要があります。
私はいつも空の配列を使います。
私の控えめな意見では、Swiftでのオプションの最も重要な目的は、nilの可能性があるいくつかの値を安全にラップすることです。配列はすでにこのタイプのラッパーとして機能しています-配列を確認できます内部に何かがあり、forループやマッピングなどでその値に安全にアクセスします。ラッパー内にラッパーを配置する必要がありますか?そうは思いません。
Swiftはオプションの値とオプションのアンラップを利用するように設計されています。
couldは、配列をnilとして宣言します。これにより、非常に小さな(ほとんど気づかない)量のメモリが節約されます。 。
Swiftのデザインパターンを満足させるために、nil値を表す配列の代わりにオプションの配列を使用します:)
私も思います
if let children = children {
}
よりもよさそうだ:
if(children != nil){
}