ARC (Auto Reference Counting)

박인준·2019년 12월 9일
0

Swift

목록 보기
13/21

참조 카운트 예제

class Person {
  let testCase: String
  init(testCase: String) {
    self.testCase = testCase
  }
  deinit {
    print("\(testCase) is being deinitialized")
  }
}
// ### case 1. Allocation & Release
 
print("\n---------- [ Case 1 ] ----------\n")

var obj1: Person? = Person(testCase: "case1")
obj1 = nil

 //### case 2. 참조 카운트 증가

print("\n---------- [ Case 2 ] ----------\n")

var obj2: Person? = Person(testCase: "case2") //count 1
var countUp = obj2 // count 2


obj2 = nil // count1
countUp = nil // count0


// case 3. Collection 에 의한 참조 카운트

print("\n---------- [ Case 3 ] ----------\n")

var obj3: Person? = Person(testCase: "case3") // count1
var array = [obj3, obj3] //count2, count3

obj3 = nil // count2
array.remove(at: 0) // count1
array.remove(at: 0) // count0

@참조의 종류

  • strong : 기본값. 강한 참조. Reference Count 1 증가
  • unowned : 미소유 참조. Count 증가하지 않음. 참조 객체 해제 시에도 기존 포인터 주소 유지
  • weak : 약한 참조. Count 증가하지 않음. 참조하던 객체 해제 시 nil 값으로 변경
print("\n---------- [ Case 4 ] ----------\n")

var strongObj4 = Person(testCase: "case4") //count1
print(strongObj4)

weak var weakObj4 = Person(testCase: "case4") //count up이 되지 않음
print(weakObj4)

unowned var unownedObj4 = Person(testCase: "case4") // 생성하자마자 사라짐
print(unownedObj4)

Scope

class LocalScope {
  func doSomething() {}
  deinit {
    print("LocalScope is being deinitialized")
  }
}

class ClassProperty {
  func doSomething() {}
  deinit {
    print("ClassProperty is being deinitialized")
  }
}

class Application {
  var prop = ClassProperty() // count1
  
  func allocateInstance() {
    let local = LocalScope() // count1
    local.doSomething()
  }
  
  deinit {
    print("Application is being deinitialized")
  }
}


// Q. 아래의 코드 실행 시 출력되는 메시지는?

var app: Application? = Application() //count1 -> classproperty count1
app?.prop.doSomething()
app?.allocateInstance() // count1 -> count0



// Q. ClassProperty 객체의 deinit 메서드가 호출되려면 어떻게 할까요?

app = nil // app이 가르키던 주소가 0 -> Application count 0 -> ClassProperty count0

Strong Reference Cycles

class Person {
  var pet: Dog?
  func doSomething() {}
  deinit {
    print("Person is being deinitialized")
  }
}

class Dog {
  var owner: Person?
  func doSomething() {}
  deinit {
    print("Dog is being deinitialized")
  }
}



var giftbot: Person! = Person() // count1
var tory: Dog! = Dog() // count1

giftbot.pet = tory  // dog count2
tory.owner = giftbot // person count2

giftbot.doSomething()
tory.doSomething()


//giftbot = nil // person count1
//tory =  nil // dog count1   -> 참조순환으로 메모리에 남아있음
// 그래서!
giftbot.pet = nil
//tory.owner = nil

giftbot = nil
tory = nil

// 큰단위의 메모리부터 해제하면 메모리 속 데이터에 접근방법을 잃어버리기 때문에 데이터부터 접근하여 제거해야 함!

Strong, Unowned, Weak


class Teacher {
  var student: Student?
  deinit {
    print("Teacher is being deinitialized")
  }
}

class Student {
  // strong, unowned, weak
//  let teacher: Teacherc  // count2
  unowned let teacher: Teacher // teacher count1
//  weak var teacher: Teacher? // weak은 필히 optional로 선언하기
  
  init(teacher: Teacher) {
    self.teacher = teacher
  }
  deinit {
    print("Student is being deinitialized")
  }
}

var teacher: Teacher? = Teacher() // teacher count1
var student: Student? = Student(teacher: teacher!)
teacher?.student = student // teacher count2


print("\n---------- [ teacher release ] ----------\n")
teacher = nil // teacher count0 -> student count1

print("\n---------- [ student release ] ----------\n")
student = nil // student count 0


// 1) strong  : 명시적으로 nil 대입 필요. teacher?.student = nil
// 2) unowned : 자동으로 deinit. nil 처리 된 속성에 접근하면 런타임 에러 발생
// 3) weak    : 자동으로 deinit. nil 처리 된 속성에 접근하면 nil 반환
profile
iOS 개발자가 되기 위해

0개의 댓글