동기와 비동기 그리고 큐

cheshire0105·2024년 1월 15일

iOS

목록 보기
1/46
post-thumbnail

동기와 비동기 그리고 큐

개요

  • 네트워크를 사용 해서 데이터를 받는 상황일 때 시간이 걸리기 때문에 반드시 비동기에 대한 고려를 하게 됩니다. 동기와 비동기 그리고 나아가 큐에 대해서 알아본 내용을 정리 했습니다.

동기와 비동기

  • 동기 (Synchronous) 동기 작업은 한 번에 한 가지 작업만을 수행합니다. 작업이 완료될 때까지 다른 작업은 대기 상태에 머무릅니다. 상황
    • 작업의 결과가 바로 필요한 경우
    • 순서가 중요한 연속적인 작업들
  • 비동기 (Asynchronous) 비동기 작업은 백그라운드에서 작업을 수행하며, 해당 작업이 완료되기를 기다리지 않고 다음 작업을 즉시 시작합니다. 상황
    • 시간이 오래 걸리는 작업 (예: 네트워크 요청, 파일 읽기/쓰기)
    • 사용자 인터페이스를 막지 않고 백그라운드에서 작업을 수행해야 할 때
    • 동시에 여러 작업을 처리해야 할 때
  • 큐 (Queue) 작업을 관리하기 위한 데이터 구조입니다. 스위프트에서는 GCD (Grand Central Dispatch)를 통해 동기/비동기 작업을 다양한 큐에서 실행할 수 있습니다. 상황
    • 메인 큐 (Main Queue): UI 업데이트와 같은 사용자 인터페이스 관련 작업을 수행합니다. 모든 UI 작업은 메인 큐에서 실행되어야 합니다.
    • 백그라운드 큐 (Background Queue): 시간이 오래 걸리거나 복잡한 작업을 백그라운드에서 수행할 때 사용합니다.
    • 우선순위 큐 (Priority Queue): 특정 작업에 우선순위를 부여하고 싶을 때 사용합니다.

동기, 비동기, 큐를 고민 해야 하는 상황

  • 성능 최적화: 사용자에게 빠르고 부드러운 응답을 제공하기 위해 필요합니다.
  • 사용자 경험 개선: 앱이 멈추거나 "응답 없음" 상태가 되지 않도록 하기 위해 필요합니다.
  • 자원 최적화: CPU, 메모리, 네트워크 등의 자원을 효율적으로 사용하기 위해 필요합니다.

Combine 과 RXSwift

개요

  • 리액티브 프로그래밍은 데이터의 흐름과 변화에 중점을 둔 프로그래밍 패러다임입니다. 이는 "반응형"이라는 의미에서 가져온 용어로, 데이터나 이벤트의 변화에 "반응"하는 방식으로 동작합니다. 주로, 네트워크 통신 같은 비동기 작업에서 데이터가 변화할 때, 그 변화를 감지하고 이를 UI에 적절하게 반영해야 하는 상황에서 리액티브 프로그래밍이 유용합니다. 예를 들어, 네트워크로부터 데이터를 받아오는 작업이 비동기적으로 진행되고 있을 때, 데이터가 도착하면 UI를 자동으로 업데이트하는 것이 리액티브 프로그래밍의 한 예입니다. 리액티브 프로그래밍은 데이터 스트림을 중심으로 합니다. 이 스트림은 연속적인 데이터 또는 이벤트의 흐름을 나타내며, 이 스트림에 변화가 발생하면 이에 반응하여 다양한 연산을 수행하거나 UI를 업데이트 할 수 있습니다. 따라서, 네트워크와의 통신이 비동기 상태에서 이루어지며, 받아온 데이터의 변화를 감지하여 UI에 적용하는 과정에서 리액티브 프로그래밍이 큰 도움을 줍니다.

활용

  • 복잡한 비동기 작업의 관리
    • 여러 비동기 작업을 순차적으로 또는 동시에 실행하고, 그 결과를 조합하거나 변환하는 등의 복잡한 시나리오를 쉽게 처리할 수 있습니다.
  • 동적 UI 업데이트
    • 사용자 입력, 네트워크 응답 등 다양한 이벤트에 반응하여 UI를 동적으로 업데이트해야 할 때 유용합니다.
  • 스트림 기반의 작업: 데이터 스트림을 생성, 변환, 필터링, 조합하는 등의 작업을 체인으로 연결하여 처리할 수 있습니다.
  • 에러 핸들링
    • 비동기 작업 중 발생하는 에러를 중앙 집중적으로 처리하거나 복구 작업을 수행할 수 있습니다.
  • 메모리 관리
    • RxSwiftCombineDisposableCancellable 개념을 통해 리소스와 메모리 관리를 도와줍니다.
  • 코드 간소화
    • 리액티브 프로그래밍을 사용하면 callback 지옥이나 복잡한 상태 관리 코드를 줄일 수 있습니다.

Combine vs RXSwift

  • RxSwift
    • RxSwift는 ReactiveX의 Swift 버전입니다. 여러 플랫폼과 언어에 걸쳐 일관된 리액티브 프로그래밍 인터페이스를 제공합니다.
    • iOS 8 이상에서 사용할 수 있습니다.
  • Combine
    • Apple이 iOS 13, macOS 10.15, watchOS 6 및 tvOS 13에서 도입한 리액티브 프로그래밍 프레임워크입니다.
    • Apple의 네이티브 환경에 특화되어 있으며, SwiftUI와의 통합이 잘 되어 있습니다.

GCD와 Scheduler

개요

  • 스위프트에서는 비동기 작업을 처리하기 위해 주로 애플이 제공하는 GCD라는 프레임워크를 활용합니다.

GCD (Grand Central Dispatch)

  • GCD는 애플이 제공하는 저수준의 동시성 및 병렬 처리 라이브러리로, 여러 작업을 동시에 처리하거나 순차적으로 처리할 수 있게 해줍니다.
  • GCD를 통해 메인 큐, 글로벌 큐, 사용자 정의 큐와 같은 다양한 큐에 작업을 할당하고, 그 작업들을 동기 또는 비동기 방식으로 실행할 수 있습니다.

RxSwift의 특징과 활용

  • RxSwift는 기본적으로 리액티브 프로그래밍 패러다임을 따르는 라이브러리입니다.
  • UIKit, 애플이 제공하는 UI 프레임워크는 명령형이기 때문에, 개발자가 직접 UI의 상태를 관리하고 변경해야 합니다.
  • 반면에, SwiftUI는 데이터의 변화에 따라 UI가 자동으로 반응하며, @State, @Binding과 같은 프로퍼티 래퍼를 사용하여 데이터와 UI 간의 바인딩을 선언적으로 정의할 수 있습니다.

SwiftUI와 RxSwift의 차이점

  • SwiftUI는 애플이 제공하는 선언형 UI 프레임워크로, 데이터의 변화에 따라 UI가 자동으로 업데이트됩니다.
  • RxSwift는 리액티브 프로그래밍을 위한 라이브러리로, 데이터의 흐름과 변화를 중심으로 프로그래밍할 수 있게 도와줍니다.
  • 즉, SwiftUI는 UI 구성에 중점을 둔 프레임워크이며, RxSwift는 데이터의 흐름과 그에 따른 반응을 관리하는 데 중점을 둔 라이브러리입니다.

RXSwift와 GCD의 비동기 처리의 차이

1. GCD (Grand Central Dispatch)

특징

  • GCD는 애플이 제공하는 저수준의 동시성 라이브러리입니다.
  • 큐를 사용하여 작업을 스케줄링하고, 동기 또는 비동기로 작업을 실행합니다.
  • 작업의 결과를 가져오기 위해서는 콜백, 클로저 등을 사용해야 합니다.

예시

swiftCopy code
// GCD를 사용하여 백그라운드에서 작업을 수행하고, 그 결과를 메인 스레드에서 처리
DispatchQueue.global().async {
    let result = "비동기 작업 결과"

    DispatchQueue.main.async {
        print("메인 스레드에서 결과 출력: \(result)")
    }
}

2. RxSwift

특징

  • RxSwift는 리액티브 프로그래밍을 위한 라이브러리입니다.
  • 데이터 스트림을 생성, 변환, 조합하는 등의 작업을 체인으로 연결하여 처리할 수 있습니다.
  • ObservableObserver 패턴을 기반으로 하며, 스트림의 변화에 반응하는 코드를 작성합니다.

예시

swiftCopy code
let observable = Observable<String>.create { observer in
    observer.onNext("비동기 작업 결과")
    observer.onCompleted()
    return Disposables.create()
}

observable
    .observeOn(MainScheduler.instance)  // 메인 스레드에서 결과를 처리
    .subscribe(onNext: { result in
        print("메인 스레드에서 결과 출력: \(result)")
    })
    .disposed(by: disposeBag)

요약

  • GCD는 작업의 실행 컨텍스트를 관리하는 데 중점을 둡니다. 작업과 결과 처리는 주로 콜백을 통해 이루어집니다.
  • RxSwift는 데이터나 이벤트의 흐름을 중심으로 프로그래밍하게 됩니다. 작업의 결과는 Observable 스트림을 통해 전달되며, 이 스트림에 반응하는 방식으로 코드를 작성합니다.

따라서, RxSwift를 사용하면 비동기 작업과 그 결과를 더 선언적이고 체인 형식으로 표현할 수 있습니다. 이로 인해 복잡한 비동기 로직도 간결하게 표현할 수 있게 됩니다.

선언적, 체인 형식

선언적 (Declarative)

  • 선언적 프로그래밍은 "어떻게"가 아닌 "무엇을" 하는지에 중점을 둡니다. 예를 들어, 배열의 모든 항목을 2배로 만들려면 명령형 방식으로는 반복문을 사용하겠지만, 선언적 방식에서는 .map 함수를 사용하여 "모든 항목을 2배로 만들 것"이라고 선언합니다.

체인 형식 (Chaining)

  • RxSwift에서는 여러 연산자를 연결하여 데이터 스트림을 처리합니다. 이러한 연결 방식을 "체인"이라고 합니다. 각 연산자는 입력 스트림을 받아 변환하고 새로운 스트림을 출력합니다. 이렇게 연속적으로 연결된 연산자들을 통해 복잡한 데이터 처리를 단계별로 정의할 수 있습니다.
let numbers = Observable.of(1, 2, 3, 4, 5)

numbers
    .map { $0 * 2 }  // 각 숫자를 2배로 만듭니다.
    .filter { $0 > 5 }  // 5보다 큰 숫자만 선택합니다.
    .subscribe(onNext: { print($0) })
  • .map 연산자는 숫자를 2배로 만드는 작업을 "선언"합니다.
  • .filter 연산자는 5보다 큰 숫자만 선택하는 작업을 "선언"합니다.
  • 이렇게 연산자들이 연결된 형태를 "체인"이라고 합니다.
  • 즉, RxSwift는 데이터의 흐름과 처리 방식을 연속적으로 연결하여 선언하게 해주는 라이브러리입니다. 이렇게 선언적으로 데이터 처리를 정의하면 코드의 가독성이 좋아지고, 복잡한 작업도 간결하게 표현할 수 있습니다.

swiftUI vs RXSwift

SwiftUI

  1. UI 프레임워크: SwiftUI는 애플이 제공하는 선언형 UI 프레임워크입니다.
  2. 리액티브 바인딩: 데이터와 UI 요소 간의 바인딩을 제공하여, 데이터의 상태가 변경될 때 UI가 자동으로 업데이트되게 합니다.
  3. 애플 플랫폼 전용: 현재로서는 iOS, macOS, watchOS, tvOS 등 애플의 플랫폼에서만 작동합니다.
  4. 선언형 스타일: UI 구성 요소와 그 구성 요소의 상태 및 동작을 선언적으로 정의합니다.

RxSwift

  1. 리액티브 프로그래밍 라이브러리: RxSwift는 리액티브 프로그래밍을 위한 스위프트 라이브러리입니다.
  2. 데이터 스트림 처리: 이벤트 또는 데이터의 스트림을 생성, 변환, 조합, 필터링하고 이에 반응하는 코드를 작성할 수 있습니다.
  3. 플랫폼 독립적: RxSwift 자체는 UI에 종속되지 않으므로, 애플의 플랫폼 뿐만 아니라 다른 환경에서도 사용될 수 있습니다.
  4. 체인 및 연산자: 다양한 연산자를 통해 복잡한 비동기 로직을 명확하게 표현할 수 있습니다.
  • 즉, SwiftUI는 UI 생성 및 관리에 중점을 둔 애플의 프레임워크이며, RxSwift는 리액티브 프로그래밍을 위한 일반적인 라이브러리입니다. 두 도구는 리액티브 프로그래밍 원칙에 기반을 둔다는 공통점이 있지만, 그 목적과 사용법은 다릅니다. 실제로 SwiftUIRxSwift는 함께 사용될 수 있어, RxSwift를 통해 생성된 데이터 스트림을 SwiftUI의 UI 요소에 바인딩하는 것이 가능합니다.

데이터 스트림 (Data Stream)

  • 데이터 스트림은 시간에 따라 연속적으로 발생하는 데이터의 시퀀스를 의미합니다. 이것은 일련의 이벤트나 값들로 볼 수 있으며, 이러한 이벤트나 값들은 시간에 따라 발생합니다.

특징

  1. 연속성
    1. 스트림은 지속적으로 값을 생성하거나 이벤트를 발생시킬 수 있습니다. 예를 들어, 사용자의 마우스 이동은 연속적인 위치 값을 스트림으로 생성할 수 있습니다.
  2. 비동기성
    1. 스트림에서 값이나 이벤트가 언제 발생할지 알 수 없습니다. 예를 들어, 네트워크 응답이나 사용자 입력과 같은 외부 이벤트는 예측할 수 없는 시점에 발생할 수 있습니다.
  3. 다양한 소스
    1. 스트림은 다양한 소스에서 생성될 수 있습니다. 사용자 입력, 파일, 데이터베이스, 네트워크, 센서 등 여러 소스에서 데이터를 스트림으로 받아올 수 있습니다.

작업

데이터 스트림은 다양한 작업을 수행할 수 있습니다. 일반적으로 사용되는 작업은:

  1. 변환 (Transformation)
    1. 스트림의 각 값을 다른 형태나 타입으로 변환합니다. 예를 들어, 숫자 스트림을 받아 문자열 스트림으로 변환할 수 있습니다.
  2. 필터링 (Filtering)
    1. 특정 조건을 만족하는 값만을 선택합니다.
  3. 조합 (Combination)
    1. 여러 스트림을 합쳐 하나의 스트림으로 만듭니다.
  4. 평탄화 (Flattening)
    1. 스트림의 스트림 (즉, 중첩된 스트림)을 하나의 스트림으로 평탄화합니다.
  5. 에러 핸들링
    1. 스트림에서 발생하는 에러를 처리합니다.

구독

  • 데이터 스트림은 "구독"을 통해 이벤트나 값에 반응하는 코드를 실행할 수 있습니다. 구독자는 스트림에서 발생하는 값을 받아 처리하거나, 스트림이 완료되었을 때 또는 에러가 발생했을 때의 동작을 정의할 수 있습니다.

SNS 앱에서 글쓰기 페이지를 구현하면서 글과 사진의 순서를 기억하고 보여주기 위한 간략한 구현 방법

enum PostContent {
    case text(String)
    case image(UIImage)
}

var contents: [PostContent] = []

// 가정: textView는 사용자의 텍스트 입력을 위한 UITextView입니다.
// imageView는 사용자가 선택한 이미지를 보여주기 위한 UIImageView입니다.
// addButton은 사용자가 텍스트나 이미지를 포스트에 추가하기 위한 버튼입니다.

let textObservable = textView.rx.text.orEmpty.asObservable()
let imageObservable = imageView.rx.tapGesture().when(.recognized).map { _ in imageView.image }

let addObservable = addButton.rx.tap.asObservable()

addObservable.withLatestFrom(textObservable)
    .filter { !$0.isEmpty }
    .map { PostContent.text($0) }
    .bind { [weak self] content in
        self?.contents.append(content)
    }
    .disposed(by: disposeBag)

addObservable.withLatestFrom(imageObservable)
    .filter { $0 != nil }
    .map { PostContent.image($0!) }
    .bind { [weak self] content in
        self?.contents.append(content)
    }
    .disposed(by: disposeBag)

프로그래밍 패러다임의 종류

  1. UIKit
    1. UIKit은 명령형 프로그래밍 스타일로 작성됩니다. 여기서 '명령형'은 개발자가 상태 변경을 직접 명령하며, 프로그램의 상태 변화를 일일이 관리해야 한다는 의미입니다.
  2. SwiftUI
    1. SwiftUI는 선언형 UI 프레임워크입니다. 선언형 접근 방식에서는 원하는 UI의 최종 상태를 선언하고, 프레임워크가 그 상태에 따라 UI를 자동으로 업데이트합니다.
  3. RxSwift
    1. RxSwift는 리액티브 프로그래밍을 위한 라이브러리입니다. 리액티브 프로그래밍은 데이터의 흐름과 변화에 따른 반응을 중심으로 합니다.

Swift의 함수형 프로그래밍

함수형 프로그래밍 (Functional Programming)

  • 함수형 프로그래밍은 순수 함수와 데이터의 불변성에 중점을 둡니다.
  • 순수 함수: 같은 입력에 대해서 항상 같은 출력을 반환하며, 부작용(side-effects)이 없는 함수를 의미합니다.
  • 데이터 불변성: 데이터는 한번 생성되면 그 이후로 변하지 않는 특성을 의미합니다.
  • 함수형 프로그래밍은 함수의 조합을 통해 로직을 구성하며, 상태 변경을 최소화하려고 합니다.
  • Swift는 함수형 프로그래밍 패러다임을 지원하며, map, filter, reduce와 같은 고차 함수를 사용하여 함수형 스타일로 코드를 작성할 수 있습니다.

간단히 말하면, 함수형 프로그래밍은 함수와 데이터의 관계에 중점을 둡니다. 코드는 데이터 변환을 위한 함수의 연속으로 구성됩니다.

RXSwift의 사용 의의

함수형, 명령형, 선언형 프로그래밍

  • 우리는 기존의 Swift를 사용 하면서 함수형 프로그래밍과 명령형 프로그래밍 그리고 나아가 선언형 프로그래밍의 개념으로 UI를 만들며 개념을 접했습니다.
let 나의성적 = [“A”, “A”, “A”, “A”, “B”, “D”]
  • 예를 들어 이 배열에서 A만 받도록 코드를 작성 하면
var 행복한성적: [String] = []
for grade in recentGrade {
  if grade == “A” {
    행복한성적.append(grade)
  } else {
    print(“엄마는 행복하지 않았다.)
  }
}
// print(행복한성적) // [“A”, “A”, “A”, “A”]```
  • 이렇게 코드가 길어지게 됩니다.
  • 이 방법은 기존의 우리가 사용 하던 명령형 프로그래밍 입니다.
  • 이 방식에서 조금 더 간결하게 변경 하게 되면
func stringFilter(grade: [String], returnBool: (String) -> Bool) -> [String] {
    return grade.filter(returnBool)
}
stringFilter(grade: 나의성적, returnBool: { $0 == “A” })
// [“A”, “A”, “A”, “A”]
  • 선언형으로 변경 해서 사용 할 수도 있습니다.

명령형과 선언형

  • 그렇다면 왜 우리는 각각을 명령형과 선언형으로 부르는 걸까요

령형 프로그래밍 (Imperative Programming)

  • "어떻게" 해야 하는지에 대한 단계별 명령이나 절차를 중심으로 합니다.
  • 코드는 상태의 변화와 데이터의 변환을 위한 연속된 명령으로 구성됩니다.
  • 위의 for 루프 예제는 "성적이 A인 것을 찾기 위해 어떻게 리스트를 반복하고 조건을 확인하며 결과 배열에 추가할 것인가?"에 대한 절차를 기술하고 있습니다.

선언형 프로그래밍 (Declarative Programming)

  • "무엇"을 하고 싶은지를 설명하고, "어떻게" 그것을 달성할지는 내부적으로 처리되게 합니다.
  • 코드는 원하는 결과나 출력을 설명하는 데 중점을 둡니다.
  • stringFilter 함수는 "나는 A 성적만 원한다"라는 의도를 명확하게 선언하며, 그 세부적인 처리는 함수 내부에 숨겨져 있습니다.

정리

  • stringFilter를 선언형이라 부르는 이유는, 이 함수를 사용할 때 우리는 "어떤 성적을 원하는지"만 선언하면 되고, 그 세부적인 처리 방법(어떻게 필터링 할 것인가)은 함수 내부에 은닉되어 있기 때문입니다.
  • 간단히 말하면, 선언형 프로그래밍은 "무엇을 원하는지"만을 명시하고, 그것을 어떻게 달성할지에 대한 구체적인 절차나 방법은 추상화하여 숨기는 방식입니다.

반응형 프로그래밍 with RXSwift

비 반응형 프로그래밍

  • 우선 비 반응형 프로그래밍의 코드 부터 작성 하겠습니다.
var a = 1
var b = 3
a + b // 4
  • 만약 a를 변경 하고 싶어서 아래와 같이 코드를 짠다면 결과가 변경 되지는 않을겁니다.
var a = 1
var b = 3
a + b // 처음(4) -> 마지막(4)
a = 3
  • a + b의 코드는 아무것도 신경 쓰지 않습니다.

반응형 프로그래밍

  • 반응형 프로그래밍은 변화에 반응 한다는 것에서 큰 의미가 있습니다.
// T 타입의 값을 가질 수 있는 Reactive 클래스를 선언합니다.
class Reactive<T> {
    // 값이 변경될 때마다 호출될 클로저의 타입을 Listener라는 별칭으로 정의합니다.
    typealias Listener = (T) -> Void
    
    // 값이 변경될 때 호출될 리스너(클로저)를 저장할 private 변수입니다.
    private var listener: Listener?
    
    // value 변수의 값이 변경될 때마다 didSet 프로퍼티 옵저버가 호출됩니다.
    var value: T {
        didSet {
            // 값이 변경되면 등록된 리스너를 호출하여 새 값을 전달합니다.
            listener?(value)
        }
    }
    
    // 초기화 메서드에서 초기 값을 받습니다.
    init(_ value: T) {
        self.value = value
    }
    
    // 값을 관찰하고자 할 때 호출되는 메서드입니다.
    // 리스너를 등록하면 값의 변화를 알 수 있습니다.
    func bind(listener: @escaping Listener) {
        // 전달받은 리스너(클로저)를 저장합니다.
        self.listener = listener
        // 리스너를 등록할 때 현재 값을 한번 호출해줍니다.
        listener(value)  
    }
}

// 사용 예제
let reactiveA = Reactive(1)  // 1 값을 갖는 Reactive 인스턴스 생성
let reactiveB = Reactive(3)  // 3 값을 갖는 Reactive 인스턴스 생성

// reactiveA의 값 변화를 구독(관찰)합니다.
reactiveA.bind { newValue in
    print("A의 값이 \(newValue)로 변경되었습니다.")
}

// reactiveB의 값 변화를 구독(관찰)합니다.
reactiveB.bind { newValue in
    print("B의 값이 \(newValue)로 변경되었습니다.")
}

reactiveA.value = 3  // "A의 값이 3으로 변경되었습니다." 출력
reactiveB.value = 4  // "B의 값이 4로 변경되었습니다." 출력
  • 위 코드에서 사용된 개념

    Typealias

    typealias는 Swift에서 타입에 대한 다른 이름을 제공하는 방법입니다. 주로 코드를 더 읽기 쉽게 만들거나 복잡한 타입의 이름을 간단하게 만들 때 사용됩니다. 예제에서는
    typealias Listener = (T) -> Void
    이 코드는 (T) -> Void 타입의 함수 (즉, T 타입의 인자를 받아 반환값이 없는 함수)에 대한 별칭으로 Listener라는 이름을 사용하겠다는 것을 의미합니다. 이후 코드에서 Listener라는 이름을 사용하면 (T) -> Void 타입의 함수를 의미하는 것이 됩니다.

    저장 프로퍼티 (Stored Properties)

    Swift에서 클래스, 구조체, 열거형은 프로퍼티를 가질 수 있습니다. 프로퍼티는 해당 타입의 인스턴스와 연관된 값을 저장하거나 계산하는 방법을 제공합니다. 저장 프로퍼티는 객체의 일부로 값을 저장하는 변수 또는 상수입니다. 예제에서는
    private var listener: Listener?
    var value: T {
        didSet {
            listener?(value)
        }
    }
    • listenerListener 타입의 옵셔널 변수로, 리스너(클로저)를 저장하는 프로퍼티입니다.

    • valueT 타입의 변수로, 해당 Reactive 인스턴스가 감싸고 있는 값을 나타냅니다. didSet은 프로퍼티 옵저버로, value의 값이 바뀔 때마다 호출되는 블록입니다. 여기서는 값이 변경되면 저장된 listener를 호출하여 새로운 값을 전달합니다.

      이 두 프로퍼티 모두 해당 Reactive 객체 내에서 값을 저장하기 위해 사용되는 저장 프로퍼티입니다.

// 사용 예제
let reactiveA = Reactive(1)  // 1 값을 갖는 Reactive 인스턴스 생성
let reactiveB = Reactive(3)  // 3 값을 갖는 Reactive 인스턴스 생성
reactiveA.value + reactiveB.value 
  • 이젠 두가지를 더 하면 값에 따라 변경 된 값으로 더하기가 됩니다.
  • 단순히 더하는게 아니고 a와 b의 값에 따라 결과가 변경 되기 때문입니다.
  • 즉 반응형 프로그래밍은 변화를 기다리고 있고, 변하면 그 값을 나타내고, 보여주고, 구독하고, 관찰 합니다. 스위프트에서 알람이나 값이 변경 되었을 때 알게 되는 NSNotification과 비슷합니다.

반응형 프로그래밍과 RXSwift

  • 반응형 프로그래밍은 데이터의 변화를 받아들이고 사용 함에 있어서 상당한 장점을 가지고 있습니다.
  • 반응형 프로그래밍인 RXSwift는 그렇기 때문에 비동기에서 일어나는 일들을 처리 하고 알람을 띄우는 것에서 많은 활용성이 있습니다. 데이터가 변함에 따라 반응 하기 때문입니다.
let 기기방향 = UIDevice.current
let 반응형방향 = Reactive(기기방향)

반응형방향.observe { 현재방향 in
  switch 현재방향 {
    case .오른쪽가로모드: print(“가로!)
    case .위아래바뀐세로모드: print(“이상한 세로!)
    case .왼쪽가로모드: print(“가로!)
    case .세로모드 { print(“세로!) }
  }
}
  • 기기를 돌림에 따라 변화 하는 로직을 만들었습니다.
  • 기기가 돌아감에 따라서 반응 하고 코드가 실행 됩니다.

반응형 프로그래밍과 함수형 프로그래밍

  • 세로 모드 일 때만 출력 하는 코드 입니다.
반응형방향.observe { 현재방향 in
  .filter { 현재방향 == .세로모드 }
  .observe { 현재방향 in
    switch 현재방향 {
      case .오른쪽가로모드: print(“가로!)
      case .위아래바뀐세로모드: print(“이상한 세로!)
      case .왼쪽가로모드: print(“가로!)
      case .세로모드 { print(“세로!) }
   }
 }
  • filtertruefalse를 반환 합니다.

  • true현재방향이 == .세로모드 일 때 아래의 switch문을 실행 합니다.

  • closure 버전 입니다.

.filter { $0 == .세로모드 } // 아니라면 돌아갑니다
.observe {
  switch $0 {
    case .오른쪽가로모드: print(“가로!)
    case .위아래바뀐세로모드: print(“이상한 세로!)
    case .왼쪽가로모드: print(“가로!)
    case .세로모드 { print(“세로!) }
 }
}

0개의 댓글