약한 참조와 소유되지 않은 참조의 차이점은 무엇입니까?


240

스위프트는 :

  • 강력한 참조
  • 약한 참조
  • 소유되지 않은 참조

소유하지 않은 참조는 약한 참조와 어떻게 다릅니 까?

소유하지 않은 참조를 사용하는 것이 언제 안전합니까?

소유되지 않은 참조는 C / C ++에서 매달려있는 포인터 와 같은 보안 위험 요소 입니까?



내 경험을 사용하는 것입니다 unowned, 애플 클래스, 우리가 제어하는 클래스를 사용하기 weak때문에 우리가 할 수있는 그 무엇을 확실히하지 보증
onmyway133

@NoorAli 또는 "ownedBy"는 "소유하지 않은"참조가 종종 소유자를 가리 킵니다.
Ian Ringrose

답변:


361

참조 weakunowned참조 둘 다 참조 된 strong오브젝트를 보류 하지 않습니다 (일명, ARC가 참조 된 오브젝트를 할당 해제하기 위해 보유 수를 늘리지 않습니다).

그러나 왜 두 개의 키워드가 있습니까? 이 구별은 Optional유형이 Swift 언어에 내장 되어 있다는 사실과 관련이 있습니다. 그들에 대한 긴 이야기를 짧게 : 옵션 유형 (이 아름답게 작동 메모리의 안전을 제공 스위프트의 생성자 규칙 -이 혜택을 제공하기 위해 엄격하다).

weak참조는 그것의 가능성이 될 수 있습니다 nil당신은, 프로그래머로서, 당신은 기본적으로 (그것을 사용하기 전에 그것을 확인 할 의무가 있으므로 - (이것은 자동으로 참조 된 개체가 해제 될 때 발생) 그러므로 재산의 유형을 선택해야합니다 컴파일러는 가능한 한 안전 코드를 작성하도록합니다.

unowned참조 가정 그것은 결코 될 것이라고 nil수명 동안. 소유되지 않은 참조는 초기화 중에 설정되어야합니다. 즉, 참조는 검사없이 안전하게 사용할 수있는 비 선택적 유형으로 정의됩니다. 어떻게 든 참조되는 객체가 할당 해제되면 소유되지 않은 참조가 사용될 때 앱이 중단됩니다.

로부터 애플 문서 :

평생 동안 어느 시점에서 해당 참조가 0이 될 때마다 약한 참조를 사용하십시오. 반대로 초기화하는 동안 참조가 설정된 후에는 절대 참조가 없음을 알 때 소유하지 않은 참조를 사용하십시오.

문서에는 보유주기와 중단 방법에 대해 설명하는 몇 가지 예가 있습니다. 이 모든 예제는 문서 에서 추출됩니다 .

weak키워드 예 :

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
}

class Apartment {
    let number: Int
    init(number: Int) { self.number = number }
    weak var tenant: Person?
}

이제 ASCII 아트의 경우 ( 문서를 보러 가야 합니다 -예쁜 다이어그램이 있습니다).

Person ===(strong)==> Apartment
Person <==(weak)===== Apartment

PersonApartment예를 도시 전무로 할 수있다 둘 두 속성이 강한 기준주기를 일으킬 가능성이있는 상황. 이 시나리오는 약한 참조로 가장 잘 해결됩니다. 두 엔터티는 다른 엔터티에 대한 엄격한 종속성없이 존재할 수 있습니다.

unowned키워드 예 :

class Customer {
    let name: String
    var card: CreditCard?
    init(name: String) { self.name = name }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer
    init(number: UInt64, customer: Customer) { self.number = number; self.customer = customer }
}

이 예에서 a Customer는을 갖거나 갖지 않을 수 CreditCard있지만 a CreditCard 는 항상 a와 연결됩니다 Customer. 이를 나타 내기 위해 Customer클래스에는 선택적 card속성이 있지만 CreditCard클래스에는 비 선택적이며 소유되지 않은 customer속성이 있습니다.

Customer ===(strong)==> CreditCard
Customer <==(unowned)== CreditCard

CustomerCreditCard예를 도시 한 것으로 닐 허용 성 및 무 수없는 또 다른 속성은 강한 기준주기를 일으킬 가능성이있는 상황. 이 시나리오는 소유하지 않은 참조로 해결하는 것이 가장 좋습니다.

애플 노트 :

약한 참조는 변수로 선언되어 값이 런타임에 변경 될 수 있음을 나타냅니다. 약한 참조는 상수로 선언 될 수 없습니다.

두 속성이 항상 값을 가져야하고 초기화가 완료되면 두 속성이 모두 0이되어서는 안되는 세 번째 시나리오도 있습니다.

또한 클로저로 작업 할 때 피해야 할 클래식 유지주기 시나리오도 있습니다.

이를 위해 Apple 문서 를 방문 하거나 책을 읽으 십시오 .


3
이것은 다소 사소한 것이지만 아파트와 사람의 예가 다소 혼란 스럽습니다. 이는 강력한 참조주기를 깰 수있는 추가 솔루션을 제시합니다. 개인의 아파트는 선택 사항이므로 묵인 일 수 있으며 아파트의 임차인은 선택 사항이므로 닐이 될 수 있으므로 두 속성을 모두 약한 것으로 정의 할 수 있습니다. ```
Justin Levi Winter

class Person {let name : String init (name : String) {self.name = name} 약한 var 아파트 : 아파트? } class Apartment {let number : Int init (number : Int) {self.number = number} 약한 세입자 : 사람? }
Justin Levi Winter

3
의 차이 무엇입니까 weak var Person?대는 var Person??
Dean

4
@JustinLevi, 두 속성을 모두 약한 것으로 선언하면 할당이 취소 될 수 있습니다. 개인은 아파트를 강력하게 참조하므로 아파트는 할당 해제되지 않습니다. 아파트가 Person에 대해 동일한 참조를 가질 경우, 유지주기를 작성합니다. 프로그래머가 알고 있으면 런타임시 프로그래머가 중단 할 수 있지만 그렇지 않으면 메모리 누수 일뿐입니다. ARC가 우리를 위해 모든 더러운 것들을 수행하기 때문에 이것은 더 높은 수준의 메모리 관리입니다. 유지주기를 피하는 것이 우리의 임무입니다.
Ilea Cristian

1
소유하지 않은 것보다 약한 것의 유일한 이점은 포장을 풀 필요가 없으며 상수를 사용할 수 있다는 것입니다. 약한 것을 사용할 수없고 소유하지 않은 경우 만있는 경우가 있습니까?
Alan

29

Q1. "소유되지 않은 참조"는 "약한 참조"와 어떻게 다릅니 까?

약한 참조 :

약한 참조는 참조하는 인스턴스를 강력하게 유지하지 않는 참조이므로 ARC가 참조 된 인스턴스의 처리를 중지하지 않습니다. 약한 참조에는 "값 없음"이 허용되므로 모든 약한 참조는 선택적 유형을 갖는 것으로 선언해야합니다. (애플 문서)

소유하지 않은 참조 :

약한 참조와 마찬가지로 소유되지 않은 참조는 참조하는 인스턴스를 강력하게 유지하지 않습니다. 그러나 약한 참조와 달리 소유하지 않은 참조는 항상 값을 갖는 것으로 가정합니다. 이로 인해 소유되지 않은 참조는 항상 비 선택적 유형으로 정의됩니다. (애플 문서)

각각 사용시기 :

평생 동안 어느 시점에서 해당 참조가 0이 될 때마다 약한 참조를 사용하십시오. 반대로 초기화하는 동안 참조가 설정되지 않은 경우 참조가 없음을 알 때 소유하지 않은 참조를 사용하십시오. (애플 문서)


Q2. "소유되지 않은 참조"를 사용하는 것이 언제 안전합니까?

위에서 인용 한 바와 같이, 소유되지 않은 참조는 항상 값을 갖는 것으로 가정합니다. 따라서 참조가 절대로 0이 아니라고 확신 할 때만 사용해야합니다. Apple Docs는 다음 예제를 통해 소유되지 않은 참조의 사용 사례를 보여줍니다.

우리는 두 개의 클래스가 있다고 가정 Customer하고이 CreditCard. 고객은 신용 카드없이 존재할 수 있지만 신용 카드는 고객없이 존재할 수 없습니다. 즉, 신용 카드에는 항상 고객이 있다고 가정 할 수 있습니다. 따라서 다음과 같은 관계가 있어야합니다.

class Customer {
    var card: CreditCard?
}

class CreditCard {
    unowned let customer: Customer
}

Q3. C / C ++의 "포인팅 포인터"와 같은 보안 위험을 "소유되지 않은 참조"참조

나는 그렇게 생각하지 않습니다.

소유되지 않은 참조는 가치가 보장되는 약한 참조이므로 보안 위험이 없어야합니다. 그러나 참조하는 인스턴스가 할당 해제 된 후 소유되지 않은 참조에 액세스하려고하면 런타임 오류가 발생하고 앱이 중단됩니다.

그것이 내가 볼 수있는 유일한 위험입니다.

Apple Docs에 연결


소유하지 않은 .thanks에 대해 이해하기 쉬운 Q2 예제 프로그램. 약하고 강한 것에 대해 동일한 유형의 예제를 추가 할 수 있습니다.
Ranjith Kumar

우수한. 감사합니다.
Swifty McSwifterton

소유하지 않거나 약한 사람에 대한 일반적인 예를 포함시킬 수 있습니까?
Honey

부모없이 자식이 존재할 수없는 경우 부모 및 자식 개체를 고려한 다음 unowned자식 클래스에서 부모 속성 을 사용 하십시오. 약한 경우도 마찬가지입니다. @myxtic 좋은 설명! unowned참조는 weak값을 갖도록 보장 된 참조 일뿐 입니다!
Saif

26

클로저에 self 가 없을 경우 [weak self]를 사용하십시오 .

클로저에서 자아 가 전혀없는 경우 [소유하지 않은 자아] .

[소유하지 않은 자아] 를 사용할 때 충돌이 발생하면 해당 폐쇄의 어느 시점에서 자아가 없을 수 있으며 대신 [약한 자아] 를 사용해야 합니다.

strong , weak , unowned 클로저 사용에 대한 예제를 확인하십시오 .

https://developer.apple.com/library/ios/documentation/swift/conceptual/swift_programming_language/AutomaticReferenceCounting.html


7
자존심이 전혀없고 해를 입히지 않아도 약한 것을 사용하는 것이 어떻습니까?
Boon

4
안녕 @ 분-그것은 정말 중요한 질문입니다.
Fattie

[약한 자기] => viewDidLoad () 내부에서 클로저를 사용하면 어떻게 selfnil이 될 수 있습니까?
Hassan Tareq

@HassanTareq, 나는 위에서 언급 한 기사에서 몇 가지 좋은 예가 언급되어 있다고 생각합니다. "닫힘에 대한 강력한 참조 사이클 해결"섹션, esp. Quote : "Swift에서는 클로저 내에서 self 멤버를 참조 할 때마다 someProperty 또는 someMethod () 대신 self.someProperty 또는 self.someMethod ()를 작성해야합니다. 사고." 발췌 : Apple Inc.“Swift Programming Language (Swift 4).” iBooks. itunes.apple.com/de/book/the-swift-programming-language-swift-4/… "
Nick Entin

1
@Boon 당신이 항상 weak를 사용한다면, 컴파일러는 사용하기 전에 옵션을 체크하도록 강제 할 것입니다. 해당 검사를하지 않으면 컴파일 시간 오류가 발생합니다. 다른 해가 없습니다.
Vikas Mishra

5

링크 에서 추출

결말 포인트

  • 강하거나 약하거나 소유하지 않은 것에 대해 걱정해야하는지 확인하려면“참조 유형을 처리하고 있습니까?”라고 문의하십시오. Structs 또는 Enum을 사용하는 경우 ARC는 해당 유형의 메모리를 관리하지 않으므로 해당 상수 또는 변수에 대해 약하거나 소유하지 않은 것을 지정할 필요조차 없습니다.
  • 강한 참조는 부모가 자식을 참조하는 계층 적 관계에서는 훌륭하지만 그 반대는 아닙니다. 실제로, 강력한 참조는 대부분의 경우 가장 적절한 종류의 참조입니다.
  • 두 인스턴스가 선택적으로 서로 관련이있는 경우 해당 인스턴스 중 하나가 다른 인스턴스에 대한 약한 참조를 보유해야합니다.
  • 두 인스턴스가 다른 인스턴스없이 존재할 수없는 방식으로 관련되는 경우 필수 종속성이있는 인스턴스는 다른 인스턴스에 대한 소유되지 않은 참조를 보유해야합니다.

1

weakunowned참조는 객체의 참조 횟수에 영향을 미치지 않습니다. 그러나 약한 참조는 항상 선택 사항입니다. 즉, nil 일 수 있지만 unowned참조는 nil이 될 수 없으므로 절대로 선택 사항이 아닙니다. 선택적 참조를 사용하는 경우 항상 객체가 없음 일 가능성을 처리해야합니다. 소유되지 않은 참조의 경우 객체가 절대로 0이 아닌지 확인해야합니다. nil 객체에 대해 소유되지 않은 참조를 사용하는 것은 nil 인 옵션을 강제로 래핑 해제하는 것과 비슷합니다.

즉, 객체의 수명이 참조의 수명보다 길다는 확신이없는 경우 소유되지 않은 참조를 사용하는 것이 안전합니다. 그렇지 않은 경우 대신 약한 참조를 사용하는 것이 좋습니다.

질문의 세 번째 부분은 소유하지 않은 참조가 매달려있는 포인터와 비슷하지 않다고 생각합니다. 우리는 참조 횟수에 대해 말할 때 일반적으로 물체의 강한 참조 횟수를 말합니다. 마찬가지로 swift는 객체에 대해 소유되지 않은 참조 카운트와 약한 참조 카운트를 유지합니다 (참조 포인트는 객체 자체가 아닌 "사이드 테이블"이라고 함). 강력한 참조 카운트가 0에 도달하면 객체가 초기화되지 않지만 소유되지 않은 참조 카운트가 0보다 크면 할당을 해제 할 수 없습니다.

이제 매달려있는 포인터는 이미 할당이 해제 된 메모리 위치를 가리키는 것입니다. 그러나 객체에 대해 소유되지 않은 참조가있는 한 메모리를 할당 해제 할 수 있기 때문에 매달려있는 포인터를 만들 수 없습니다.

신속한 메모리 관리에 대해 자세히 설명하는 기사가 많이 있습니다. 여기 하나입니다.


0

소유되지 않은 참조는 한 객체가 다른 객체 만 소유해야하는 경우 두 객체 간의 동일 수명 관계의 경우에 사용되는 일종의 약한 참조입니다. 객체와 속성 중 하나 사이에 불변 바인딩을 만드는 방법입니다.

중간 신속한 WWDC 비디오에 제공된 예에서 개인은 신용 카드를 소유하며 신용 카드는 한 명의 소유자 만 가질 수 있습니다. 신용 카드의 경우, 한 명의 소유자 만 신용 카드를 떠 다니고 싶지 않기 때문에 그 사람은 선택 재산이되어서는 안됩니다. 크레디트의 holder 속성을 약한 참조로 만들어이주기를 중단 할 수 있지만, 상수와 달리 옵션뿐만 아니라 가변으로 만들어야합니다. 이 경우 소유권이없는 참조는 CreditCard에 개인에 대한 지분이 없지만 그 수명은 그에 달려 있음을 의미합니다.

class Person {
    var card: CreditCard?
}

class CreditCard {

    unowned let holder: Person

    init (holder: Person) {
        self.holder = holder
    }
}

wwdc 비디오 또는 제목 링크?
Osa

-2

액세스 지점에 절대 도달 할 수없는 unowned경우 사용selfnilself해당 시점에 .

예 (물론 직접 대상을 추가 할 수는 MyViewController있지만 간단한 예입니다.)

class MyViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let myButton = MyButton { [unowned self] in
            print("At this point, self can NEVER be nil. You are safe to use unowned.")
            print("This is because myButton can not be referenced without/outside this instance (myViewController)")
        }
    }
}

class MyButton: UIButton {
    var clicked: (() -> ())

    init(clicked: (() -> ())) {
        self.clicked = clicked

        // We use constraints to layout the view. We don't explicitly set the frame.
        super.init(frame: .zero)

        addTarget(self, action: #selector(clicked), for: .touchUpInside)
    }

    @objc private func sendClosure() {
        clicked()
    }
}

액세스 weakself수 있는 가능성이있을 때 사용nilself .

예:

class MyViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        NetworkManager.sharedInstance.receivedData = { [weak self] (data) in
            print("Can you guarentee that self is always available when the network manager received data?")
            print("Nope, you can't. Network manager will be alive, regardless of this particular instance of MyViewController")
            print("You should use weak self here, since you are not sure if this instance is still alive for every")
            print("future callback of network manager")
        }
    }
}

class NetworkManager {

    static let sharedInstance = NetworkManager()

    var receivedData: ((Data) -> ())?

    private func process(_ data: Data) {
        // process the data...

        // ... eventually notify a possible listener.
        receivedData?(data)
    }
}

단점 unowned:

  • 약한 것보다 더 효율적
  • 인스턴스를 불변으로 표시하도록 강요 할 수 있습니다 (Swift 5.0 이후로는 더 이상).
  • 코드 리더에게 나타냅니다.이 인스턴스는 X와 관계가 있으며 X 없이는 살 수 없지만 X가 사라지면 나도 사라집니다.

단점 weak:

  • 소유하지 않은 것보다 안전합니다 (충돌 할 수 없기 때문에).
  • 두 가지 방식으로 진행되는 X와의 관계를 만들 수 있지만 둘 다 서로없이 살 수 있습니다.

확실하지 않은 경우을 사용하십시오 weak. 잠깐 , StackOverflow에서 귀하의 경우에 무엇을 해야하는지 물어보십시오. 항상 약한 것을 사용하면 안된다고 생각하는 사람과 당신의 코드 독자에게 혼동하지 마십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.