BIBI BLOG

📱 SwiftUI에서 메모리 사용 줄이기! ⚡ 본문

iOS/Swift

📱 SwiftUI에서 메모리 사용 줄이기! ⚡

BIBI⭐️ 2025. 3. 14. 11:29
728x90

📱 SwiftUI에서 메모리 사용 줄이기! ⚡

SwiftUI로 앱을 만들다 보면, 어느 순간 앱이 점점 무거워지고 느려지는 걸 느낄 때가 있어요.
메모리를 많이 쓰면 기기 성능이 떨어지고, 심한 경우 앱이 강제 종료될 수도 있죠.

이런 문제를 방지하려면, SwiftUI의 동작 방식을 잘 이해하고 메모리를 효율적으로 관리하는 게 중요해요.
이번 글에서는 앱을 더 가볍고 빠르게 만들 수 있는 실전 최적화 방법을 정리해보았습니다.🚀


1️⃣ SwiftUI에서 메모리 사용 방식 이해하기

SwiftUI에서는 UI가 상태(State)에 따라 자동으로 변경돼요.
즉, 우리가 직접 화면을 업데이트할 필요 없이, 상태만 바꾸면 SwiftUI가 알아서 새로운 화면을 그려요.

하지만, 잘못된 상태(State) 사용법이나 큰 데이터를 잘못 다루면 메모리가 많이 사용될 수 있어요.


2️⃣ 올바른 State 관리 방법

SwiftUI에서는 데이터를 관리할 때 여러 가지 방법을 제공해요.
각 방법의 차이를 알면 불필요한 메모리 사용을 줄일 수 있어요!

속성 설명 메모리 관리
@State 단순한 값 (숫자, 문자열 등) 사용하기 쉬움, 작은 데이터에 적합
@Binding 부모 뷰에서 전달받은 값 직접 데이터를 저장하지 않음
@ObservedObject 외부에서 만든 객체를 관찰 메모리 관리 필요
@StateObject SwiftUI가 객체를 직접 관리 뷰가 사라질 때 자동으로 해제됨
@EnvironmentObject 여러 뷰에서 공유하는 객체 전역 데이터 관리

 

잘못된 사용법 예제 (메모리 과소비!)

struct ContentView: View {
    @StateObject private var viewModel = LargeDataViewModel()

    var body: some View {
        Text(viewModel.data)
    }
}​

이렇게 하면 ContentView가 새로 생성될 때마다 viewModel이 계속 만들어져서 메모리를 낭비할 수 있어요!

 

메모리를 아끼는 올바른 방법

struct ContentView: View {
    @ObservedObject var viewModel: LargeDataViewModel

    var body: some View {
        Text(viewModel.data)
    }
}

// 상위 뷰에서 ViewModel을 전달해주기
let sharedViewModel = LargeDataViewModel()
ContentView(viewModel: sharedViewModel)

✔️ 이렇게 하면 viewModel이 여러 뷰에서 재사용되면서 불필요한 메모리 낭비를 막을 수 있어요! 💡


3️⃣ 리스트 최적화 (LazyVStack 사용하기)

만약 리스트에서 수천 개의 데이터를 한 번에 로딩한다면 메모리가 폭발할 수도 있어요! 💥
SwiftUI에서는 이를 해결하기 위해 LazyVStack을 제공해요.

 

❎ 비효율적인 코드 (메모리 낭비!)

ScrollView {
    VStack {
        ForEach(largeDataSet) { item in
            DataRowView(item: item)
        }
    }
}

이렇게 하면 리스트의 모든 아이템이 한 번에 메모리에 로드돼서 앱이 느려질 수 있어요.

 

최적화된 코드 (LazyVStack 활용)

ScrollView {
    LazyVStack {
        ForEach(largeDataSet) { item in
            DataRowView(item: item)
        }
    }
}

✔️ LazyVStack은 화면에 보이는 데이터만 로드하기 때문에 메모리를 훨씬 절약할 수 있어요! 🎉


4️⃣ 이미지 로딩 최적화

큰 이미지를 많이 불러오면 메모리를 엄청 많이 사용할 수 있어요.
그래서 이미지 크기를 조절하거나 캐싱(임시 저장)하는 게 중요해요!

 

AsyncImage를 활용한 최적화

struct ThumbnailView: View {
    let imageURL: URL

    var body: some View {
        AsyncImage(url: imageURL) { phase in
            if let image = phase.image {
                image.resizable().scaledToFit()
            } else if phase.error != nil {
                Color.red // 에러 시 빨간 배경
            } else {
                ProgressView() // 로딩 중 표시
            }
        }
        .frame(width: 100, height: 100)
    }
}

✔️ AsyncImage를 사용하면 자동으로 이미지를 백그라운드에서 로딩하고, 캐싱할 수 있어요.
✔️ 또, ProgressView()를 추가하면 이미지가 로딩될 때 깔끔하게 표시돼요!


5️⃣ 무거운 연산을 백그라운드에서 실행하기

SwiftUI에서 무거운 연산을 직접 하면 화면이 멈추거나, 앱이 느려질 수 있어요.
이럴 때는 백그라운드에서 실행하고, 결과만 화면에 표시하면 돼요!

 

❎ 잘못된 코드 (앱이 멈출 수 있음)

struct ContentView: View {
    var body: some View {
        let processedData = heavyComputation()
        Text("데이터: \(processedData)")
    }
}

이렇게 하면 SwiftUI가 화면을 그릴 때마다 heavyComputation()을 실행해서 앱이 멈출 수 있어요.

 

백그라운드에서 실행하는 최적화 코드

struct ContentView: View {
    @State private var processedData: String = ""

    var body: some View {
        Text("데이터: \(processedData)")
            .onAppear {
                DispatchQueue.global(qos: .userInitiated).async {
                    let data = heavyComputation()
                    DispatchQueue.main.async {
                        self.processedData = data
                    }
                }
            }
    }
}

✔️ DispatchQueue.global을 사용하면 백그라운드에서 실행돼서 앱이 멈추지 않아요!
✔️ 결과는 DispatchQueue.main.async를 이용해 메인 화면에서 업데이트해 줘야 해요.


6️⃣ 메모리 누수 방지 (ARC와 Retain Cycle 해결)

Swift에서는 객체가 서로 강한 참조를 가지면 메모리가 해제되지 않는 문제(메모리 누수)가 생길 수 있어요.
이를 해결하려면 weak self를 사용해서 메모리 누수를 막아야 해요!

 

메모리 누수를 방지하는 코드

class ViewModel: ObservableObject {
    @Published var data: String = ""

    func fetchData() {
        NetworkManager.fetch { [weak self] result in
            DispatchQueue.main.async {
                self?.data = result
            }
        }
    }
}

✔️ [weak self]를 사용하면 ViewModel이 필요 없어질 때 자동으로 메모리에서 해제돼요! 🛠


🎯 정리

SwiftUI에서 메모리를 아끼는 가장 중요한 6가지 방법!
✅ @StateObject와 @ObservedObject를 적절히 사용하기
✅ LazyVStack을 사용해서 리스트 메모리 최적화
✅ AsyncImage를 활용한 이미지 로딩 최적화
✅ 백그라운드에서 무거운 작업 실행하기
✅ weak self를 사용해서 메모리 누수 방지하기

 

 

자료

reducing swiftui memory usage in large applications

728x90
Comments