Swift Language
メモリ管理
サーチ…
前書き
Unmanaged
] [1]構造を使用することができます。 [1]:https://developer.apple.com/reference/swift/unmanaged
備考
弱いキーワードを使用する場合:
参照を保持しているオブジェクトの存続期間中に参照オブジェクトが割り当て解除される可能性がある場合は、weak
キーワードを使用する必要があります。 unowned-keywordを使用するタイミング:
参照されたオブジェクトが参照を保持するオブジェクトの存続期間中に割り当て解除されることが予想されない場合、unowned
キーワードを使用する必要があります。 落とし穴
頻繁に起こるエラーは、機能が終了した後で生活する必要があるオブジェクトへの参照を作成することを忘れてしまうことです(ロケーションマネージャやモーションマネージャなど)。例:
class A : CLLocationManagerDelegate
{
init()
{
let locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.startLocationUpdates()
}
}
この例は、イニシャライザが戻った後にロケーションマネージャが割り当て解除されるため、正常に動作しません。適切な解決策は、インスタンス変数としての強力な参照を作成することです。
class A : CLLocationManagerDelegate
{
let locationManager:CLLocationManager
init()
{
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.startLocationUpdates()
}
}
リファレンスサイクルと弱い参照
参照サイクル (または保持サイクル )は、 オブジェクトグラフの サイクルを示すため、その名前が付けられています。
各矢印は、あるオブジェクトが別のオブジェクトを保持していることを示します(強い参照)。サイクルが壊れていない限り、これらのオブジェクトのメモリは決して解放されません 。
保持サイクルは、クラスの2つのインスタンスが互いに参照するときに作成されます。
class A { var b: B? = nil }
class B { var a: A? = nil }
let a = A()
let b = B()
a.b = b // a retains b
b.a = a // b retains a -- a reference cycle
両方のインスタンスは、プログラムが終了するまで存続します。これは保持サイクルです。
弱い参照
保持サイクルを回避するには、保持サイクルをunowned
参照を作成するときにキーワードweak
またはunowned
使用します。
class B { weak var a: A? = nil }
弱いまたは所有されていない参照は、インスタンスの参照カウントを増加させません。これらの参考文献は、保持サイクルに寄与しない。 weak参照は 、それが参照するオブジェクトの割り当てが解除されるとnil
になります。
a.b = b // a retains b
b.a = a // b holds a weak reference to a -- not a reference cycle
クロージャを操作するときには、キャプチャリストにweak
とunowned
を使用することもできます 。
手動メモリ管理
C APIとのインタフェース時に、Swiftリファレンスカウンタをオフにしたい場合があります。これを行うには、アンマネージオブジェクトを使用します。
C関数に型打ちポインタを渡す必要がある場合は、 Unmanaged
構造体のtoOpaque
メソッドを使用して未加工のポインタを取得し、 fromOpaque
を使用して元のインスタンスを復元します。
setupDisplayLink() {
let pointerToSelf: UnsafeRawPointer = Unmanaged.passUnretained(self).toOpaque()
CVDisplayLinkSetOutputCallback(self.displayLink, self.redraw, pointerToSelf)
}
func redraw(pointerToSelf: UnsafeRawPointer, /* args omitted */) {
let recoveredSelf = Unmanaged<Self>.fromOpaque(pointerToSelf).takeUnretainedValue()
recoveredSelf.doRedraw()
}
passUnretained
とcounterpartsを使用する場合、 unowned
れていunowned
参照と同様に、すべての予防措置を取る必要があることに注意してください。
レガシーObjective-C APIと対話するには、特定のオブジェクトの参照カウントに手動で影響を与えたい場合があります。そのため、 Unmanaged
はそれぞれのメソッドがretain
、 release
ます。それにもかかわらず、結果を返す前に保持を実行するpassRetained
とtakeRetainedValue
を使用する方が望ましいです。
func preferredFilenameExtension(for uti: String) -> String! {
let result = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension)
guard result != nil else { return nil }
return result!.takeRetainedValue() as String
}
これらのソリューションは常に最後の手段であるべきであり、言語固有のAPIが常に優先されるべきです。