스위프트는 :
- 강력한 참조
- 약한 참조
- 소유되지 않은 참조
소유하지 않은 참조는 약한 참조와 어떻게 다릅니 까?
소유하지 않은 참조를 사용하는 것이 언제 안전합니까?
소유되지 않은 참조는 C / C ++에서 매달려있는 포인터 와 같은 보안 위험 요소 입니까?
unowned
, 애플 클래스, 우리가 제어하는 클래스를 사용하기 weak
때문에 우리가 할 수있는 그 무엇을 확실히하지 보증
스위프트는 :
소유하지 않은 참조는 약한 참조와 어떻게 다릅니 까?
소유하지 않은 참조를 사용하는 것이 언제 안전합니까?
소유되지 않은 참조는 C / C ++에서 매달려있는 포인터 와 같은 보안 위험 요소 입니까?
unowned
, 애플 클래스, 우리가 제어하는 클래스를 사용하기 weak
때문에 우리가 할 수있는 그 무엇을 확실히하지 보증
답변:
참조 weak
와 unowned
참조 둘 다 참조 된 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
Person
및 Apartment
예를 도시 전무로 할 수있다 둘 두 속성이 강한 기준주기를 일으킬 가능성이있는 상황. 이 시나리오는 약한 참조로 가장 잘 해결됩니다. 두 엔터티는 다른 엔터티에 대한 엄격한 종속성없이 존재할 수 있습니다.
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
Customer
및 CreditCard
예를 도시 한 것으로 닐 허용 성 및 무 수없는 또 다른 속성은 강한 기준주기를 일으킬 가능성이있는 상황. 이 시나리오는 소유하지 않은 참조로 해결하는 것이 가장 좋습니다.
애플 노트 :
약한 참조는 변수로 선언되어 값이 런타임에 변경 될 수 있음을 나타냅니다. 약한 참조는 상수로 선언 될 수 없습니다.
두 속성이 항상 값을 가져야하고 초기화가 완료되면 두 속성이 모두 0이되어서는 안되는 세 번째 시나리오도 있습니다.
또한 클로저로 작업 할 때 피해야 할 클래식 유지주기 시나리오도 있습니다.
weak var Person?
대는 var Person?
?
Q1. "소유되지 않은 참조"는 "약한 참조"와 어떻게 다릅니 까?
약한 참조 :
약한 참조는 참조하는 인스턴스를 강력하게 유지하지 않는 참조이므로 ARC가 참조 된 인스턴스의 처리를 중지하지 않습니다. 약한 참조에는 "값 없음"이 허용되므로 모든 약한 참조는 선택적 유형을 갖는 것으로 선언해야합니다. (애플 문서)
소유하지 않은 참조 :
약한 참조와 마찬가지로 소유되지 않은 참조는 참조하는 인스턴스를 강력하게 유지하지 않습니다. 그러나 약한 참조와 달리 소유하지 않은 참조는 항상 값을 갖는 것으로 가정합니다. 이로 인해 소유되지 않은 참조는 항상 비 선택적 유형으로 정의됩니다. (애플 문서)
각각 사용시기 :
평생 동안 어느 시점에서 해당 참조가 0이 될 때마다 약한 참조를 사용하십시오. 반대로 초기화하는 동안 참조가 설정되지 않은 경우 참조가 없음을 알 때 소유하지 않은 참조를 사용하십시오. (애플 문서)
Q2. "소유되지 않은 참조"를 사용하는 것이 언제 안전합니까?
위에서 인용 한 바와 같이, 소유되지 않은 참조는 항상 값을 갖는 것으로 가정합니다. 따라서 참조가 절대로 0이 아니라고 확신 할 때만 사용해야합니다. Apple Docs는 다음 예제를 통해 소유되지 않은 참조의 사용 사례를 보여줍니다.
우리는 두 개의 클래스가 있다고 가정 Customer
하고이 CreditCard
. 고객은 신용 카드없이 존재할 수 있지만 신용 카드는 고객없이 존재할 수 없습니다. 즉, 신용 카드에는 항상 고객이 있다고 가정 할 수 있습니다. 따라서 다음과 같은 관계가 있어야합니다.
class Customer {
var card: CreditCard?
}
class CreditCard {
unowned let customer: Customer
}
Q3. C / C ++의 "포인팅 포인터"와 같은 보안 위험을 "소유되지 않은 참조"참조
나는 그렇게 생각하지 않습니다.
소유되지 않은 참조는 가치가 보장되는 약한 참조이므로 보안 위험이 없어야합니다. 그러나 참조하는 인스턴스가 할당 해제 된 후 소유되지 않은 참조에 액세스하려고하면 런타임 오류가 발생하고 앱이 중단됩니다.
그것이 내가 볼 수있는 유일한 위험입니다.
unowned
자식 클래스에서 부모 속성 을 사용 하십시오. 약한 경우도 마찬가지입니다. @myxtic 좋은 설명! unowned
참조는 weak
값을 갖도록 보장 된 참조 일뿐 입니다!
클로저에 self 가 없을 경우 [weak self]를 사용하십시오 .
클로저에서 자아 가 전혀없는 경우 [소유하지 않은 자아] .
[소유하지 않은 자아] 를 사용할 때 충돌이 발생하면 해당 폐쇄의 어느 시점에서 자아가 없을 수 있으며 대신 [약한 자아] 를 사용해야 합니다.
strong , weak , unowned 클로저 사용에 대한 예제를 확인하십시오 .
self
nil이 될 수 있습니까?
링크 에서 추출
결말 포인트
두 weak
및 unowned
참조는 객체의 참조 횟수에 영향을 미치지 않습니다. 그러나 약한 참조는 항상 선택 사항입니다. 즉, nil 일 수 있지만 unowned
참조는 nil이 될 수 없으므로 절대로 선택 사항이 아닙니다. 선택적 참조를 사용하는 경우 항상 객체가 없음 일 가능성을 처리해야합니다. 소유되지 않은 참조의 경우 객체가 절대로 0이 아닌지 확인해야합니다. nil 객체에 대해 소유되지 않은 참조를 사용하는 것은 nil 인 옵션을 강제로 래핑 해제하는 것과 비슷합니다.
즉, 객체의 수명이 참조의 수명보다 길다는 확신이없는 경우 소유되지 않은 참조를 사용하는 것이 안전합니다. 그렇지 않은 경우 대신 약한 참조를 사용하는 것이 좋습니다.
질문의 세 번째 부분은 소유하지 않은 참조가 매달려있는 포인터와 비슷하지 않다고 생각합니다. 우리는 참조 횟수에 대해 말할 때 일반적으로 물체의 강한 참조 횟수를 말합니다. 마찬가지로 swift는 객체에 대해 소유되지 않은 참조 카운트와 약한 참조 카운트를 유지합니다 (참조 포인트는 객체 자체가 아닌 "사이드 테이블"이라고 함). 강력한 참조 카운트가 0에 도달하면 객체가 초기화되지 않지만 소유되지 않은 참조 카운트가 0보다 크면 할당을 해제 할 수 없습니다.
이제 매달려있는 포인터는 이미 할당이 해제 된 메모리 위치를 가리키는 것입니다. 그러나 객체에 대해 소유되지 않은 참조가있는 한 메모리를 할당 해제 할 수 있기 때문에 매달려있는 포인터를 만들 수 없습니다.
신속한 메모리 관리에 대해 자세히 설명하는 기사가 많이 있습니다. 여기 하나입니다.
소유되지 않은 참조는 한 객체가 다른 객체 만 소유해야하는 경우 두 객체 간의 동일 수명 관계의 경우에 사용되는 일종의 약한 참조입니다. 객체와 속성 중 하나 사이에 불변 바인딩을 만드는 방법입니다.
중간 신속한 WWDC 비디오에 제공된 예에서 개인은 신용 카드를 소유하며 신용 카드는 한 명의 소유자 만 가질 수 있습니다. 신용 카드의 경우, 한 명의 소유자 만 신용 카드를 떠 다니고 싶지 않기 때문에 그 사람은 선택 재산이되어서는 안됩니다. 크레디트의 holder 속성을 약한 참조로 만들어이주기를 중단 할 수 있지만, 상수와 달리 옵션뿐만 아니라 가변으로 만들어야합니다. 이 경우 소유권이없는 참조는 CreditCard에 개인에 대한 지분이 없지만 그 수명은 그에 달려 있음을 의미합니다.
class Person {
var card: CreditCard?
}
class CreditCard {
unowned let holder: Person
init (holder: Person) {
self.holder = holder
}
}
액세스 지점에 절대 도달 할 수없는 unowned
경우 사용self
nil
self
해당 시점에 .
예 (물론 직접 대상을 추가 할 수는 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()
}
}
액세스 weak
할 self
수 있는 가능성이있을 때 사용nil
self
.
예:
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
:
단점 weak
:
확실하지 않은 경우을 사용하십시오 weak
. 잠깐 , StackOverflow에서 귀하의 경우에 무엇을 해야하는지 물어보십시오. 항상 약한 것을 사용하면 안된다고 생각하는 사람과 당신의 코드 독자에게 혼동하지 마십시오.