Swift Language
메모리 관리
수색…
소개
Unmanaged
] [1] 구조를 사용할 수 있습니다. [1] : https://developer.apple.com/reference/swift/unmanaged
비고
약 키워드를 사용하는 경우 :
참조를 보유한 객체의 수명 동안 참조 된 객체의 할당을 해제 할 수있는 경우weak
키워드를 사용해야합니다. 소유되지 않은 키워드를 사용하는 경우 :
참조 된 객체가 참조를 보유한 객체의 수명 동안 할당 해제 될 것으로 예상되지 않으면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()
}
}
참조주기 및 약한 참조
참조주기 (또는 유지주기 )는 객체 그래프 의 주기 를 나타 내기 때문에 그렇게 명명 됩니다 .
각 화살표는 하나의 객체가 다른 객체를 유지하고 있음을 나타냅니다 (강력한 참조). 주기가 깨지지 않는 한,이 오브젝트에 대한 메모리는 절대로 해제되지 않습니다 .
두 개의 클래스 인스턴스가 서로 참조 할 때 보관주기가 생성됩니다.
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
두 인스턴스 모두 프로그램이 종료 될 때까지 계속 살게됩니다. 이것은 유지주기입니다.
약한 참조
보유주기를 피하려면 참조를 작성하여 보유주기를 중단 할 때 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를 사용하는 경우 passUnretained
가 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가 항상 선호 될 수 있습니다.