티스토리 뷰

 

 

 

 

combine과 observableobject를 사용하여 간단하게 구현해 보고 비교해보려 한다.

 

 

 

2024.03.15 - [Swift] - [swift] Combine & ObservableObject 

 

[swift] Combine & ObservableObject

오늘은 swiftUI에서 꼭 알아야 하는 Combine랑 ObservableObject에 대해 차이점과 각 특징들을 비교해보자! Combine 공식문서를 찾아보면 combine은 비동기 작업과 이벤트 처리를 사용자 정의한다고 작성되어

yanni13.tistory.com

 

이전 포스팅에서 같이 개념을 설명하면서 예제까지 작성하려 했으나 생각보다 길어질 거 같아서 글을 나누었다.

대충 2편이라고 생각해주면 될 듯!

 

 

 

 

예제

 

 

Combine

import Combine
import SwiftUI

struct ContentView: View {
    
    
    var vm = CombineViewModel()
    @State var anyCancellable = Set<AnyCancellable>()
    @State var number = 0
    
    var body: some View {
        VStack {
            Text("John Appleseed, Age: \(number)")
                .padding()
            
            Button(action: {
                vm.number.value += 1
                //print(vm.number.value)
            }, label: {
                Text("Celebrate Birthday")
            })
            .onAppear {
                vm.number.sink { [self]  value in
                    DispatchQueue.main.async {
                        self.number = value
                    }
                }.store(in: &anyCancellable)
            }
        }
    }
    
}

 

위 코드는 애플 공식문서에서 올려놓은 코드를 참고하여 가공했다.

코드를 하나하나 뜯어보자!!!!!

 

view랑 viewmodel를 따로 구분해서 파일을 만들었다.

 

CombineViewModel

import Combine
import SwiftUI

class CombineViewModel {
    var number = CurrentValueSubject<Int, Never>(23)
    //하나의 값을 둘러싸고 값이 변동될 때 publish
}

 

코드에 대한 전반적인 설명은 celebrate birthday 버튼을 누르면 john의 나이가 증가한다. (내 나이는 아니길 바람 ㅎ)

 

공식문서에 올려놓은 코드를 봤을 때 나는 combine으로 구현하려 했는데 무슨 AnyCancellable에다가.. sink에다가.. 이게 뭔데?? 했었다

 

차근차근 파헤쳐 보자.

 

 

AnyCancellable

 

combine 프레임워크에서 발생하는 구독을 취소하거나 처리하는 데 사용되는 타입이다.

 

combine에서 subscriber에게 값을 전달하는 동안 구독이 취소되거나 완료되면 해당 구독을 메모리에서 해제해야 하기 때문에 그때 쓰이는게 AnyCancellable이다.

 

메모리 누수를 방지하니 메모리 관점에서 좋을거 같다.

 

@State var anyCancellable = Set<AnyCancellable>()

 

AnyCancellable을 저장하는 set타입을 변수로 지정해 뷰가 해제될 때 구독을 취소할 수 있도록 선언해 주었다.

 

 

 

.store(in: &anyCancellable)을 통해 구독을 저장하여 뷰가 해제될 때 해당 구독을 취소할 수 있다.

 

 

 

 

sink

 

sink의 반환값도 AnyCancellable임을 확인할 수 있다.

공식문서를 보면.. 절대 실패하지 않는 publisher에 폐쇄 기반을 가진 subscriber를 첨부한다고 한다

 

이해하기 쉽게 설명해 보자면, publisher의 값을 처리하는 역할을 하며 publisher가 subscriber에게 값을 전달할 때 사용된다.

 

 

vm.number.sink { [self]  value in
                    DispatchQueue.main.async {
                        self.number = value
                    }

 

위의 코드에서 sink메서드를 사용하여 vm의 number를 구독하고 값의 변경사항을 감지하여 UI를 업데이트하도록 한다.

 

Combine 으로 구현

 

 

ObservableObject

import SwiftUI
import Combine

class Contact: ObservableObject {
    @Published var name: String
    @Published var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

    func haveBirthday() -> Int {
        age += 1
        return age
    }
}

struct ObserableObject: View {
    @StateObject private var john = Contact(name: "John Appleseed", age: 23)

    var body: some View {
        VStack {
            Text("\(john.name), Age: \(john.age)")
                .padding()
            Button("Celebrate Birthday") {
                let newAge = john.haveBirthday()
                print("New age is \(newAge)")
            }
        }
        .onAppear {
            let cancellable = john.objectWillChange.sink { _ in
                print("\(john.age) will change")
            }
        }
    }
}

 

위와 똑같은 UI와 기능도 똑같은데 코드는 다른 게 신기하지 않나요????

 

아무튼.. 이 코드들도 파헤쳐보자.

 

combine을 사용한 observableobject를 구현한 예시이다.

name과 age를 @publisher 속성을 채택해 속성의 변경사항을 swiftUI에 알리는 역할을 한다.

 

 

StateObject

 

관찰 가능한 객체를 인스턴스화하는 propertyWrapper라고 한다.

 

StateObject까지 설명하면 포스팅하려고 했던 주제에서 벗어나게 되는 거 같아서 이 부분은 ObservedObject와 함께 작성하도록 하겠다.

 

뷰의 상태를 관리하고 추적한다고만 일단 알고 넘어가자!

 

@StateObject private var john = Contact(name: "John Appleseed", age: 23)

 

위 코드에서는 해당 뷰의 상태를 관리하는 속성이며 contect 클래스의 인스턴스를 생성하여 john에게 저장된다는 정도로만 이해해 보자

 

 

ObjectWillchange

 

객체가 변경되기 전에 내보내는 publisher라고 한다. 

 

objectWillChange는 ObservableObject 프로토콜의 일부이며 이 프로토콜로 구현한 객체는 내부의 데이터가 바뀔 때마다 publisher를 통해 변경사항을 swiftUI에 알릴 수 있다.

 

 

let cancellable = john.objectWillChange.sink { _ in
                print("\(john.age) will change")
            }

 

위의 코드에서는 objectWillChange에 대한 sink를 설정하여 john의 상태가 변경될 때마다 호출되며 나이가 변경된다.

 

 

ObservableObject로 구현

 

 

 

느낀 점

여전히 스유에 대해서 이해하는 건 어렵지만.. 확실히 블로그에 정리하고 코드를 하나하나 뜯어보면서 적용시켜 보니 그냥 애플 공식문서를 읽고 WWDC 강의만 봤을 때 보다 훨씬 이해가 잘 되긴 한다.

 

이제 0.1 걸음 정도.. 나아갔다고 할 수 있으려나 하하하하 

뭐든 꾸준히 해보자~!~!~! 아좌좌..

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

[iOS] lazy var에 대해 알아보기  (0) 2024.09.21
[iOS/Swift] Closure  (0) 2024.05.08
[swiftUI] NSPredicate  (0) 2024.03.30
[Swift] Optional  (1) 2024.03.28
[Swift] map 함수 정리하기  (0) 2024.02.27
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함