• 카테고리

    질문 & 답변
  • 세부 분야

    모바일 앱 개발

  • 해결 여부

    미해결

retain cycle 질문입니다.

22.01.05 14:14 작성 조회수 150

1

강의 중 코드 입니다. 아래에서 weak self 하지 않을 경우 강한 참조 사이클은 일어나지 않는다고 하셨는데, 
1.클로저가 해당 클래스를 참조하고 있지만 해당 클래스는 클로저를 참조하고 있지 않기때문인가요?
2.weak self하지 않을때, sleep(3)에 의해 클로저가 3초정도 클래스를 참조하고 있어 그 사이에 class가 dismiss되어도
self가 nil이 아닌상황이 지속되고, 3초 이후 즉 클로저가 모두 진행된 이후에는 클로저가 클래스를 더 이상 참조하고 있지않아 class가 dismiss할 경우
deinit이 정상작동 되는 것인가요?



class ViewController2: UIViewController { var name: String = "뷰컨" func doSomething() { // 강한 참조 사이클이 일어나지 않지만, 굳이 뷰컨트롤러를 길게 잡아둘 필요가 없다면 // weak self로 선언 DispatchQueue.global().async { [weak self] in sleep(3) guard let weakSelf = self else { return } print("글로벌큐에서 출력하기: \(weakSelf.name)") DispatchQueue.main.async { print("메인큐에서 출력하기: \(weakSelf.name)") } } } deinit { print("\(name) 메모리 해제") } } func localScopeFunction2() { let vc = ViewController2() vc.doSomething() } localScopeFunction2()

답변 1

답변을 작성해보세요.

1

1. 네 맞습니다. [weak self] 를 쓰지 않더라도,
클로저는 클래스의 인스턴스를 (강하게)가리키지만 클래스의 인스턴스는 클로저를 가리키는 것이 없기 때문에 강한 참조 싸이클은 일어나지 않아요. (다만, 길게 잡아두기 때문에.. (3초) 제가 강의에서 보여드린 대로 출력이 일어나는 현상은 보실 수 있죠.)

2. 결국 스위프트 메모리 관리 모델 - ARC는 나를 참조하는 것의 갯수를 세어서(레퍼런스 카운팅) 그 참조(가리키는 것)의 갯수가 0이 될때, 메모리에서 해제가 되는 것입니다. 그래서.. 한규 님이 말씀하신 것이 거의 맞지만, 더 정확하게 말씀드리면...  3초정도 계속 뷰컨트롤러의 인스턴스를 참조하므로, 만약에 뷰컨트롤러의 인스턴스가 dismiss 되어도.. (즉, 아직 가리키는 것이 1개 이상으로 RC를 세기 때문에..) 메모리에서는 여전히 존재하기 때문에 deinit자체가 되지 않습니다. (dismiss는 단순히 화면에서 안보인다는 의미이고, deinit은 실제 메모리에서 내려감의 의미). 그리고 3초 이후에는 이제.. 클로저도 사라지고, 이에 따라 뷰컨트롤러를 가리키는 것이 없어졌기 때문에 RC가 0이 되고 이제서야 메모리에서 해제가 되면서, deinit이 호출이 되는 것입니다.


고맙습니다. :)

이한규님의 프로필

이한규

질문자

2022.01.18

앨런님 문득 질문이 생겨 질문드립니다.

3초 동안, 클로저가 클래스 인스턴스를 일방향으로 참조하기 때문에 retain cycle이 발생하지는 않지만 weak self를 사용하는 이유는 3초 정도 memory leak이 일어나서라고 이해하면 될까요? 

메모리 누수(leak)는 아닙니다. 메모리 누수라는 것은 말 그대로, 힙에 있는 인스턴스 자체를 해제할 수 있는 방법조차 없어지는 것을 의미하는 것이기 때문이예요. (힙이라는 메모리에 데이터가 올라가 있는 데.. 필요없는 데도 불구하고, 메모리를 해제 자체를 시킬 수 없는 것을 메모리 누수라고 합니다.)

여기서, 
weak self를 사용해도 되고, 안해도 됩니다.
(정확하게 알고 목적에 맞게 사용하시면 됩니다.)

1) weak self를 사용하면
뷰컨트롤러를 길게 잡아두지 않습니다. 예를 들어서, 길게 붙잡아 두지 않으니.. 3초 정도 붙잡아 두지도 않겠죠. 뷰컨트롤러가 없어지면..(dismiss되어 화면에서 사라지면) 클로저에서도 굳이 어떤 프린트와 같은 동작을 실행시키지 않아도 된다고 생각되면.. weak self를 쓰시면 됩니다.
(뷰컨트롤러가 없어지면, 굳이 3초 뒤에 클로저에서 어떤 일도 하지 않겠다는 의미)

2) weak self를 사용하지 않으면 (Strong)
뷰컨트롤러를 길게 잡아둡니다. 예를 들어서, 길게 붙잡아 두니.. 3초 정도 붙잡아 둡니다. 뷰컨트롤러가 dismiss되면, 일반적으로 메모리에서도 해제가 되겠지만, dismiss되어서 화면에서 없어졌음에도 불구하고.... 클로저에서 이미 어떤 동작을 실행하기로 마음 먹었으니... (프린트를 한다던지)하는 동작을 끝까지 하는 것입니다. 
(뷰컨트롤러가 없어지지만, 3초 뒤에 일어나는 동작은 끝까지 시키고 종료시키겠다는 의미)


그래서 결론적으로,
3초정도 메모리 누수가 일어난다는 표현보다는 그냥 인스턴스 자체를 길게 붙잡아 둔다는 표현이 더 정확한 표현인 것 같습니다... ^^;