Swift3.0-プロパティ、プロパティオブザーバ
7694 ワード
ツールバーの
プロパティは、値を特定のクラス、構造、または列挙に関連付けます.
ストレージのプロパティ
簡単に言えば、1つのストレージ属性は、特定のクラスまたは構造体インスタンスに格納される定数または変数です.記憶属性は、変数記憶属性(キーワード
var
で定義)であってもよく、定数記憶属性(キーワードlet
で定義)であってもよい.ストレージ属性を定義するときにデフォルト値を指定できます.また、構築中にストレージ属性の値を設定または変更することもできます.
struct FixedLengthRange {
var firstValue: Int
let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// 0,1,2
rangeOfThreeItems.firstValue = 6
// 6,7,8
FixedLengthRange
の例は、firstValue
という変数記憶属性と、length
という定数記憶属性とを含む.上記の例では、length
はインスタンスの作成時に初期化され、定数記憶属性であるため、その後の値は変更できません.定数構造体のストレージプロパティ
構造体のインスタンスを作成して定数に値を割り当てると、そのインスタンスのプロパティは変更できません.変数として宣言されたプロパティがあっても、変更できません.
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// 0,1,2,3
rangeOfFourItems.firstValue = 6
// firstValue ,
rangeOfFourItems
が定数として宣言されているため(let
キーワードで)、firstValue
が変数属性であっても変更できません.この挙動は構造体(struct)が値タイプに属するためである.値タイプのインスタンスが定数として宣言されると、そのすべてのプロパティが定数になります.
参照タイプに属するクラス(class)は異なります.参照タイプのインスタンスを定数に割り当てると、インスタンスの変数プロパティを変更できます.
遅延ストレージ属性(怠惰ロード)
遅延ストレージ属性とは、最初に呼び出されたときにその初期値が計算される属性です.属性宣言の前に
lazy
を使用して、遅延ストレージ属性を表示します.注意:属性の初期値は、インスタンス構築が完了した後に得られる可能性があるため、遅延記憶属性は変数として宣言する必要があります(
var
キーワードを使用します).定数属性は、構築プロセスが完了する前に初期値が必要であるため、遅延属性として宣言できません.遅延プロパティは、インスタンスの構築プロセスが終了してから値に影響する外部要因がわかるようにプロパティの値に依存する場合や、プロパティの初期値を取得するのに複雑または大量の計算が必要な場合にのみ計算できます.
class DataImporter {
var fileName:String? = "data.txt"
init() {
print(" DataImporter")
}
}
class DataManager {
lazy var importer = DataImporter()
var data = [String]()
}
let manager = DataManager()
manager.importer.fileName = "fileName" // print: DataImporter
OCでのダラダラロードはnilか否かを判断し、nilであれば作成するが、Swiftでlazyタグを用いた属性は初めてアクセスされたときのみ作成される.
注意
lazy
とマークされた属性が初期化されていない場合、同時に複数のスレッドにアクセスされる場合、その属性が一度だけ初期化されることは保証されません.計算プロパティ
クラス、構造体、列挙は、ストレージ属性に加えて計算属性を定義できます.計算プロパティは、値を直接格納するのではなく、getterとオプションのsetterを提供して、他のプロパティまたは変数の値を間接的に取得および設定します.
struct Point { //
var x = 0.0, y = 0.0
}
struct Size { //
var width = 0.0, height = 0.0
}
struct Rect { //
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set(newCenter) {
origin.x = newCenter.x - (size.width / 2)
origin.y = newCenter.y - (size.height / 2)
}
}
}
var square = Rect(origin: Point(x: 0.0, y: 0.0),
size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)
この例では、ジオメトリを記述する3つの構造体を定義します.
Point
は、(x, y)
の座標Size
は、1つのwidth
および1つのheight
Rect
は、原点および寸法を有する矩形Rect
はまた、center
という計算属性を提供する.長方形の中心点は、原点(origin
)およびサイズ(size
)から算出できるので、明示的に宣言されたPoint
で保存する必要はない.Rect
の計算プロパティcenter
は、矩形の中心点を取得および設定するためのカスタムgetterおよびsetterを提供し、記憶プロパティがあるようにします.便利setter宣言
計算属性のsetterが新しい値を表すパラメータ名を定義していない場合は、デフォルト名
newValue
を使用します.以下は、便利なsetter宣言を使用したRect
構造体コードです.struct AlternativeRect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
}
}
読み取り専用計算プロパティ
getterにsetterがない計算属性だけが読み取り専用計算属性です.読み取り専用計算プロパティは、ポイント演算子でアクセスできる値を常に返しますが、新しい値を設定することはできません.
注意:値が固定されていないため、
var
キーワードを使用して計算プロパティを定義する必要があります.let
キーワードは定数属性を宣言するためにのみ使用され、初期化後に変更できない値を示します.読み取り専用計算プロパティの宣言により、
get
のキーワードとカッコを削除できます.struct Cuboid {
var width = 0.0, height = 0.0, depth = 0.0
var volume: Double {
// get {
return width * height * depth
// }
}
}
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
// "the volume of fourByFiveByTwo is 40.0"
この例は、
Cuboid
、width
、およびheight
の属性を含む3次元空間を表す立方体を定義する.構造体には、立方体のボリュームを返すためにdepth
という読み取り専用計算プロパティもあります.volume
にsetterを提供することは、volume
、width
、height
、およびdepth
の3つの値をどのように変更して新しいvolume
に一致するかを決定することができないため、意味がありません.しかしながら、Cuboid
は、外部ユーザが直接ボリュームを取得するために読み取り専用計算属性を提供することが有用である.属性オブザーバ
アトリビュートオブザーバは、アトリビュート値の変化を監視し、応答します.アトリビュート値が設定されるたびにアトリビュートオブザーバが呼び出されます.新しい値と現在の値が同じ場合でも例外ではありません.
遅延ストレージ属性以外のストレージ属性に属性オブザーバを追加するか、継承した属性(ストレージ属性と計算属性を含む)を書き換えることで属性オブザーバを追加できます.書き換えられていない計算プロパティにプロパティオブザーバを追加する必要はありません.setterによって値の変化を直接監視し、応答することができます.
アトリビュートに次の1つまたはすべてのオブジェクトを追加できます.
willSet
新しい値が設定前にdidSet
は、新しい値が設定された直後にwillSet
オブザーバは、新しい属性値を定数パラメータとして入力し、willSet
のインプリメンテーションコードでこのパラメータの名前を指定できます.指定しない場合、パラメータは使用できます.この場合、デフォルトの名前newValue
で表されます.同様に、
didSet
オブザーバは、古い属性値をパラメータとして入力し、このパラメータに名前を付けるか、デフォルトのパラメータ名oldValue
を使用することができます.didSet
メソッドでプロパティに再び値を割り当てると、新しい値は古い値を上書きします.親のプロパティが子クラスのコンストラクタに割り当てられている場合、親クラスの
willSet
およびdidSet
オブザーバが呼び出され、その後、子クラスのオブザーバが呼び出されることに注意してください.親初期化メソッドが呼び出される前に、サブクラスがプロパティに値を割り当てると、オブザーバは呼び出されません.次に、
willSet
およびdidSet
が実際に使用された例を示し、StepCounter
というクラスが定義され、1人の歩行時の総歩数を統計するために使用される.このクラスは、歩数計や他の日常的なトレーニングの統計装置の入力データと組み合わせて使用することができます.class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("totalSteps \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print(" \(totalSteps - oldValue) ")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// print: totalSteps 200
// print: 200
stepCounter.totalSteps = 360
// print: totalSteps 360
// print: 160
stepCounter.totalSteps = 896
// print: totalSteps 896
// print: 536
StepCounter
クラスは、Int
およびtotalSteps
オブザーバを含むストレージ属性であるwillSet
タイプの属性didSet
を定義する.totalSteps
が新しい値を設定されると、willSet
とdidSet
のオブザーバが呼び出され、新しい値と現在の値が完全に同じであっても呼び出されます.例の
willSet
オブザーバは、新しい値を表すパラメータをnewTotalSteps
にカスタマイズし、このオブザーバは単純に新しい値を出力するだけである.didSet
オブザーバは、totalSteps
の値が変更された後に呼び出され、新しい値と古い値を比較し、総ステップ数が増加した場合、どのくらい増加したかを示すメッセージを出力します.didSet
は古い値にカスタム名を指定していないので、デフォルト値oldValue
は古い値のパラメータ名を表します.に注意
属性がin-out方式で関数に入力されると、
willSet
およびdidSet
も呼び出されます.これは、in-outパラメータがコピーコピーモードを採用しているためです.すなわち、関数内部でパラメータのcopyが使用され、関数が終了した後、パラメータに値を再割り当てします.func change( a: inout Int) {
a += 1
}
change(a: &stepCounter.totalSteps)
// totalSteps 897
// 1