-
[사전캠프 TIL 3일차] ARC / 클로저 / OOPiOS💖 2025. 2. 5. 18:22
키워드
🗂️ ARC (strong, weak, unowned, optional unowned 타입) ➡️ 복잡한 데이터 구조 설정시 적용해보기! 🔴
클로저
OOP
ARC
ARC (Automatic Reference Counting) ?
1. 참조 변수 (클래스 instance, 클로저 등) 가 더이상 참조 되지 않을때, Heap 영역에 할당된 메모리를 자동으로 해제
2. RC 계산 개념으로 메모리를 자동 해제
3. Automatic Reference Counting 이므로, reference 타입에만 적용 (struct, enum 등 X)
모든 instance 는 자신의 RC 값이 있음
(instance 생성시, Heap에 같이 저장됨)
RC (Reference Count)
: instance 를 참조하고 있는 횟수 계산
RC 가 +1 되는 경우
1. instance 를 새로 생성 시 ⭐️
2. instance 의 address 를 변수에 할당 시
RC 가 -1 되는 경우
1. instance 를 가리키던 변수가 메모리 해제 됐을 시
2. instance 본인 마저도 nil 로 지정될 시 (RC == 0)
(instance 가 Heap영역에 메모리 할당되고, Stack영역에 해당 instance 를 참조하는 지역변수로 메모리 할당 됨)3. instance의 property의 경우,
해당 property가 다른 클래스 instance를 참조할 때;
RC에 대해..
- 참조 계산 시점
Compile Time : 컴파일 시점에서 언제 참조/해제 될 지 결정되어, 런타임 때 그대로 실행됨
- 장점
개발자가 참조 해제 시점 파악 가능
Run Time 시, 추가 리소스 발생 X
- 단점
1. 순환 참조 발생시, 영구적으로 메모리 해제되지 않을 수 있음
2. 사용중인 instance 메모리를 해제하여, 해당 instance 의 속성/메서드 호출시 app crush(충돌) 일어날 수 있음
* ARC 가 메모리 해제 할 수 없는 참조
1. strong 참조
2. strong 참조 사이클이 생성된 경우
* ARC 의 메모리 해제를 막을 수 없는 참조
: weak, unowned
[RC 계산 방법 & 메모리 해제] 그림으로 이해하기 ❤️

RC 계산 방법 & 메모리 해제 그림의 코드에서와 같이,
B instance 의 property a 는 해제됐어도, 해당 property (= a) 를 다른 곳에서 참조하고 있었다면
A instance 의 RC는 -1 일 뿐, 메모리 해제되지 않는다!
위의 경우에서, B instance 의 메모리가 해제되어 A instance 메모리도 해제 된 것이 아니다!! ❌
예제에서 B instance 에서만 참조 중이었던 것이 전제였으므로, A instance 의 기존 RC값 (=1) 이 -1 되어, RC = 0이 되었으므로,
메모리가 해제 된 것이다!!
메모리 할당 / 해제 출력
Class XXX { init { print("XXX Init") } deinit { print("XXX Deinit") } }순환 참조 문제
: instance 를 확실하게 유지 / strong 참조가 유지되는 한, ARC는 메모리 해제 불가!
ARC 에서 메모리 해제 하지 않는 이유?
1. RC != 0
즉, 활성화 되고있는 참조가 있는 경우
2. strong 참조 사이클 (= 순환 참조 문제 = Circular Reference) 가 생성된 경우
순환 참조 문제? (= Circular Reference) 🔴
: 두 개 이상의 객체가 서로 참조하면서 메모리에서 해제되지 않는 상황
class Person { let name: String init(name: String) { self.name = name } var apartment: Apartment? deinit { print("\(name) is being deinitialized") } } class Apartment { let unit: String init(unit: String) { self.unit = unit } var tenant: Person? deinit { print("Apartment \(unit) is being deinitialized") } } // 🔴 1 var john: Person? var unit4A: Apartment? john = Person(name: "John Appleseed") unit4A = Apartment(unit: "4A") // 🔴 2 // linking these two instances(john,unit4A) creates a strong reference cycle between them. john!.apartment = unit4A unit4A!.tenant = john // 🔴 3 // The strong reference cycle 는 nil 이 되어도 메모리 할당이 끊어지지 않음 john = nil unit4A = nil순환 참조 해결
순환 참조 해결 방법
: 클래스 간의 관계 중, 일부를 weak / unowned 참조로 정의
1. weak 참조
- 다른 instance 보다 lifetime이 짧은 (= 메모리 할당 해제될 수 있는) 경우 사용
2. unowned 참조 (= non-optional unowned 참조)
- 다른 instance 와 lifetime이 같거나, 더 긴 경우 사용
- unowned 참조는, 항상 값을 갖는 것 (= 종속적인 관계 (상대가 있어야 나도 존재) = non-optional 타입) 를 전제
- unowned 참조는, 항상 참조가 할당 해제되지 않는 instance를 참조할 때만 사용
3. unowned optional 참조
- unowned 참조와 같이, 종속적인 관계 이지만 & 항상 참조를 해야만 하는 것은 아닌 (= 그래서 optional = 참조안하고 있을때는 nil 일 수도 있다는 말)
- 코드 예시)
class Course의 nextCourse property (🔴 부분)
class Department { var name: String var courses: [Course] init(name: String) { self.name = name self.courses = [] } } class Course { var name: String unowned var department: Department unowned var nextCourse: Course? // 🔴 init(name: String, in department: Department) { self.name = name self.department = department self.nextCourse = nil } } let department = Department(name: "Horticulture") let intro = Course(name: "Survey of Plants", in: department) let intermediate = Course(name: "Growing Common Herbs", in: department) let advanced = Course(name: "Caring for Tropical Plants", in: department) intro.nextCourse = intermediate intermediate.nextCourse = advanced department.courses = [intro, intermediate, advanced]직접 구현해보기
ARC와 순환 참조 해결
1. 순환 참조 문제 구현
- 두 클래스를 생성하세요:
- Person 클래스: 이름을 저장하는 속성(name)과 애완동물(pet) 속성을 가짐.
- Pet 클래스: 주인(owner) 속성을 가짐.
- 서로를 참조하는 인스턴스를 생성하고 순환 참조 문제를 확인하세요.
class Person { var name: String var pet: Pet? init(name: String) { self.name = name } deinit { print("\(name) deinitialized") } } class Pet { var owner: Person? deinit { print("Owner \(owner) deinitialized") } } var mimi: Person? var toto: Pet? mimi = Person(name: "mimi") toto = Pet() mimi!.pet = toto toto!.owner = mimi mimi = nil toto = nil[실행결과] // 아무것도 안찍힘. deinit 실행되지 않음 >>>>> 메모리 해제되지 않음!! 🔴2. 순환 참조 해결
- weak 키워드를 사용해 순환 참조 문제를 해결하세요.
- 해결 후, 두 인스턴스가 정상적으로 메모리에서 해제되는지 확인하세요.
class Person { var name: String var pet: Pet? init(name: String) { self.name = name } deinit { print("\(name) deinitialized") } // 🔴 실행됨 } class Pet { weak var owner: Person? deinit { print("Owner \(owner) deinitialized") } // 🔴 실행됨 } var mimi: Person? var toto: Pet? mimi = Person(name: "mimi") toto = Pet() mimi!.pet = toto toto!.owner = mimi mimi = nil toto = nil[실행 결과] mimi deinitialized Owner nil deinitialized회고
이전에도 ARC 개념을 공부했었지만, 정해주신 학습 순서대로 공부하니 이번엔 제대로 이해가 됐다.
내가 이전에 ARC 가 알긴알겠는데 확실하게 모르겠었던 이유는, 메모리 구조 때문이었다.
Swift 에서 많이 쓰이는 Heap, Stack 개념을 확실하게 이해한 후 ARC 를 이해하니 완전 이해된다. 야호~💝
출처
https://babbab2.tistory.com/26
iOS) 메모리 관리 (1/3) - ARC(Automatic Reference Counting)
안녕하세요~~ 소들입니다 👀 오늘은 지난 시간 메모리 구조에 이어 Swift를 사용할 때 메모리 관리가 어떤 식으로 되는지에 대해 공부해볼 거예요 :) ARC 면접 단골 질문이라죠? 깔깔 iOS 개발자라
babbab2.tistory.com
https://hortenssiaa.tistory.com/37
(Swift) ARC (Automatic Reference Counting, 자동 참조 계산)
@escaping 을 공부하다가 여기 까지 오게 되었음 ㅠㅠ ㅎ ARC (Automatic Reference Counting, 자동 참조 계산)앱의 메모리 사용량을 추적, 관리class instance 가 더 이상 필요하지 않을 때, 해당 instance 에서
hortenssiaa.tistory.com
https://hortenssiaa.tistory.com/38 🔴🔴🔴
(Swift) 메모리 참조 속성 (strong, week, unowned, optional unowned)
Apple Documentation 을 보고 정리하였음 1. strong 참조default reference type 이다. var / let 앞에 week, unowned 가 붙지 않으면 strong reference type 임!!instance 를 확실히 유지 & strong 참조가 유지되는 한, 할당 해
hortenssiaa.tistory.com
Documentation
docs.swift.org
클로저 🩷
클로저란?
- 코드에서 독립적으로 전달/사용 할 수 있는 기능을 가진 코드블록
- 비동기 처리 / UI 업데이트에서 자주 사용
- 변수/상수에 저장 가능
- 함수 인자로 전달 가능
- 이름있는 클로저 (= 함수)일 경우, 함수처럼 () 를 붙여 사용
- 이름없는 클로저 (= 익명함수)
클로저 문법
{ (매개변수) -> 반환타입 in 실행 코드 } // 매개변수 O { (name: String) -> String in print("Hello, \(name)!") } // 매개변수 X { () -> Int in print(30) }캡쳐 (Capture)
클로저는 외부 변수/상수의 값을 "캡쳐" 하여 저장한다.
var number = 10 let closure = { number += 5 } closure() print(number) // 15클로저 예제
// 기본 클로저 let greet = { (name: String) -> String in return "Hello, \(name)!") } print(greet("Alice") // "Hello, Alice!" // 🔴함수의 인자로 클로저 전달 func performAction(action: () -> Void) { action() // 전달받은 클로저 실행 } performAction { print("Action Performed") }직접 구현해보기
1. 간단한 클로저 구현:
숫자 배열 [1, 2, 3, 4, 5]를 생성하고, 클로저를 사용해 배열의 모든 값을 2배로 만든 결과를 출력하세요.
let numbers = [1, 2, 3, 4, 5] let doubled = numbers.map { $0 * 2 } print(doubled)2. 클로저 캡처 이해:
아래 코드를 완성하여 클로저가 외부 변수 값을 캡처하는 동작을 확인하세요.
var counter = 0 let incrementCounter = { counter += 1 } incrementCounter() // 1 incrementCounter() // 2 print(counter) // 출력: 2
객체지향 프로그래밍 (OOP)
객체지향 프로그래밍 (OOP) ?
객체 (Object) 기반인 프로그램 설계 방식
주요 원칙
1. 캡슐화 (Encapsulation) : 데이터를 숨기고, 외부에는 필요한 인터페이스만 제공
2. 상속 (Inheritance) : 기존 클래스를 확장하여 새로운 클래스 생성
3. 다형성 (Polymorphism) : 같은 메서드를 다양한 방식으로 동작하게 함
4. 추상화 (Abstraction) : 불필요한 세부 사항을 숨기고, 중요한 부분만 표현
클래스와 객체
클래스 : 객체를 정의하기 위한 청사진
객체 : 클래스에서 생성된 실제 instance
OOP 기본 예제
class Animal { var name: String init(name: String) { self.name = name } func makeSound() { print("Some generic sound") } } class Dog: Animal { override func makeSound() { print("Bark!") } } let dog = Dog(name: "Buddy") dog.makeSound() // "Bark!"직접 구현해보기
1. 동물 클래스 설계:
다음 요구 사항에 맞는 클래스를 구현하세요:
Animal 클래스: name 속성과 makeSound() 메서드를 포함.
Dog 클래스: Animal을 상속받고 makeSound() 메서드를 오버라이드하여 "Bark!" 출력.
Cat 클래스: Animal을 상속받고 makeSound() 메서드를 오버라이드하여 "Meow!" 출력.
class Animal { var name: String init(name: String) { self.name = name } func makeSound() { } } class Dog: Animal { override func makeSound() { print("Bark!") } } class Cat: Animal { override func makeSound() { print("Meow!") } } var toto = Dog(name: "toto") var nani = Cat(name: "nani") toto.makeSound() // Bark! nani.makeSound() // Meow!2. 다형성 확인:
Animal 타입 배열에 Dog와 Cat 객체를 저장하고, 배열의 각 객체에서 makeSound() 메서드를 호출하세요.
예상 출력:
Bark! Meow!코드
var animalArr: [Animal] = [toto, nani] var makeSound = animalArr.map { $0.makeSound() } // Bark! // Meow!'iOS💖' 카테고리의 다른 글
[사전캠프 TIL 5일차] GCD (+α), Operation (0) 2025.02.07 [사전캠프 TIL 4일차] 비동기 프로그래밍 (with. GCD 💝) (2) 2025.02.06 [사전캠프 TIL 2일차] 자료구조 / 메모리 구조 (2) 2025.02.04 [사전캠프 TIL 1일차] Struct / Class / Protocol (0) 2025.02.03 [Swift] Network connect 두 가지 방법 (0) 2024.10.22 - 두 클래스를 생성하세요: