swift 기초 문법 <12>

구찌댕댕이·2022년 7월 22일
0

swift 기초 문법

목록 보기
12/12
post-thumbnail

ARC : Automatic Reference Counting

Reference : reference타입인 클래스의 인스턴스를 관리.
value타입인 struct나 enum은 값이 복사되고 참조하는 것이 아니므로 ARC로 관리할 필요 없음
스위프트는 앱의 메모리 사용을 추적하고 관리하는 ARC를 사용
대부분 메모리 작업은 잘 작동하며, 메모리 관리를 생각할 필요 없음

ARC는 인스턴스가 더이상 필요가 없을 때 인스턴스에 사용된 메모리를 자동적으로 해제함
클래스의 인스턴스를 만들때마다 ARC는 인스턴스에 대한 정보를 저장하기 위해 메모리를 할당 -> 자료형과 프로퍼티 저장
ARC가 사용중인 인스턴스를 해제하면 해당 인스턴스의 프로퍼티나 메소드를 접근할 수 없고 앱이 crash
인스턴스가 필요한 동안 사라지지 않도록 ARC는 현재 각 클래스 인스턴스를 참조하는 프로퍼티/상수/변수의 참조횟수(RC: Reference Count)를 추적함 -> 해당 인스턴스에 하나 이상의 참조가 여전히 존재하면 인스턴스 할당을 해제하지 않는다.

프로퍼티/상수/변수가 인스턴스를 strong reference 하며 RC 값이 1 증가
인스턴스는 참조가 유지되는 한 해제할 수 없기 때문에 strong reference 라고 한다
참조를 사용하는 프로퍼티/변수/상수에 nil을 할당하면 참조횟수가 1 감소
참조횟수가 0이 되면 인스턴스가 메모리에서 해제

강한참조(strong reference)

기본 참조 방식으로 프로퍼티/상수/변수 선언 앞에 특별한 식별자가 없음 -> var apartment: Apartment?
약한참조의 경우 선언 처음에 weak를 사용 -> weak var person: Person?

class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("\(name) 생성됨(init)")
    }
    deinit {
        print("\(name) 해제됨(deinit)")
    }
}
var han1: Person?
var han2: Person?
var han3: Person?
//Optional 인스턴스 3개 생성 -> 아직 참조 되지 않은 상태 -> 나중에 nil 대입하기위해 옵셔널 인스턴스로 생성
han1 = Person(name: "Han") //Han 생성됨(init), Person인스턴스의 RC1
han2 = han1 //Person인스턴스의 RC2
han3 = han1 //Person인스턴스의 RC3
han1 = nil //Person인스턴스의 RC2
han2 = nil //Person인스턴스의 RC1
han3 = nil //Han 해제됨(deinit), Person인스턴스의 RC0

클래스 인스턴스 사이의 강한참조 순환

class Person {
    let name: String
    init(name: String) {
        self.name = name
    }
    var apartment: Apartment?
    deinit { print("\(name) 해제됨(deinit)")}
}
class Apartment {
    let unit: String
    init(unit: String) {
        self.unit = unit
    }
    var tenat: Person?
    deinit { print("\(unit) 해제됨(deinit)")}
} //현재 Person 과 Apartment가 엮여 있음
var john: Person?
var unit4A: Apartment?
john = Person(name:"john") //Person인스턴스의 RC1
unit4A = Apartment(unit: "4A") //Apartment인스턴스의 RC1
john!.apartment = unit4A //Apartment인스턴스의 RC2
unit4A!.tenat = john //Person인스턴스의 RC2
john = nil //Person인스턴스의 RC1, deinit호출 안됨 -> 메모리 누수
unit4A = nil //Apartment인스턴스의 RC1, deinit호출 안됨 -> 메모리 누수

Weak Reference

strong reference를 피하기 위해 weak 이나 unowned를 사용하여 인스턴스를 참조하더라도 참조 횟수를 늘리지 않음
참조하고 있는 상태라 하더라도 참조하는 인스턴스가 해제되었을때 자동으로 nil값 할당
옵셔널과 var로 선언해야한다 -> nil값이 자동으로 할당되야 하기때문에 let은 안된다.
weak var tenant: Person? -> let으로 선언하면 안된다.

class Person {
    let name: String
    init(name: String) {
        self.name = name
    }
    var apartment: Apartment? //여기에 weak 을 사용해도 된다
    deinit { print("\(name) 해제됨(deinit)")}
}
class Apartment {
    let unit: String
    init(unit: String) {
        self.unit = unit
    }
    weak var tenat: Person?
    deinit { print("\(unit) 해제됨(deinit)")}
}
var john: Person?
var unit4A: Apartment?
john = Person(name:"john") //Person인스턴스의 RC1
unit4A = Apartment(unit: "4A") //Apartment인스턴스의 RC1
john!.apartment = unit4A //Apartment인스턴스의 RC2
unit4A!.tenat = john //Person인스턴스의 RC1 -> tenat프로퍼티가 약한 참조이므로 RC는 증가하지 않는다
john = nil //Person인스턴스의 RC0, john 해제됨(deinit)
unit4A = nil //Apartment인스턴스의 RC0, 4A 해제됨(deinit) -> 자동으로 RC0으로 바뀐다

Unowned Reference

unowned reference도 weak와 비슷하게 강한 참조를 하지 않음
차이점은 unowned reference는 그 자체가 값을 가짐
weak는 참조 대상이 제거되었을 때 ARC가 자동으로 nil값을 주지만, unowned는 nil값을 주지 않음 -> 항상 값을 가질 것이라고 가정
unowned는 non-optional 타입을 사용하고 해당 인스턴스와 같거나 혹은 더 긴 lifetime을 가질 때 사용
unowned reference는 참조할 인스턴스가 해제되지 않는다고 확실할 때 사용
unowned로 참조된 인스턴스가 해제되었는데 접근하려고 하면 crash

class Customer {
    let name : String
    var card : CreditCard? // 카드가 없을 수도 있으므로 옵셔널, 강한참조
    init(name: String) {
        self.name = name
    }
    deinit {print("\(name) : deinit")}
}
class CreditCard {
    let number : Int
    unowned let customer: Customer //카드는 주인이 항상 있음, 옵셔널 아님
    init(number: Int, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit {print("Card #\(number) : deinit")}
}
var john : Customer?
john = Customer(name: "John")
john!.card = CreditCard(number: 123456789, customer: john!) //CreditCard 인스턴스의 RC1
john = nil //CreditCard 인스턴스의 RC0, John : deinit
//Customer인스턴스의 card 프로퍼티가 참조하고 있던 CreditCard 인스턴스도 RC값이 1 감소되어 메모리에서 해제

출처 : https://www.youtube.com/channel/UCM8wseo6DkA-D7yGlCrcrwA/playlists

profile
개발자를 꿈꾸는 사람 입니당

0개의 댓글