iyOmSd/Title: SwiftUI

[SwiftUI] Published, ObservableObject

냄수 2021. 1. 29. 17:43
반응형

SwiftUI를 공부하다보면

@Published 라는 키워드를 보게될거에요

이와 같이 언급되는게 ObservableObject죠

 

ObservableObject는 필수구현을 필요로 하지않는 프로토콜이에요

Combine에 속한 기능이구요

클래스에서만 사용가능하고

ObservableObject를 준수한 클래스는

objectWillChange라는 프로퍼티를 사용할 수 있어요(ObservableObjectPublisher타입)

objectWillChange.send()를 이용하기위함이죠

이 send()함수는 변경된 사항이 있다고 알려주는 거에요

 

Combine?!!? RxSwift같이 쓰는거잖아요..!! 어렵잖아요..!

라고 생각할수 잇지만

 

스유를 공부하다보면 자연스레 접할수있어요 ㅎㅎ

Combine도 따로 공부하시면 좋아요!

저도 곧...해야죠..

 

가지고있는 변수가 적으면 send()함수를 몇번 해줘서 간단하게할 수 있겟지만

변수도 많고 수정 되는부분이 많고 복잡하다면?!

하나하나 신경쓰기 힘들어지겟죠

 

이를 대신해주는 기능이 @Published 속성래퍼가 해주는 역할이에요

해당 변수가 변경되면 자동으로 objectWillChange.send()를 호출해줘요

간편하죠!

 

 

SwiftUI는 View가 class가 아닌 struct에요

해당 뷰에대한 참조를 가지고 있을 수 가없어요

 

그렇다면 리스트가 일부만 변경되었을때 항상 그 뷰들을 새로 그릴까요??

SwiftUI는 매번 그리는것을 피하기위해서 최선을 다한다고해요

뷰를 렌더, 즉 그리는 단계에 있어서는 성능 최적화하는 동작이있고 필요할 때만 그린다고해요

 

무슨말이냐면

ForEach를 이용해서 뷰를 10개를 그린뒤

한개의 뷰만 변경해서 새로 그릴때 참조를 할 수없기때문에 10개를 또 새로그린다? 낭비겟죠 당연히

코드로 실행하는건 비용이 비싸지않기때문에 다 돌아가고(코드로 그려보기)

직접 보여지는 뷰를 그리는건 비용이 비싸요 그래서 필요한 것만 새로 그려주는 방식이라고 해요

 

이를 테스트해보기위해서

init에 print를 찍으면 모든 뷰 10개의 출력을 볼수 있고

뷰가 그려질때 랜덤색을 주기로 했는데

하나의 뷰만 변경할때 하나의 뷰만 변하는 걸 볼수있어요

 

 

감시대상 클래스 변수에는 @ObservedObject를 선언하고 그 변수의 class에 ObservableObject를 준수해주고

변경됨을 알릴 변수에는 @Publisher을 선언한는 방식으로 사용해요

 

struct TestView: View {
	// 감시대상 클래스
    @ObservedObject var viewModel: ViewModel = ViewModel(count: 10)
    
    var body: some View {
        ForEach(0..<viewModel.models.count) { index in
            RandomView(id: index, model: viewModel.models[index]).onTapGesture {
                let changeNum = Int.random(in: 0...100)
                viewModel.models[index].id = changeNum
                print("tap change: \(changeNum)")
            }
        }
    }
}

struct RandomView: View {
    let color: [Color] = [.red, .black, .blue, .gray, .green]
    var id: Int // Identifiable test
    var model: Model
    var body: some View {
        Text("\(model.id)")
            .foregroundColor(color.randomElement()!)
    }
    
    init(id: Int, model: Model) {
        self.id = id
        self.model = model
        print("init")
    }
}

class ViewModel: ObservableObject {
	// 변경을 감지할 변수
    @Published var models: [Model] = []
    
    init(count: Int) {
        for _ in 0..<count {
            models.append(Model(id: Int.random(in: 0...100)))
        }
    }
}

struct Model {
	// Identifiable test
    var id: Int
}

하나의 텍스트를 클릭하면 하나의 텍스트의 색만 변하는걸 볼 수 있어요

모든 뷰가 다시그려진다면 모든 텍스트의 색이 랜덤으로 변해야 하지만 그렇지않을걸 알 수 있죠

 

 

반응형