自動参照カウント
日本語を消す 英語を消す下記URLから引用し、日本語訳をつけてみました。
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/automaticreferencecounting
Model the lifetime of objects and their relationships.
オブジェクトの存続期間とその関係をモデル化します。
Swift uses Automatic Reference Counting (ARC) to track and manage your app’s memory usage. In most cases, this means that memory management “just works” in Swift, and you don’t need to think about memory management yourself. ARC automatically frees up the memory used by class instances when those instances are no longer needed.
Swift は、自動参照カウント (ARC) を使用して、アプリのメモリ使用量を追跡および管理します。 ほとんどの場合、これはメモリ管理が Swift で「そのまま機能する」ことを意味し、メモリ管理について自分で考える必要はありません。 ARC は、クラス インスタンスが不要になったときに、クラス インスタンスによって使用されていたメモリを自動的に解放します。
However, in a few cases ARC requires more information about the relationships between parts of your code in order to manage memory for you. This chapter describes those situations and shows how you enable ARC to manage all of your app’s memory. Using ARC in Swift is very similar to the approach described in Transitioning to ARC Release Notes(Link:developer.apple.com) for using ARC with Objective-C.
ただし、場合によっては、ARC がメモリを管理するために、コードの各部分間の関係に関する詳細な情報が必要になります。 この章では、これらの状況について説明し、ARC を有効にしてアプリのすべてのメモリを管理する方法を示します。 Swift での ARC の使用は、Objective-C で ARC を使用するための ARC リリースノートへの移行(Link:developer.apple.com)(英語)で説明されているアプローチと非常に似ています。
Reference counting applies only to instances of classes. Structures and enumerations are value types, not reference types, and aren’t stored and passed by reference.
参照カウントはクラスのインスタンスにのみ適用されます。 構造体と列挙型は参照型ではなく値型であり、参照によって保存されたり渡されたりしません。
How ARC Works
ARC の仕組み
Every time you create a new instance of a class, ARC allocates a chunk of memory to store information about that instance. This memory holds information about the type of the instance, together with the values of any stored properties associated with that instance.
クラスの新しいインスタンスを作成するたびに、ARC はそのインスタンスに関する情報を保存するためにメモリのチャンクを割り当てます。 このメモリには、インスタンスのタイプに関する情報と、そのインスタンスに関連付けられた保存されたプロパティの値が保持されます。
Additionally, when an instance is no longer needed, ARC frees up the memory used by that instance so that the memory can be used for other purposes instead. This ensures that class instances don’t take up space in memory when they’re no longer needed.
さらに、インスタンスが不要になった場合、ARC はそのインスタンスが使用していたメモリを解放し、そのメモリを他の目的に使用できるようにします。 これにより、クラス インスタンスが不要になったときにメモリ内のスペースを占有することがなくなります。
However, if ARC were to deallocate an instance that was still in use, it would no longer be possible to access that instance’s properties, or call that instance’s methods. Indeed, if you tried to access the instance, your app would most likely crash.
ただし、ARC がまだ使用中のインスタンスの割り当てを解除した場合、そのインスタンスのプロパティにアクセスしたり、そのインスタンスのメソッドを呼び出したりすることはできなくなります。 実際、インスタンスにアクセスしようとすると、アプリはクラッシュする可能性が高くなります。
To make sure that instances don’t disappear while they’re still needed, ARC tracks how many properties, constants, and variables are currently referring to each class instance. ARC will not deallocate an instance as long as at least one active reference to that instance still exists.
インスタンスが必要なまま消えないように、ARC は現在各クラス インスタンスを参照しているプロパティ、定数、変数の数を追跡します。 ARC は、インスタンスへのアクティブな参照が少なくとも 1 つ存在する限り、インスタンスの割り当てを解除しません。
To make this possible, whenever you assign a class instance to a property, constant, or variable, that property, constant, or variable makes a strong reference to the instance. The reference is called a “strong” reference because it keeps a firm hold on that instance, and doesn’t allow it to be deallocated for as long as that strong reference remains.
これを可能にするために、クラス インスタンスをプロパティ、定数、または変数に割り当てるたびに、そのプロパティ、定数、または変数はインスタンスへの強い参照を作成します。 この参照は、そのインスタンスをしっかりと保持し、その強い参照が残っている限り割り当てを解除できないため、「強」参照と呼ばれます。
ARC in Action
ARC の動作
Here’s an example of how Automatic Reference Counting works. This example starts with a simple class called Person
, which defines a stored constant property called name
:
以下に、自動参照カウントがどのように機能するかを示す例を示します。 この例は、Person
という単純なクラスから始まり、name
という保存された定数プロパティを定義します。
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit {
print("\(name) is being deinitialized")
}
}
The Person
class has an initializer that sets the instance’s name
property and prints a message to indicate that initialization is underway. The Person
class also has a deinitializer that prints a message when an instance of the class is deallocated.
Person
クラスには、インスタンスの name
プロパティを設定し、初期化が進行中であることを示すメッセージを出力する初期化子があります。 Person
クラスには、クラスのインスタンスの割り当てが解除されたときにメッセージを出力する初期化解除子もあります。
The next code snippet defines three variables of type Person?
, which are used to set up multiple references to a new Person
instance in subsequent code snippets. Because these variables are of an optional type (Person?
, not Person
), they’re automatically initialized with a value of nil
, and don’t currently reference a Person
instance.
次のコード スニペットでは、タイプ「Person?
」の 3 つの変数を定義します。これらは、後続のコード スニペットで新しい Person
インスタンスへの複数の参照を設定するために使用されます。 これらの変数はオプションのタイプ(Person
ではなくPerson?
)であるため、値 nil
で自動的に初期化され、現在は人インスタンスを参照しません。
var reference1: Person?
var reference2: Person?
var reference3: Person?
You can now create a new Person
instance and assign it to one of these three variables:
これで、新しい Person
インスタンスを作成し、次の 3 つの変数のいずれかに割り当てることができます。
reference1 = Person(name: "John Appleseed")
// Prints "John Appleseed is being initialized"
Note that the message "John Appleseed is being initialized"
is printed at the point that you call the Person
class’s initializer. This confirms that initialization has taken place.
Person
クラスのイニシャライザを呼び出した時点で、"John Appleseed is being initialized"
というメッセージが出力されることに注意してください。 これにより、初期化が行われたことが確認されます。
Because the new Person
instance has been assigned to the reference1
variable, there’s now a strong reference from reference1
to the new Person
instance. Because there’s at least one strong reference, ARC makes sure that this Person
is kept in memory and isn’t deallocated.
新しい Person
インスタンスがreference1
変数に割り当てられているため、reference1
から新しい Person
インスタンスへの強い参照が存在します。 少なくとも 1 つの強い参照があるため、ARC はこの Person
がメモリ内に保持され、割り当てが解除されていないことを確認します。
If you assign the same Person
instance to two more variables, two more strong references to that instance are established:
同じ Person
インスタンスをさらに 2 つの変数に割り当てると、そのインスタンスへのさらに 2 つの強参照が確立されます。
reference2 = reference1
reference3 = reference1
There are now three strong references to this single Person
instance.
この単一の Person
インスタンスに対して 3 つの強い参照が存在します。
If you break two of these strong references (including the original reference) by assigning nil
to two of the variables, a single strong reference remains, and the Person
instance isn’t deallocated:
2 つの変数に nil
を代入して、これらの 2 つの強参照(元の参照を含む)を解除した場合、1 つの強参照が残り、Person
インスタンスの割り当ては解除されません。
reference1 = nil
reference2 = nil
ARC doesn’t deallocate the Person
instance until the third and final strong reference is broken, at which point it’s clear that you are no longer using the Person
instance:
ARC は、3 番目で最後の強参照が壊れるまで、Person
インスタンスの割り当てを解除しません。その時点で、Person
インスタンスがもう使用されていないことが明らかです。
reference3 = nil
// Prints "John Appleseed is being deinitialized"
Strong Reference Cycles Between Class Instances
クラスインスタンス間の強参照サイクル
In the examples above, ARC is able to track the number of references to the new Person
instance you create and to deallocate that Person
instance when it’s no longer needed.
上記の例では、ARC は作成した新しい Person
インスタンスへの参照の数を追跡し、不要になった Person
インスタンスの割り当てを解除できます。
However, it’s possible to write code in which an instance of a class never gets to a point where it has zero strong references. This can happen if two class instances hold a strong reference to each other, such that each instance keeps the other alive. This is known as a strong reference cycle.
ただし、クラスのインスタンスが強参照がゼロになることのないコードを作成することも可能です。 これは、2 つのクラス インスタンスが相互に強い参照を保持し、各インスタンスが他のインスタンスを存続させる場合に発生する可能性があります。 これは、強参照サイクルとして知られています。
You resolve strong reference cycles by defining some of the relationships between classes as weak or unowned references instead of as strong references. This process is described in Resolving Strong Reference Cycles Between Class Instances. However, before you learn how to resolve a strong reference cycle, it’s useful to understand how such a cycle is caused.
強参照サイクルを解決するには、クラス間の関係の一部を強参照ではなく弱参照または非所有参照として定義します。 このプロセスについては、「クラス インスタンス間の強参照サイクルの解決」で説明されています。 ただし、強参照サイクルを解決する方法を学ぶ前に、そのようなサイクルがどのように発生するかを理解することが役立ちます。
Here’s an example of how a strong reference cycle can be created by accident. This example defines two classes called Person
and Apartment
, which model a block of apartments and its residents:
以下は、強参照サイクルがどのようにして偶然に作成されるかの例です。 この例では、アパートのブロックとその居住者をモデル化する、「Person
」と「Apartment
」という 2 つのクラスを定義します。
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
var tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
}
Every Person
instance has a name
property of type String
and an optional apartment
property that’s initially nil
. The apartment
property is optional, because a person may not always have an apartment.
すべての Person
インスタンスには、String
型の name
プロパティと、最初は nil
であるオプションの apartment
プロパティがあります。 人が常にアパートを所有しているとは限らないため、アパートの所有権はオプションです。
Similarly, every Apartment
instance has a unit
property of type String
and has an optional tenant
property that’s initially nil
. The tenant property is optional because an apartment may not always have a tenant.
同様に、すべてのApartment
インスタンスには String
型のunit
プロパティがあり、オプションで初期値が nil
のテナント プロパティがあります。 アパートには常にテナントがいるとは限らないため、テナント プロパティはオプションです。
Both of these classes also define a deinitializer, which prints the fact that an instance of that class is being deinitialized. This enables you to see whether instances of Person
and Apartment
are being deallocated as expected.
これらのクラスは両方とも、そのクラスのインスタンスが初期化解除されていることを出力する初期化解除子も定義します。 これにより、「Personal
」と「Apartment
」のインスタンスが予想どおりに割り当て解除されているかどうかを確認できます。
This next code snippet defines two variables of optional type called john
and unit4A
, which will be set to a specific Apartment
and Person
instance below. Both of these variables have an initial value of nil
, by virtue of being optional:
この次のコード スニペットは、john
とunit4A
というオプションのタイプの 2 つの変数を定義します。これらは、以下の特定の Apartment
と Person
インスタンスに設定されます。 これらの変数は両方ともオプションであるため、初期値は nil
です。
var john: Person?
var unit4A: Apartment?
You can now create a specific Person
instance and Apartment
instance and assign these new instances to the john
and unit4A
variables:
これで、特定の Person
インスタンスと Apartment
インスタンスを作成し、これらの新しいインスタンスを john
変数とunit4A
変数に割り当てることができます。
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
Here’s how the strong references look after creating and assigning these two instances. The john
variable now has a strong reference to the new Person
instance, and the unit4A
variable has a strong reference to the new Apartment
instance:
これら 2 つのインスタンスを作成して割り当てた後の強参照がどのように見えるかを次に示します。 john
変数には新しい Person
インスタンスへの強い参照が含まれ、unit4A
変数には新しい Apartment
インスタンスへの強い参照が含まれています。
You can now link the two instances together so that the person has an apartment, and the apartment has a tenant. Note that an exclamation point (!
) is used to unwrap and access the instances stored inside the john
and unit4A
optional variables, so that the properties of those instances can be set:
これで、2 つのインスタンスをリンクして、その人がアパートを所有し、そのアパートにテナントが存在するようにすることができます。 感嘆符 (!
) は、john
および unit4A
のオプション変数内に保存されているインスタンスをラップ解除してアクセスするために使用され、これらのインスタンスのプロパティを設定できることに注意してください。
john!.apartment = unit4A
unit4A!.tenant = john
Here’s how the strong references look after you link the two instances together:
2 つのインスタンスをリンクした後の強参照は次のようになります。
Unfortunately, linking these two instances creates a strong reference cycle between them. The Person
instance now has a strong reference to the Apartment
instance, and the Apartment
instance has a strong reference to the Person
instance. Therefore, when you break the strong references held by the john
and unit4A
variables, the reference counts don’t drop to zero, and the instances aren’t deallocated by ARC:
残念ながら、これら 2 つのインスタンスをリンクすると、それらの間に強力な参照サイクルが作成されます。 Person
インスタンスは Apartment
インスタンスへの強い参照を持ち、Apartment
インスタンスは Person
インスタンスへの強い参照を持ちます。 したがって、john
変数とunit4A
変数が保持する強参照を解除しても、参照カウントはゼロにならず、インスタンスは ARC によって割り当て解除されません。
john = nil
unit4A = nil
Note that neither deinitializer was called when you set these two variables to nil
. The strong reference cycle prevents the Person
and Apartment
instances from ever being deallocated, causing a memory leak in your app.
これら 2 つの変数を nil
に設定した場合、どちらの初期化解除子も呼び出されないことに注意してください。 強参照サイクルは、Person
インスタンスと Apartment
インスタンスの割り当てが解除されるのを妨げ、アプリにおいてメモリ リークの原因となります。
Here’s how the strong references look after you set the john
and unit4A
variables to nil
:
john
変数とunit4A
変数を nil
に設定した後の強参照は次のようになります。
The strong references between the Person
instance and the Apartment
instance remain and can’t be broken.
Person
インスタンスと Apartment
インスタンスの間の強い参照は残り、破ることはできません。
Resolving Strong Reference Cycles Between Class Instances
クラスインスタンス間の強参照サイクルの解決
Swift provides two ways to resolve strong reference cycles when you work with properties of class type: weak references and unowned references.
Swift では、クラス型のプロパティを操作するときに強参照サイクルを解決する 2 つの方法、つまり、弱参照と非所有参照を提供します。
Weak and unowned references enable one instance in a reference cycle to refer to the other instance without keeping a strong hold on it. The instances can then refer to each other without creating a strong reference cycle.
弱参照と非所有参照により、参照サイクル内の 1 つのインスタンスが、強力な保持を維持することなく、他のインスタンスを参照できるようになります。 これにより、インスタンスは強参照サイクルを作成せずに相互に参照できるようになります。
Use a weak reference when the other instance has a shorter lifetime — that is, when the other instance can be deallocated first. In the Apartment
example above, it’s appropriate for an apartment to be able to have no tenant at some point in its lifetime, and so a weak reference is an appropriate way to break the reference cycle in this case. In contrast, use an unowned reference when the other instance has the same lifetime or a longer lifetime.
他のインスタンスの有効期間が短い場合、つまり、他のインスタンスの割り当てを最初に解除できる場合は、弱参照を使用します。 上記のApartment
の例では、アパートがその存続期間のある時点でテナントを持たないことが適切であるため、この場合、参照サイクルを断ち切るには弱参照が適切な方法です。 対照的に、他のインスタンスの有効期間が同じかそれより長い場合は、非所有参照を使用します。
Weak References
弱参照
A weak reference is a reference that doesn’t keep a strong hold on the instance it refers to, and so doesn’t stop ARC from disposing of the referenced instance. This behavior prevents the reference from becoming part of a strong reference cycle. You indicate a weak reference by placing the weak
keyword before a property or variable declaration.
弱参照とは、参照するインスタンスを強力に保持しない参照であり、そのため、ARC による参照されたインスタンスの破棄を停止しません。 この動作により、参照が強参照サイクルの一部になることが防止されます。 弱参照を指定するには、プロパティまたは変数の宣言の前にweak
キーワードを置きます。
Because a weak reference doesn’t keep a strong hold on the instance it refers to, it’s possible for that instance to be deallocated while the weak reference is still referring to it. Therefore, ARC automatically sets a weak reference to nil
when the instance that it refers to is deallocated. And, because weak references need to allow their value to be changed to nil
at runtime, they’re always declared as variables, rather than constants, of an optional type.
弱参照は参照先のインスタンスを強力に保持しないため、弱参照が参照している間にそのインスタンスの割り当てが解除される可能性があります。 したがって、ARC は、参照しているインスタンスの割り当てが解除されると、弱参照を自動的に nil
に設定します。 また、弱参照は実行時に値を nil
に変更できるようにする必要があるため、常にオプションの型の定数ではなく変数として宣言されます。
You can check for the existence of a value in the weak reference, just like any other optional value, and you will never end up with a reference to an invalid instance that no longer exists.
他のオプションの値と同様に、弱参照内の値の存在を確認できます。存在しない無効なインスタンスへの参照が発生することはありません。
Note
注釈
Property observers aren’t called when ARC sets a weak reference to nil
.
ARC が弱参照を nil
に設定する場合、プロパティ オブザーバーは呼び出されません。
The example below is identical to the Person
and Apartment
example from above, with one important difference. This time around, the Apartment
type’s tenant
property is declared as a weak reference:
以下の例は、上記の人物とアパートの例と同じですが、重要な違いが 1 つあります。 今回は、Apartment
タイプのtenant
プロパティが弱い参照として宣言されています。
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
weak var tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
}
The strong references from the two variables (john
and unit4A
) and the links between the two instances are created as before:
2 つの変数 (john
とunit4A
) からの強参照と 2 つのインスタンス間のリンクが以前と同様に作成されます。
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
Here’s how the references look now that you’ve linked the two instances together:
2 つのインスタンスをリンクすると、参照は次のようになります。
The Person
instance still has a strong reference to the Apartment
instance, but the Apartment
instance now has a weak reference to the Person
instance. This means that when you break the strong reference held by the john
variable by setting it to nil
, there are no more strong references to the Person
instance:
Person
インスタンスは依然として Apartment
インスタンスへの強い参照を持っていますが、Apartment インスタンス
は Person
インスタンスへの弱参照を持ちます。 これは、john
変数を nil
に設定してその強参照を解除すると、Person
インスタンスへの強参照がなくなることを意味します。
john = nil
// Prints "John Appleseed is being deinitialized"
Because there are no more strong references to the Person
instance, it’s deallocated and the tenant
property is set to nil
:
Person
インスタンスへの強い参照がなくなったため、割り当てが解除され、テナント プロパティが nil
に設定されます。
The only remaining strong reference to the Apartment
instance is from the unit4A
variable. If you break that strong reference, there are no more strong references to the Apartment
instance:
Apartment
インスタンスへの唯一残っている強参照は、unit4A
変数からのものです。 その強参照を破ると、Apartment
インスタンスへの強参照はなくなります。
unit4A = nil
// Prints "Apartment 4A is being deinitialized"
Because there are no more strong references to the Apartment
instance, it too is deallocated:
Apartment
インスタンスへの強い参照がなくなったため、このインスタンスも割り当てが解除されます。
Note
注釈
In systems that use garbage collection, weak pointers are sometimes used to implement a simple caching mechanism because objects with no strong references are deallocated only when memory pressure triggers garbage collection. However, with ARC, values are deallocated as soon as their last strong reference is removed, making weak references unsuitable for such a purpose.
ガベージ コレクションを使用するシステムでは、メモリ負荷がガベージ コレクションをトリガーした場合にのみ、強参照を持たないオブジェクトの割り当てが解除されるため、単純なキャッシュ メカニズムを実装するために弱いポインターが使用されることがあります。 ただし、ARC では、最後の強参照が削除されるとすぐに値の割り当てが解除されるため、弱参照はそのような目的には適していません。
Unowned References
非所有参照
Like a weak reference, an unowned reference doesn’t keep a strong hold on the instance it refers to. Unlike a weak reference, however, an unowned reference is used when the other instance has the same lifetime or a longer lifetime. You indicate an unowned reference by placing the unowned
keyword before a property or variable declaration.
弱参照と同様、非所有参照は、参照するインスタンスを強力に保持しません。 ただし、弱参照とは異なり、非所有参照は、他のインスタンスの存続期間が同じかそれより長い場合に使用されます。 非所有参照を指定するには、プロパティまたは変数の宣言の前に unowned
キーワードを置きます。
Unlike a weak reference, an unowned reference is expected to always have a value. As a result, marking a value as unowned doesn’t make it optional, and ARC never sets an unowned reference’s value to nil
.
弱参照とは異なり、非所有参照は常に値を持つことが期待されます。 その結果、値を非所有としてマークしてもそれがオプションになるわけではなく、ARC が非所有の参照の値を nil
に設定することはありません。
Important
重要
Use an unowned reference only when you are sure that the reference always refers to an instance that hasn’t been deallocated.
非所有参照は、参照が常に割り当て解除されていないインスタンスを参照していることが確実な場合にのみ使用してください。
If you try to access the value of an unowned reference after that instance has been deallocated, you’ll get a runtime error.
インスタンスの割り当てが解除された後に、非所有参照の値にアクセスしようとすると、実行時エラーが発生します。
The following example defines two classes, Customer
and CreditCard
, which model a bank customer and a possible credit card for that customer. These two classes each store an instance of the other class as a property. This relationship has the potential to create a strong reference cycle.
次の例では、Customer
と CreditCard
という 2 つのクラスを定義しており、銀行顧客とその顧客に使用できるクレジット カードをモデル化しています。 これら 2 つのクラスはそれぞれ、他のクラスのインスタンスをプロパティとして保存します。 この関係は、強力な参照サイクルを生み出す可能性があります。
The relationship between Customer
and CreditCard
is slightly different from the relationship between Apartment
and Person
seen in the weak reference example above. In this data model, a customer may or may not have a credit card, but a credit card will always be associated with a customer. A CreditCard
instance never outlives the Customer
that it refers to. To represent this, the Customer
class has an optional card
property, but the CreditCard
class has an unowned (and non-optional) customer
property.
「Customer
」と「CreditCard
」の関係は、上記の弱参照の例に見られる「Apartment
」と「Person
」の関係とは少し異なります。 このデータモデルでは、顧客はクレジット カードを持っている場合も持っていない場合もありますが、クレジット カードは常に顧客に関連付けられます。 CreditCard
インスタンスは、それが参照する顧客よりも存続することはありません。 これを表すために、Customer
クラスにはオプションのカード プロパティがありますが、CreditCard
クラスには非所有の(オプションではない)customer
プロパティがあります。
Furthermore, a new CreditCard
instance can only be created by passing a number
value and a customer
instance to a custom CreditCard
initializer. This ensures that a CreditCard
instance always has a customer
instance associated with it when the CreditCard
instance is created.
さらに、新しい CreditCard
インスタンスは、number
とcustomer
インスタンスをカスタム CreditCard
イニシャライザに渡すことによってのみ作成できます。 これにより、CreditCard
インスタンスの作成時に、CreditCard
インスタンスには常に顧客インスタンスが関連付けられるようになります。
Because a credit card will always have a customer, you define its customer
property as an unowned reference, to avoid a strong reference cycle:
クレジット カードには常に顧客が存在するため、強参照サイクルを避けるために、そのcustomer
プロパティを非所有参照として定義します。
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit { print("\(name) is being deinitialized") }
}
class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Card #\(number) is being deinitialized") }
}
Note
注釈
The number
property of the CreditCard
class is defined with a type of UInt64
rather than Int
, to ensure that the number
property’s capacity is large enough to store a 16-digit card number on both 32-bit and 64-bit systems.
CreditCard
クラスのnumber
プロパティは、number
プロパティの容量が 32 ビット システムと 64 ビット システムの両方で 16 桁のカード番号を格納するのに十分な大きさであることを保証するために、Int
ではなく UInt64
の型で定義されています。
This next code snippet defines an optional Customer
variable called john
, which will be used to store a reference to a specific customer. This variable has an initial value of nil, by virtue of being optional:
次のコード スニペットは、特定の顧客への参照を保存するために使用される、john
というオプションのCustomer
変数を定義します。 この変数はオプションであるため、初期値は nil
です。
var john: Customer?
You can now create a Customer
instance, and use it to initialize and assign a new CreditCard
instance as that customer’s card
property:
これで、Customer
インスタンスを作成し、それを使用して新しいCreditCard
インスタンスを初期化し、その顧客のcard
プロパティとして割り当てることができます。
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
Here’s how the references look, now that you’ve linked the two instances:
2 つのインスタンスをリンクした後の参照は次のようになります。
The Customer
instance now has a strong reference to the CreditCard
instance, and the CreditCard
instance has an unowned reference to the Customer
instance.
Customer
インスタンスには、CreditCard
インスタンスへの強参照があり、CreditCard
インスタンスには、Customer
インスタンスへの非所有参照が含まれています。
Because of the unowned customer
reference, when you break the strong reference held by the john
variable, there are no more strong references to the Customer
instance:
非所有customer
参照のため、john
変数によって保持されている強参照を解除すると、Customer
インスタンスへの強参照はなくなります。
Because there are no more strong references to the Customer
instance, it’s deallocated. After this happens, there are no more strong references to the CreditCard
instance, and it too is deallocated:
Customer
インスタンスへの強参照がなくなったため、割り当てが解除されます。 これが発生すると、CreditCard
インスタンスへの強参照はなくなり、割り当ても解除されます。
john = nil
// Prints "John Appleseed is being deinitialized"
// Prints "Card #1234567890123456 is being deinitialized"
The final code snippet above shows that the deinitializers for the Customer
instance and CreditCard
instance both print their “deinitialized” messages after the john
variable is set to nil
.
上記の最後のコード スニペットは、Customer
インスタンスと CreditCard
インスタンスの初期化解除ツールが両方とも、john
変数が nil
に設定された後に「初期化解除」メッセージを出力することを示しています。
Note
注釈
The examples above show how to use safe unowned references. Swift also provides unsafe unowned references for cases where you need to disable runtime safety checks — for example, for performance reasons. As with all unsafe operations, you take on the responsibility for checking that code for safety.
上記の例は、安全な非所有参照を使用する方法を示しています。 Swift は、パフォーマンス上の理由などで、実行時の安全性チェックを無効にする必要がある場合に備えて、安全でない非所有参照も提供します。 すべての危険な操作と同様に、コードの安全性をチェックする責任はあなたにあります。
You indicate an unsafe unowned reference by writing unowned(unsafe)
. If you try to access an unsafe unowned reference after the instance that it refers to is deallocated, your program will try to access the memory location where the instance used to be, which is an unsafe operation.
unowned(unsafe)
と書くことで、安全でない非所有参照を示します。 参照するインスタンスの割り当てが解除された後で、安全でない非所有参照にアクセスしようとすると、プログラムはインスタンスが以前存在していたメモリ位置にアクセスしようとしますが、これは安全でない操作です。
Unowned Optional References
非所有オプションの参照
You can mark an optional reference to a class as unowned. In terms of the ARC ownership model, an unowned optional reference and a weak reference can both be used in the same contexts. The difference is that when you use an unowned optional reference, you’re responsible for making sure it always refers to a valid object or is set to nil
.
クラスへのオプションの参照を非所有としてマークできます。 ARC 所有権モデルに関しては、非所有オプションの参照と弱参照の両方を同じコンテキストで使用できます。 違いは、非所有オプションの参照を使用する場合、それが常に有効なオブジェクトを参照するか、nil に設定されていることを確認する責任があるということです。
Here’s an example that keeps track of the courses offered by a particular department at a school:
学校の特定の学部が提供するコースを追跡する例を次に示します。
class Department {
var name: String
var courses: [Course]
init(name: String) {
self.name = name
self.courses = []
}
}
class Course {
var name: String
unowned var department: Department
unowned var nextCourse: Course?
init(name: String, in department: Department) {
self.name = name
self.department = department
self.nextCourse = nil
}
}
Department
maintains a strong reference to each course that the department offers. In the ARC ownership model, a department owns its courses. Course
has two unowned references, one to the department and one to the next course a student should take; a course doesn’t own either of these objects. Every course is part of some department so the department
property isn’t an optional. However, because some courses don’t have a recommended follow-on course, the nextCourse
property is an optional.
学部は、Department
が提供する各コースへの強参照を維持します。 ARC 所有権モデルでは、部門がコースを所有します。 Course
には 2 つの非所有参照があり、1 つは学部への参照、もう 1 つは学生が受講する必要がある次のコースへの参照です。 コースはこれらのオブジェクトのいずれも所有しません。 すべてのコースは一部の部門の一部であるため、department
プロパティはオプションではありません。 ただし、一部のコースには推奨される後続コースがないため、nextCourse
プロパティはオプションです。
Here’s an example of using these classes:
これらのクラスの使用例を次に示します。
let department = Department(name: "Horticulture")
let intro = Course(name: "Survey of Plants", in: department)
let intermediate = Course(name: "Growing Common Herbs", in: department)
let advanced = Course(name: "Caring for Tropical Plants", in: department)
intro.nextCourse = intermediate
intermediate.nextCourse = advanced
department.courses = [intro, intermediate, advanced]
The code above creates a department and its three courses. The intro and intermediate courses both have a suggested next course stored in their nextCourse
property, which maintains an unowned optional reference to the course a student should take after completing this one.
上記のコードは、部門とその 3 つのコースを作成します。 入門コースと中級コースの両方には、nextCourse
プロパティに保存された次のコースの提案があり、このプロパティは、学生がこのコースを完了した後に受講する必要があるコースへの非所有のオプションの参照を維持します。
An unowned optional reference doesn’t keep a strong hold on the instance of the class that it wraps, and so it doesn’t prevent ARC from deallocating the instance. It behaves the same as an unowned reference does under ARC, except that an unowned optional reference can be nil
.
非所有オプションの参照は、それがラップするクラスのインスタンスを強力に保持しないため、ARC によるインスタンスの割り当て解除が妨げられることはありません。 非所有のオプションの参照が nil
になる可能性があることを除いて、ARC での非所有参照と同じように動作します。
Like non-optional unowned references, you’re responsible for ensuring that nextCourse
always refers to a course that hasn’t been deallocated. In this case, for example, when you delete a course from department.courses
you also need to remove any references to it that other courses might have.
オプションではない非所有参照と同様に、nextCourse
が常に割り当て解除されていないコースを参照するようにするのはあなたの責任です。 この場合、たとえば、Department.courses
からコースを削除するときに、他のコースにある可能性のあるそのコースへの参照も削除する必要があります。
Note
注釈
The underlying type of an optional value is Optional
, which is an enumeration in the Swift standard library. However, optionals are an exception to the rule that value types can’t be marked with unowned
.
オプションの値の基になるタイプは Optional
で、これは Swift 標準ライブラリの列挙です。 ただし、オプショナルは、値のタイプを unowned
でマークできないというルールの例外です。
The optional that wraps the class doesn’t use reference counting, so you don’t need to maintain a strong reference to the optional.
クラスをラップするオプションは参照カウントを使用しないため、オプションへの強参照を維持する必要はありません。
Unowned References and Implicitly Unwrapped Optional Properties
非所有参照と暗黙的にアンラップされたオプションのプロパティ
The examples for weak and unowned references above cover two of the more common scenarios in which it’s necessary to break a strong reference cycle.
上記の弱参照と非所有参照の例は、強参照サイクルを中断する必要がある、より一般的な 2 つのシナリオをカバーしています。
The Person
and Apartment
example shows a situation where two properties, both of which are allowed to be nil
, have the potential to cause a strong reference cycle. This scenario is best resolved with a weak reference.
Person
とApartment
の例は、両方とも nil
が許可されている 2 つのプロパティが強参照サイクルを引き起こす可能性がある状況を示しています。 このシナリオは、弱参照を使用して解決するのが最適です。
The Customer
and CreditCard
example shows a situation where one property that’s allowed to be nil
and another property that can’t be nil
have the potential to cause a strong reference cycle. This scenario is best resolved with an unowned reference.
Customer
と CreditCard
の例は、nil
であることが許可されている 1 つのプロパティと nil にすることができない別のプロパティが強い参照サイクルを引き起こす可能性がある状況を示しています。 このシナリオは、非所有参照を使用して解決するのが最適です。
However, there’s a third scenario, in which both properties should always have a value, and neither property should ever be nil
once initialization is complete. In this scenario, it’s useful to combine an unowned property on one class with an implicitly unwrapped optional property on the other class.
ただし、両方のプロパティが常に値を持つ必要があり、初期化が完了するとどちらのプロパティも nil になることがあってはならない 3 番目のシナリオがあります。 このシナリオでは、一方のクラスの非所有プロパティと、もう一方のクラスの暗黙的にラップ解除されたオプションのプロパティを組み合わせると便利です。
This enables both properties to be accessed directly (without optional unwrapping) once initialization is complete, while still avoiding a reference cycle. This section shows you how to set up such a relationship.
これにより、初期化が完了すると、参照サイクルを回避しながら、両方のプロパティに (オプションのアンラップなしで) 直接アクセスできるようになります。 このセクションでは、そのような関係を設定する方法を説明します。
The example below defines two classes, Country
and City
, each of which stores an instance of the other class as a property. In this data model, every country must always have a capital city, and every city must always belong to a country. To represent this, the Country
class has a capitalCity
property, and the City
class has a country
property:
以下の例では、 Country
と City
の 2 つのクラスを定義しており、それぞれが他のクラスのインスタンスをプロパティとして保存しています。 このデータ モデルでは、すべての国には必ず首都があり、すべての都市は常に国に属している必要があります。 これを表すために、 Country
クラスには CapitalCity
プロパティがあり、City
クラスには country
プロパティがあります。
class Country {
let name: String
var capitalCity: City!
init(name: String, capitalName: String) {
self.name = name
self.capitalCity = City(name: capitalName, country: self)
}
}
class City {
let name: String
unowned let country: Country
init(name: String, country: Country) {
self.name = name
self.country = country
}
}
To set up the interdependency between the two classes, the initializer for City
takes a Country
instance, and stores this instance in its country
property.
2 つのクラス間の相互依存関係を設定するために、City
のイニシャライザは Country
インスタンスを取得し、このインスタンスを country
プロパティに保存します。
The initializer for City
is called from within the initializer for Country
. However, the initializer for Country
can’t pass self
to the City
initializer until a new Country
instance is fully initialized, as described in Two-Phase Initialization.
City
のイニシャライザは Country
のイニシャライザ内から呼び出されます。 ただし、「2 段階の初期化」で説明されているように、新しい Country
インスタンスが完全に初期化されるまで、 Country
のイニシャライザは自分自身を City
イニシャライザに渡すことはできません。
To cope with this requirement, you declare the capitalCity
property of Country
as an implicitly unwrapped optional property, indicated by the exclamation point at the end of its type annotation (City!
). This means that the capitalCity
property has a default value of nil
, like any other optional, but can be accessed without the need to unwrap its value as described in Implicitly Unwrapped Optionals.
この要件に対処するには、 Country
の CapitalCity
プロパティを暗黙的にアンラップされたオプションのプロパティとして宣言します。これは、型注釈の末尾にある感嘆符 (City!
) で示されます。 これは、capitalCity
プロパティのデフォルト値は他のオプションと同様に nil
ですが、暗黙的にアンラップされたオプションで説明されているように値をアンラップする必要なくアクセスできることを意味します。
Because capitalCity
has a default nil
value, a new Country
instance is considered fully initialized as soon as the Country
instance sets its name
property within its initializer. This means that the Country
initializer can start to reference and pass around the implicit self
property as soon as the name
property is set. The Country
initializer can therefore pass self
as one of the parameters for the City
initializer when the Country
initializer is setting its own capitalCity
property.
CapitalCity
にはデフォルトの nil
値があるため、 Country
インスタンスがイニシャライザ内で name
プロパティを設定するとすぐに、新しい Country
インスタンスは完全に初期化されたとみなされます。 これは、name
プロパティが設定されるとすぐに、 Country
イニシャライザーが暗黙的な self
プロパティの参照と受け渡しを開始できることを意味します。 したがって、 Country
イニシャライザが独自の CapitalCity
プロパティを設定する場合、 Country
イニシャライザは City
イニシャライザのパラメータの 1 つとして self
を渡すことができます。
All of this means that you can create the Country
and City
instances in a single statement, without creating a strong reference cycle, and the capitalCity
property can be accessed directly, without needing to use an exclamation point to unwrap its optional value:
これらすべては、強参照サイクルを作成せずに、単一のステートメントで Country
インスタンスと City
インスタンスを作成でき、オプションの値を展開するために感嘆符を使用することなく、capitalCity
プロパティに直接アクセスできることを意味します。
var country = Country(name: "Canada", capitalName: "Ottawa")
print("\(country.name)'s capital city is called \(country.capitalCity.name)")
// Prints "Canada's capital city is called Ottawa"
In the example above, the use of an implicitly unwrapped optional means that all of the two-phase class initializer requirements are satisfied. The capitalCity
property can be used and accessed like a non-optional value once initialization is complete, while still avoiding a strong reference cycle.
上記の例では、暗黙的にアンラップされたオプションの使用は、2 フェーズのクラス初期化子の要件がすべて満たされていることを意味します。 CapitalCity
プロパティは、初期化が完了すると、強参照サイクルを回避しながら、非オプションの値のように使用およびアクセスできます。
Strong Reference Cycles for Closures
クロージャの強参照サイクル
You saw above how a strong reference cycle can be created when two class instance properties hold a strong reference to each other. You also saw how to use weak and unowned references to break these strong reference cycles.
2 つのクラス インスタンス プロパティが相互に強参照を保持している場合に、強参照サイクルがどのように作成されるかを上で見てきました。 また、弱参照と非所有参照を使用して、これらの強参照サイクルを断ち切る方法についても説明しました。
A strong reference cycle can also occur if you assign a closure to a property of a class instance, and the body of that closure captures the instance. This capture might occur because the closure’s body accesses a property of the instance, such as self.someProperty
, or because the closure calls a method on the instance, such as self.someMethod()
. In either case, these accesses cause the closure to “capture” self
, creating a strong reference cycle.
強参照サイクルは、クラス インスタンスのプロパティにクロージャを割り当て、そのクロージャの本体がインスタンスをキャプチャする場合にも発生する可能性があります。 このキャプチャは、クロージャの本体が self.someProperty
などのインスタンスのプロパティにアクセスするか、クロージャが self.someMethod()
などのインスタンスのメソッドを呼び出すために発生する可能性があります。 いずれの場合も、これらのアクセスによりクロージャが自己を「キャプチャ」し、強参照サイクルが作成されます。
This strong reference cycle occurs because closures, like classes, are reference types. When you assign a closure to a property, you are assigning a reference to that closure. In essence, it’s the same problem as above — two strong references are keeping each other alive. However, rather than two class instances, this time it’s a class instance and a closure that are keeping each other alive.
この強参照サイクルは、クラスと同様にクロージャが参照型であるために発生します。 クロージャをプロパティに割り当てると、そのクロージャへの参照が割り当てられることになります。 本質的には、これは上記と同じ問題です。2 つの強参照がお互いを生かし続けています。 ただし、今回は 2 つのクラス インスタンスではなく、クラス インスタンスとクロージャが相互に存続させています。
Swift provides an elegant solution to this problem, known as a closure capture list. However, before you learn how to break a strong reference cycle with a closure capture list, it’s useful to understand how such a cycle can be caused.
Swift は、クロージャ キャプチャ リストとして知られる、この問題に対する洗練された解決を提供します。 ただし、クロージャ キャプチャ リストを使用して強参照サイクルを破る方法を学ぶ前に、そのようなサイクルがどのように発生するかを理解しておくと役立ちます。
The example below shows how you can create a strong reference cycle when using a closure that references self
. This example defines a class called HTMLElement
, which provides a simple model for an individual element within an HTML document:
以下の例は、self
を参照するクロージャを使用するときに強参照サイクルを作成する方法を示しています。 この例では、HTMLElement
というクラスを定義します。これは、HTML ドキュメント内の個々の要素の単純なモデルを提供します。
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
The HTMLElement
class defines a name
property, which indicates the name of the element, such as "h1"
for a heading element, "p"
for a paragraph element, or "br"
for a line break element. HTMLElement
also defines an optional text
property, which you can set to a string that represents the text to be rendered within that HTML element.
HTMLElement
クラスは、要素の名前を示す name
プロパティを定義します。これは、見出し要素の場合は「h1
」、段落要素の場合は「p
」、改行要素の場合は「br
」などです。 HTMLElement
は、オプションのtext
プロパティも定義します。このプロパティは、HTML 要素内でレンダリングされるテキストを表す文字列に設定できます。
In addition to these two simple properties, the HTMLElement
class defines a lazy property called asHTML
. This property references a closure that combines name
and text
into an HTML string fragment. The asHTML
property is of type () -> String
, or “a function that takes no parameters, and returns a String
value”.
これら 2 つの単純なプロパティに加えて、HTMLElement
クラスは asHTML
と呼ばれる遅延プロパティを定義します。 このプロパティは、name
とtext
を HTML 文字列フラグメントに結合するクロージャを参照します。 asHTML
プロパティは、() -> String
型、つまり「パラメータを受け取らず、String
値を返す関数」です。
By default, the asHTML
property is assigned a closure that returns a string representation of an HTML tag. This tag contains the optional text
value if it exists, or no text content if text
doesn’t exist. For a paragraph element, the closure would return "<p>some text</p>"
or "<p />"
, depending on whether the text
property equals "some text"
or nil
.
デフォルトでは、asHTML
プロパティには、HTML タグの文字列表現を返すクロージャが割り当てられます。 このタグには、オプションのtext
値が存在する場合は含まれますが、text
が存在しない場合はテキスト コンテンツが含まれません。 段落要素の場合、テキスト プロパティが「some text」または nil に等しいかどうかに応じて、クロージャは「<p>some text</p>
」または「<p />
」を返します。
The asHTML
property is named and used somewhat like an instance method. However, because asHTML
is a closure property rather than an instance method, you can replace the default value of the asHTML
property with a custom closure, if you want to change the HTML rendering for a particular HTML element.
asHTML プロパティには名前が付けられ、インスタンス メソッドのように使用されます。 ただし、asHTML はインスタンス メソッドではなくクロージャ プロパティであるため、特定の HTML 要素の HTML レンダリングを変更する場合は、asHTML プロパティのデフォルト値をカスタム クロージャに置き換えることができます。
For example, the asHTML
property could be set to a closure that defaults to some text if the text
property is nil
, in order to prevent the representation from returning an empty HTML tag:
たとえば、表現が空の HTML タグを返さないようにするために、text
プロパティが nil
の場合に、asHTML
プロパティをデフォルトでテキストを使用するクロージャに設定できます。
let heading = HTMLElement(name: "h1")
let defaultText = "some default text"
heading.asHTML = {
return "<\(heading.name)>\(heading.text ?? defaultText)</\(heading.name)>"
}
print(heading.asHTML())
// Prints "<h1>some default text</h1>"
Note
注釈
The asHTML
property is declared as a lazy property, because it’s only needed if and when the element actually needs to be rendered as a string value for some HTML output target. The fact that asHTML
is a lazy property means that you can refer to self
within the default closure, because the lazy property will not be accessed until after initialization has been completed and self
is known to exist.
asHTML
プロパティは、要素を HTML 出力ターゲットの文字列値として実際にレンダリングする必要がある場合にのみ必要となるため、遅延プロパティとして宣言されます。 asHTML
が遅延プロパティであるという事実は、デフォルトのクロージャ内で self
を参照できることを意味します。これは、遅延プロパティは、初期化が完了し、self
の存在が判明するまでアクセスされないためです。
The HTMLElement
class provides a single initializer, which takes a name
argument and (if desired) a text
argument to initialize a new element. The class also defines a deinitializer, which prints a message to show when an HTMLElement
instance is deallocated.
HTMLElement
クラスは、name
引数と (必要に応じて) text
引数を受け取り、新しい要素を初期化する単一の初期化子を提供します。 このクラスは、HTMLElement
インスタンスの割り当てが解除されたときに表示するメッセージを出力する初期化解除子も定義します。
Here’s how you use the HTMLElement
class to create and print a new instance:
HTMLElement
クラスを使用して新しいインスタンスを作成して出力する方法は次のとおりです。
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
// Prints "<p>hello, world</p>"
Note
注釈
The paragraph
variable above is defined as an optional HTMLElement
, so that it can be set to nil
below to demonstrate the presence of a strong reference cycle.
上のparagraph
変数はオプションの HTMLElement
として定義されているため、以下で nil
に設定して、強参照サイクルの存在を示すことができます。
Unfortunately, the HTMLElement
class, as written above, creates a strong reference cycle between an HTMLElement
instance and the closure used for its default asHTML
value. Here’s how the cycle looks:
残念ながら、HTMLElement
クラスは、上で書いたように、HTMLElement
インスタンスとそのデフォルトの asHTML
値に使用されるクロージャとの間に強参照サイクルを作成します。 サイクルは次のようになります。
The instance’s asHTML
property holds a strong reference to its closure. However, because the closure refers to self
within its body (as a way to reference self.name
and self.text
), the closure captures self, which means that it holds a strong reference back to the HTMLElement
instance. A strong reference cycle is created between the two. (For more information about capturing values in a closure, see Capturing Values.)
インスタンスの asHTML
プロパティは、クロージャへの強参照を保持します。 ただし、クロージャは本体内で self
を参照するため(self.name
と self.text
を参照する方法として)、クロージャは self をキャプチャします。これは、HTMLElement
インスタンスへの強参照を保持していることを意味します。 両者の間には強参照サイクルが形成されます。 (クロージャ内の値のキャプチャの詳細については、「値の取得」を参照してください。)
Note
注釈
Even though the closure refers to self
multiple times, it only captures one strong reference to the HTMLElement
instance.
クロージャは self
を複数回参照していますが、HTMLElement
インスタンスへの強参照は 1 つだけキャプチャされます。
If you set the paragraph
variable to nil
and break its strong reference to the HTMLElement
instance, the strong reference cycle prevents deallocating both the HTMLElement
instance and its closure:
paragraph
変数を nil
に設定し、HTMLElement
インスタンスへの強参照を解除しても、強参照サイクルにより HTMLElement
インスタンスとそのクロージャの両方の割り当てが解除されません。
paragraph = nil
Note that the message in the HTMLElement
deinitializer isn’t printed, which shows that the HTMLElement
instance isn’t deallocated.
HTMLElement
初期化解除子のメッセージは出力されないことに注意してください。これは、HTMLElement
インスタンスの割り当てが解除されていないことを示しています。
Resolving Strong Reference Cycles for Closures
クロージャの強参照サイクルの解決
You resolve a strong reference cycle between a closure and a class instance by defining a capture list as part of the closure’s definition. A capture list defines the rules to use when capturing one or more reference types within the closure’s body. As with strong reference cycles between two class instances, you declare each captured reference to be a weak or unowned reference rather than a strong reference. The appropriate choice of weak or unowned depends on the relationships between the different parts of your code.
クロージャとクラス インスタンスの間の強参照サイクルを解決するには、クロージャの定義の一部としてキャプチャ リストを定義します。 キャプチャ リストは、クロージャ本体内の 1 つ以上の参照型をキャプチャするときに使用するルールを定義します。 2 つのクラス インスタンス間の強参照サイクルと同様に、キャプチャされた各参照を、強参照ではなく弱参照または非所有参照として宣言します。 弱いか非所有かの適切な選択は、コードのさまざまな部分間の関係によって異なります。
Note
注釈
Swift requires you to write self.someProperty
or self.someMethod()
(rather than just someProperty
or someMethod()
) whenever you refer to a member of self
within a closure. This helps you remember that it’s possible to capture self
by accident.
Swift では、クロージャ内で self
のメンバーを参照するときは常に、self.someProperty
または self.someMethod()
(someProperty
または someMethod()
だけではなく) を記述する必要があります。 これは、突発的ににself
をキャプチャする可能性があることを思い出すのに役立ちます。
Defining a Capture List
キャプチャリストの定義
Each item in a capture list is a pairing of the weak
or unowned
keyword with a reference to a class instance (such as self
) or a variable initialized with some value (such as delegate = self.delegate
). These pairings are written within a pair of square braces, separated by commas.
キャプチャ リストの各項目は、weak
キーワードまたはunowned
キーワードと、クラス インスタンス(self
など)または何らかの値で初期化された変数(delegate = self.delegate
など)への参照との組み合わせです。 これらのペアは、カンマで区切られた 1 対の大括弧内に記述されます。
Place the capture list before a closure’s parameter list and return type if they’re provided:
キャプチャ リストをクロージャのパラメータ リストの前に配置し、提供されている場合は戻り値の型を返します。
lazy var someClosure = {
[unowned self, weak delegate = self.delegate]
(index: Int, stringToProcess: String) -> String in
// closure body goes here
}
If a closure doesn’t specify a parameter list or return type because they can be inferred from context, place the capture list at the very start of the closure, followed by the in
keyword:
コンテキストから推測できるため、クロージャでパラメータ リストまたは戻り値の型を指定しない場合は、キャプチャ リストをクロージャの先頭に配置し、その後に in
キーワードを配置します。
lazy var someClosure = {
[unowned self, weak delegate = self.delegate] in
// closure body goes here
}
Weak and Unowned References
弱参照と非所有参照
Define a capture in a closure as an unowned reference when the closure and the instance it captures will always refer to each other, and will always be deallocated at the same time.
クロージャとそれがキャプチャするインスタンスが常に相互参照し、常に同時に割り当て解除される場合は、クロージャ内のキャプチャを非所有参照として定義します。
Conversely, define a capture as a weak reference when the captured reference may become nil
at some point in the future. Weak references are always of an optional type, and automatically become nil
when the instance they reference is deallocated. This enables you to check for their existence within the closure’s body.
逆に、キャプチャされた参照が将来のある時点で nil
になる可能性がある場合は、キャプチャを弱参照として定義します。 弱参照は常にオプションのタイプであり、参照するインスタンスの割り当てが解除されると自動的に nil
になります。 これにより、クロージャーの本体内にそれらが存在するかどうかを確認できます。
Note
注釈
If the captured reference will never become nil
, it should always be captured as an unowned reference, rather than a weak reference.
キャプチャされた参照が決して nil
にならない場合、それは弱参照ではなく、常に非所有参照としてキャプチャされる必要があります。
An unowned reference is the appropriate capture method to use to resolve the strong reference cycle in the HTMLElement
example from Strong Reference Cycles for Closures above. Here’s how you write the HTMLElement
class to avoid the cycle:
非所有参照は、上記のクロージャの強参照サイクルの HTMLElement
の例で、強参照サイクルを解決するために使用する適切なキャプチャ方法です。 サイクルを回避するために HTMLElement
クラスを記述する方法は次のとおりです。
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
[unowned self] in
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
This implementation of HTMLElement
is identical to the previous implementation, apart from the addition of a capture list within the asHTML
closure. In this case, the capture list is [unowned self]
, which means “capture self as an unowned reference rather than a strong reference”.
HTMLElement
のこの実装は、asHTML
クロージャ内にキャプチャ リストが追加されていることを除けば、前の実装と同じです。 この場合、キャプチャ リストは [unowned self]
であり、「強参照ではなく非所有参照として self
をキャプチャする」ことを意味します。
You can create and print an HTMLElement
instance as before:
以前と同様に、HTMLElement
インスタンスを作成して出力できます。
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
// Prints "<p>hello, world</p>"
Here’s how the references look with the capture list in place:
キャプチャ リストが配置された場合の参照は次のようになります。
This time, the capture of self
by the closure is an unowned reference, and doesn’t keep a strong hold on the HTMLElement
instance it has captured. If you set the strong reference from the paragraph
variable to nil
, the HTMLElement
instance is deallocated, as can be seen from the printing of its deinitializer message in the example below:
今回、クロージャによる self
のキャプチャは非所有参照であり、キャプチャした HTMLElement
インスタンスを強力に保持しません。 paragraph
変数からの強参照を nil
に設定すると、以下の例の初期化解除メッセージの出力からわかるように、HTMLElement
インスタンスの割り当てが解除されます。
paragraph = nil
// Prints "p is being deinitialized"
For more information about capture lists, see Capture Lists.
キャプチャ リストの詳細については、「キャプチャ リスト」を参照してください。