[TIL / 25.02.25] 자료구조, 메모리 구조, ARC에 대해 간략하게!

2025. 2. 25. 18:55·iOS/Swift

1. 자료구조

1.1 배열(Array)

  • 데이터를 순차적으로 저장하는 자료구조
  • 인덱스를 사용해 특정 요소에 접근
  • 특징 : 빠른 조회 (O(1)), 삽입/삭제 시 성능 저하(O(n)).
  • 예시
var numbers = [1, 2, 3, 4, 5]
numbers.append(6)
print(numbers) // [1, 2, 3, 4, 5, 6]

 

시간 복잡도를 연관지어 보는건 처음이라 왜 O(n)이 되는지 알아봤는데 삽입 혹은 삭제 시 최악의 경우 그 갯수만큼 값을 밀어야 하거나 당겨와야하기에 O(n)이 된다고 한다.

 

1.2 큐(Queue)

  • 선입선출(FIFO, First In First Out) 구조.
  • 데이터를 한쪽에서 삽입하고, 반대쪽에서 제거.
  • 사용 사례: 프린터 작업 대기열, BFS 탐색.
  • 예시
struct Queue<T> {
	private var elements: [T] = []
    
    mutating func enqueue(_ element: T) {
    	elements.append(element)
    }
    
    mutating func dequeue() -> T? {
    	return elements.isEmpty ? nil : elements.removeFirst()
    }
}

 

구조체에 있는 프로퍼티의 값을 변경하는 메서드를 선언할 때 mutating 키워드를 붙여야 한다.

 

1.2.1 실습

struct Queue {
    
    var numbers: [Int] = []
    
    mutating func enqueue(num: Int) {
        numbers.append(num)
        print(numbers)
    }
    
    mutating func dequeue() {
        numbers.removeFirst()
        print(numbers)
    }
    
}

var queue = Queue()

queue.enqueue(num: 1)
queue.enqueue(num: 2)
queue.enqueue(num: 3)
queue.enqueue(num: 4)

queue.dequeue()
queue.dequeue()

 

1.3 스택(Stack)

  • 후입선출(LIFO, Last In First Out) 구조
  • 데이터를 한쪽에서 삽입하고 제거.
  • 사용 사례: 함수 호출 스택, 괄호 검사.
  • 예시
struct Stack<T> {
    private var elements: [T] = []
    
    mutating func push(_ element: T) {
        elements.append(element)
    }
    
    mutating func pop() -> T? {
        return elements.popLast()
    }
}

 

struct Stack {
    var elements: [String] = []
    
    mutating func push(element: String) {
        elements.append(element)
    }
    
    mutating func pop() {
        elements.popLast()
    }
    
    mutating func printLastElement() {
        print(elements.last)
    }
}

var stack = Stack()

stack.push(element: "스")
stack.push(element: "위")
stack.push(element: "프")
stack.push(element: "트")
stack.push(element: "굿")

stack.pop()
stack.printLastElement() // "트"

2. 메모리 구조 및 ARC

2.1 메모리 구조

  • Stack : 함수 호출시 함수의 지역변수, 매개변수, 리턴 값 등등이 저장되고 함수가 종료되면 저장된 메모리도 해제된다.
    • 컴파일 타임에 결정되기 때문에 무한히 할당할 수 없다.
  • Heap : 동적 메모리 할당, 참조 타입(클래스) 저장.
    • 사용하고 난 후에는 반드시 메모리 해제를 해줘야 한다. 그렇지 않으면 memory leak이 발생한다.
    • 유일하게 런타임 시에 결정되기 때문에 데이터의 크기가 확실하지 않을 때 사용한다.
    • 클래스 인스턴스, 클로저 같은 참조 타입의 값은 모두 힙에 자동 할당된다.
    • 인스턴스 다 쓰고 free, release 같은 걸 해준 적이 없는데 이는 스위프트가 ARC를 통해 힙에 할당된 메모리가 더 이상 쓸모 없어지면(참조되지 않으면) 자동으로 해제해주기 때문이다 !!
  • Code : 실행 중인 코드 저장. 기계어로 저장해준다.
  • Data : 전역 변수, 정적 변수 저장. ~ static

2.2 ARC(Automatic Reference Counting)

  • Swift의 메모리 관리 방식
  • 클래스 인스턴스의 참조 횟수를 추적하여 필요하지 않은 인스턴스를 메모리에서 해제.
  • 순환 참조(Circular Reference):
    • 두 개 이상의 객체가 서로를 참조하면서 메모리에서 해제되지 않는 상황.
  • 해결 방법:
    • weak 또는 unowned 키워드 사용
class Person {
    var name: String
    var pet: Pet?

    init(name: String) {
        self.name = name
    }
}

class Pet {
    var owner: Person?
}

let person = Person(name: "Alice")
let pet = Pet()

person.pet = pet
pet.owner = person // 순환 참조 발생

 

서로 참조합니다. 끝없이 서로 필요하다고 판단되어 메모리에서 해제되지 않는다.

 

class Pet {
    weak var owner: Person?
}

 

이렇게 한쪽에서 weak 키워드를 써줘야 약한 참조를 하게 되어, 한쪽이 메모리에서 해제될때 타 객체도 해제될 수 있다.

 

2.2.1 실습

class Person {
    let name: String
    var pet: Pet?
    
    init(name: String, pet: Pet? = nil) {
        self.name = name
    }
    
    deinit {
        print("Person deinit")
    }
}

class Pet {
    var owner: Person?
    
    deinit {
        print("Pet deinit")
    }
}

var person: Person? = Person(name: "Anderson")
var cat = Pet()

person?.pet = cat
cat.owner = person


person = nil

print(person?.pet) // "nil"
print(cat.owner!.name) // "Anderson"

 

weak로 한쪽을 약하게 참조하고 해당 참조되는 객체를 nil 처리하면

class Person {
    let name: String
    weak var pet: Pet?
    
    init(name: String, pet: Pet? = nil) {
        self.name = name
    }
    
    deinit {
        print("Person deinit")
    }
}

class Pet {
    var owner: Person?
    
    deinit {
        print("Pet deinit")
    }
}

var person: Person? = Person(name: "Anderson")
var cat: Pet? = Pet()

person?.pet = cat
cat?.owner = person


cat = nil

print(person?.pet) // nil
print(cat?.owner?.name) // nil

 

Pet deinit과 함께 메모리 해제가 이뤄진다 !


 

순환 참조 등을 고려하지 않은 채로 앱을 만들게 되면 시간이 가면 갈수록 성능이 떨어질거고, 메모리 구조는 전에 본적이 있는데 이를 실제로 응용해서 쓴적이 없어서 아직 크게 와닿진 않는다. 퀄리티 있는 앱을 만들기 위해선 이런 CS적인 부분도 놓치면 안되고 UI/UX적인 부분도 고려해야하니 꽤나 정교할 필요가 있다는 생각이 든다.

'iOS > Swift' 카테고리의 다른 글

[TIL / 25.03.11] 에러 핸들링(Error Handling)  (2) 2025.03.11
[TIL / 25.03.05] 이미지 슬라이더 + 커스텀 인디케이터  (2) 2025.03.05
[TIL / 25.02.21] SkeletonView 적용 및 생명주기 관련 문제 해결  (0) 2025.02.21
[TIL / 25.02.17] 뷰 맨 앞으로 보내기  (0) 2025.02.17
[TIL / 25.02.14] 열거형 Enum을 이용한 메뉴 구성  (2) 2025.02.14
'iOS/Swift' 카테고리의 다른 글
  • [TIL / 25.03.11] 에러 핸들링(Error Handling)
  • [TIL / 25.03.05] 이미지 슬라이더 + 커스텀 인디케이터
  • [TIL / 25.02.21] SkeletonView 적용 및 생명주기 관련 문제 해결
  • [TIL / 25.02.17] 뷰 맨 앞으로 보내기
subkyu-ios
subkyu-ios
subkyu-ios 님의 블로그 입니다.
  • subkyu-ios
    subkyu-ios 님의 블로그
    subkyu-ios
  • 전체
    오늘
    어제
    • 분류 전체보기 (45) N
      • iOS (29) N
        • Swift (29) N
      • 내일배움캠프 (7)
      • Git, Github (3)
      • Algorithm (6)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    알고리즘
    github
    ios
    til
    트러블슈팅
    협업
    algorithm
    본캠프
    UIKit
    KPT
    tabman
    Wil
    TableView
    stackview
    최적화
    사전캠프
    회고
    Swift
    프로그래머스
    내일배움캠프
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
subkyu-ios
[TIL / 25.02.25] 자료구조, 메모리 구조, ARC에 대해 간략하게!
상단으로

티스토리툴바