수색…


소개

이 항목에서는 Swift 런타임이 응용 프로그램 데이터 구조에 메모리를 할당하는 방법과시기와 해당 메모리를 회수해야 할시기를 설명합니다. 기본적으로 메모리 백업 클래스 인스턴스는 참조 카운팅을 통해 관리됩니다. 구조는 항상 복사를 통해 전달됩니다. 내장 된 메모리 관리 체계를 거부하려면 [ 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

클로저를 사용하여 작업 할 때는 캡처 목록에 weakunowned 사용할 수도 있습니다.

수동 메모리 관리

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를 사용하는 경우 passUnretainedunowned 참조와 마찬가지로 모든 예방 조치를 취해야합니다.

레거시 Objective-C API와 상호 작용하려면 특정 개체의 참조 횟수에 수동으로 영향을 줄 수 있습니다. 그 때문에 Unmanaged 는 각각의 메소드를 retain 하고 release 합니다. 그럼에도 불구하고 결과를 반환하기 전에 보유를 수행하는 passRetainedtakeRetainedValue 를 사용하는 것이 더 바람직합니다.

func preferredFilenameExtension(for uti: String) -> String! {
  let result = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension)
  guard result != nil else { return nil }

  return result!.takeRetainedValue() as String
}

이러한 솔루션은 항상 최후의 수단이어야하며 언어 고유 API가 항상 선호 될 수 있습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow