Notice
Recent Posts
Recent Comments
Link
ยซ   2024/05   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
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
Archives
Today
Total
๊ด€๋ฆฌ ๋ฉ”๋‰ด

lgvv98

[Swift] extension Reactive ๋ณธ๋ฌธ

apple/๐Ÿฆ• UIKit & ReactiveX

[Swift] extension Reactive

๐Ÿฅ• ์บ๋Ÿฟ๋งจ 2022. 1. 12. 17:24

โœ… ์ด๋ฒˆ ์‹œ๊ฐ„์—๋Š” extension Reactive์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณผ ์˜ˆ์ •์ด์•ผ.

 

์šฐ๋ฆฌ๊ฐ€ ์„ค์น˜ํ•œ RxSwfit ์•ˆ์—๋Š” Reactive.swift ํŒŒ์ผ์ด ์žˆ๋Š”๋ฐ, custom point๋กœ ์‚ฌ์šฉํ•˜๋ผ๊ณ  ํ•œ๋‹ค.

 

๐ŸŸ  Reactive.swift

 Use `Reactive` proxy as customization point for constrained protocol extensions.

 General pattern would be:

 // 1. Extend Reactive protocol with constrain on Base
 // Read as: Reactive Extension where Base is a SomeType
 extension Reactive where Base: SomeType {
 // 2. Put any specific reactive extension for SomeType here
 }

 With this approach we can have more specialized methods and properties using
 `Base` and not just specialized on common base type.

 */

public struct Reactive<Base> {
    /// Base object to extend.
    public let base: Base

    /// Creates extensions with base object.
    ///
    /// - parameter base: Base object.
    public init(_ base: Base) {
        self.base = base
    }
}

 

โœ… ๊ทธ๋ ‡๋‹ค๋ฉด Reactive ์ด๋ฏธ ๊ตฌํ˜„๋œ RxSwift ํŒŒ์ผ์—์„œ๋Š” ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์„๊นŒ?

extension Reactive where Base: UIButton {
    
    /// Reactive wrapper for `TouchUpInside` control event.
    public var tap: ControlEvent<Void> {
        return controlEvent(.touchUpInside)
    }
}

์ด๋Ÿฐ์‹์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๋‹ค.

 

๊ทธ๋Ÿผ ์šฐ๋ฆฌ๋„ ์ด์— ๋งž์ถฐ์„œ customํ•˜๊ฒŒ๋” ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ฒ ์ง€?

 

โœ… ๋ณธ๊ฒฉ์ ์œผ๋กœ ๋“ค์–ด๊ฐ€๊ธฐ ์ „์—... ์•Œ์•„์•ผ ํ•  3๊ฐ€์ง€

1๏ธโƒฃ ControlEvent - ๊ฐ’์„ ๊ด€์ฐฐํ•  ์ˆ˜๋Š” ์žˆ์œผ๋‚˜, ๊ฐ’์„ ์ฃผ์ž…์‹œํ‚ค์ง€๋Š” ๋ชปํ•จ.

2๏ธโƒฃ ControlProperty - ๊ฐ’์„ ์ฃผ์ž…์‹œํ‚ฌ ์ˆ˜๋„ ์žˆ๊ณ , ๊ฐ’์˜ ๋ณ€ํ™”๋„ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ๋‹ค.

3๏ธโƒฃ Binder - ๊ฐ’์„ ์ฃผ์ž…์‹œํ‚ฌ ์ˆ˜ ์žˆ์œผ๋‚˜, ๊ฐ’์˜ ๋ณ€ํ™”๋Š” ๊ด€์ฐฐํ•˜์ง€ ๋ชปํ•จ.

 

๐ŸŸ  UIViewController+Rx

import Foundation

import RxCocoa
import RxSwift

extension Reactive where Base: UIViewController {
    var viewWillAppear: ControlEvent<Void> {
        let source = self.methodInvoked(#selector(Base.viewWillAppear(_:))).map { _ in }
        return ControlEvent(events: source)
    }
}

์‚ฌ์šฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

	rx.viewWillAppear // UIViewController+Rx์— ์ •์˜
            .asObservable() // ๋ฐ˜ํ™˜๋˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ์˜ต์ €๋ฒ„๋ธ” ํƒ€์ž…์œผ๋กœ ๋ฐ›๋Š”๋‹ค. (๊ณต์‹๋ฌธ์„œ link์— ์˜ํ•˜๋ฉด From์œผ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์Œ)
            .bind(to: viewWillAppearSubject)
            .disposed(by: disposeBag)

 

๐ŸŸ  UIButton+Rx.swift

import Foundation

import RxCocoa
import RxSwift

extension Reactive where Base: UIButton {
    // ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ชฉ์ !
    public var customChangeTitle: Binder<String> {
        let s = Binder<String>(base) { btn, text in
            btn.setTitle(text, for: [])
        }
        return s
    } // ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ชฉ์ !
}

์œ„ ์•„๋ž˜ ๋‘ ์ฝ”๋“œ๋Š” target์ด base์ž„์œผ๋กœ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ํ•œ๋‹ค. 

extension Reactive where Base: UIButton {
    // ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ชฉ์ !
    public var customChangeTitle: Binder<String> {
        let s = Binder<String>(base) { _, text in
            base.setTitle(text, for: [])
        }
        return s
    } 
}
Binder<String>(base, binding: {}) // ํด๋กœ์ € ๊ตฌ๋ฌธ ์ด๋ ‡๊ฒŒ๋„ ์ž‘์„ฑ ๊ฐ€๋Šฅ

์–ด๋–ค ์ผ์„ ํ•  ์ˆ˜ ์žˆ๋ƒ๋ฉด

         myButton.rx
            .tap
            .map{ "text" }
            .bind(to: myButton.rx.customChangeTitle)
            .disposed(by: bag)

์ด๋ ‡๊ฒŒ ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด. ํ•จ์ˆ˜๊ฐ€ ์‚ฌ๋ผ์ ธ์„œ ํ›จ์”ฌ ์ข‹์€ ๊ตฌ์กฐ

 

๐ŸŸ  UITextField+Rx.swift

import Foundation

import RxCocoa
import RxSwift
import UIKit

extension Reactive where Base: UITextField {
   
    public var text: ControlProperty<String?> {
        value
    }
}

ControlProperty๋Š” ๊ฐ’์„ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—

textField.rx.text.onNext("Hello") // ๊ฐ’์„ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—
textField.rx.text.subcribe(onNext: { _ in }) // ๊ฐ’์„ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—

 

 

โœ… Binder์˜ ์›ํ˜•์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด์ž.

Binder

 

extension์œผ๋กœ Binder๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” target์„ ๋ฐ›์•„์•ผ ํ•œ๋‹ค.

๊ทธ๋ž˜์„œ ์•„๊นŒ Button์—์„œ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ๊ฒƒ๋„ ์ด์™€ ๊ฐ™์€ ์ด์œ ์—์„œ์ด๋‹ค.

 

 

Comments