ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Combine - ObservableObject / @Published / @ObservedObject
    Combine 2022. 3. 17. 21:00

    안녕하세요. 그린입니다🟢

    이번 포스팅에서는 ObservableObject라는 프로토콜에 대해 학습해보겠습니다🙋🏻

    추가로 이어져서 @Published@ObservedObject도 보시죠!

    요즘 개인적으로 많이 바빠져서 블로그를 소홀하게 될 것 같아..
    많은 양을 공부하고 포스팅하는것보다 짧게 학습하고 포스팅하면서 꾸준함을 잃지 않는 전략으로 당분간 가려합니다!
    (안그러면 어느 순간 놔버릴것 같은....)

    그래서 이번에 준비한 주제는 초심부터 찾자! 느낌으로 저번에 Combine의 대표적 개념들을 공부하면서

    연결되어 ObservableObject라는 주제를 선정하게 되었네요ㅎㅎ

     

    그럼 신속하게 학습하고 치고 빠져 봅시다🙌

    ObservableObject?

    공식문서의 정의는 개체 변경 전 방출하는 게시자가 있는 개체 유형이라고 합니다.

    뭔소리?!?!?

    흠 일단 정의는 이래요.

    protocol ObservableObject : AnyObject

    클래스 프로토콜입니다.

    그러니까 생각해보면 이 프로토콜을 따르는 클래스 인스턴스를 관찰하다 어떠한 값이 변경되면 뷰 업데이트를 해줍니다.

    아직 감이 안올 수 있으니 한번 코드로 보시죠!

    (참고로, 공식문서의 코드 전문입니다.)

    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
        }
    }
    
    let john = Contact(name: "John Appleseed", age: 24)
    cancellable = john.objectWillChange
        .sink { _ in
            print("\(john.age) will change")
    }
    print(john.haveBirthday())
    // Prints "24 will change"
    // Prints "25"

    자 Contact라는 클래스가 ObservableObject 클래스 프로토콜을 따릅니다.

    내부에는 프로퍼티 2개가 있는데, 앞에 붙은 @Published 는 곧바로 알아볼거니 일단 무시 ㄱㄱ!

    그리고 john이라는 Contact 인스턴스를 초기화하여 만들어줍니다.

    objectWillChange를 통해 개체의 변경사항이 있기전에 내보내는 게시자로 탐색해줍니다.

    즉 마지막 코드의 출력문을 통해 haveBirthday 메서드를 호출하면 age 프로퍼티 값이 바뀌죠?

    그러면 요 will change 구문이 먼저 출력되고 그다음 age += 1한 값이 출력됩니다.

    즉 이러한걸 우리는 뷰에 적용해볼 수 있을거에요.
    또한 ObservableObject를 학습하면서 파생되게 중요한 것이 @Published와 @ObservedObject가
    데이터 모델과 뷰를 바인딩 할때 필요한 녀석들인걸 알게 되었어요.
    그럼 이제 이 친구들을 파악해보시죠!

    Published

    자 공식문서 고고고!

    속성을 게시하는 유형이라고 합니다.

    @propertyWrapper struct Published<Value>

    정의를 보면 propertyWrapper입니다.

    @Published를 붙여 만들면 이 유형으로 생성됩니다.

    또한 $ 오퍼레이터를 붙여 게시자에 엑세스 할 수 있습니다.

    요것도 역시나 코드로 고고하시죠!

    class Weather {
        @Published var temperature: Double
        init(temperature: Double) {
            self.temperature = temperature
        }
    }
    
    let weather = Weather(temperature: 20)
    cancellable = weather.$temperature
        .sink() {
            print ("Temperature now: \($0)")
    }
    weather.temperature = 25
    
    // Prints:
    // Temperature now: 20.0
    // Temperature now: 25.0

    Weather라는 클래스에 temperature 프로퍼티에 @Published를 붙여 속성 게시 유형으로 만듭니다.

    그리고 weather 인스턴스를 만듭니다.

    값 변화를 파악하기 위해 설정해주고 해당 $temperature를 이용해 게시자에 엑세스 할 수 있도록 해줍니다.

    그러고 해당 값을 변화시켜주면 출력문이 해당 값에 맞게 출력되게 됩니다!

    그런데 여기서 새로운 값이 실제로 설정되기전에 저 sink블럭이 실행됨으로 두번 현재값과 변경값이 출력되게 됩니다.

    또한 해당 속성은 오직 클래스에서만 쓸 수 있으니 유의해주세요🙋🏻

    즉 뷰와 연결하면 해당 값이 변화할때 마다 업데이트 시켜 주겠네요.

    OvservedObject

    공식문서 코드 정의를 봅시다.

    @propertyWrapper @frozen struct ObservedObject<ObjectType> where ObjectType : ObservableObject

    역시나 propertyWrapper군요.

    ObservableObject 타입에서 해당되네요.

    ObservableObject를 구독하며 값 업데이트가 발생하면 뷰를 갱신해주는 친구입니다.

    코드로 보시죠!

    (공식 문서에 설명과 코드가 정말 없어서 한번 간단히 만들어봤어요.

    class User: ObservableObject {
      @Published var age = 10
    }
    
    struct MainView: View {
      @StateObject var green = User()
      
      var body: some View {
        Text("Age is \(green.age)")
        SubView(user: green)
      }
    }
    
    struct SubView: View {
      @ObservedObject var user: User
    
      var body: some View {
        Button("Plus Age") {
          user.age += 1
        }
      }
    }

    자 이렇게 뷰에 적용합니다.

    SubView에 @ObesrvedObject로 User 클래스 타입으로 프로퍼티를 지정해줍니다.

    해당 클래스에서는@Published age를 가집니다.

    SubView에서는 버튼을 두어 클릭 시 age의 값을 변경해줍니다.

    MainView에서는 해당 User 타입을 참조하여 프로퍼티를 만듭니다.

    SubView에 해당 프로퍼티를 넘겨주어 연결해줍니다.

    그러면 뷰의 업데이트가 값이 바뀔때 바로 갱신되며 보여지게 되겠네요🙌

    마무리

    이건 정말 해봐야 아는...

    아주 작게 프로젝트로 코드를 돌려봐야 이해가 잘되는 그런 친구들이네요!

    어렵지 않은데 뇌로만 이해하려면 어려운 친구들...

    힘내봐요🤯

    [참고자료]

    https://developer.apple.com/documentation/combine/observableobject

     

    Apple Developer Documentation

     

    developer.apple.com

    https://developer.apple.com/documentation/combine/published

     

    Apple Developer Documentation

     

    developer.apple.com

    https://developer.apple.com/documentation/swiftui/observedobject

     

    Apple Developer Documentation

     

    developer.apple.com

    'Combine' 카테고리의 다른 글

    Combine - ConnectablePublisher  (0) 2022.03.28
    Combine - multicast / share  (0) 2022.03.24
    Combine - Cancellable  (2) 2022.03.10
    Combine - Scheduler  (0) 2022.03.07
    Combine - Subject  (0) 2022.02.28
Designed by Tistory.