Reactivecocoa: '์•ก์…˜'์— ๋Œ€ํ•œ ์ œ์–ด ๋ฐ”์ธ๋”ฉ์ž…๋‹ˆ๋‹ค.

์— ๋งŒ๋“  2016๋…„ 10์›” 04์ผ  ยท  22์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: ReactiveCocoa/ReactiveCocoa

๋ช…๋ น ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋Š” ๋‘ ๊ฐ€์ง€ API๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. @sharplet์ด ๋งํ–ˆ๋“ฏ์ด button.rac_command ์™€ ๊ฐ™์ด ReactiveObjC์—์„œ ๊ฐ€์ ธ์˜จ ๊ฒƒ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

extension Reactive where Host: UIButton {
    public var pressed: MutableProperty<CocoaAction> { ... }
}

extension Reactive where Host: UIBarButtonItem {
    public var pressed: MutableProperty<CocoaAction> { ... }
}

๊ฐ•๋ ฅํ•œ ์ฐธ์กฐ์™€ ํ•จ๊ป˜ Action ๋ฅผ ์†Œ์œ ํ•œ ๋ทฐ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์€ ์ž˜๋ชป๋œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. Action ( CocoaAction ๋ฅผ ํ†ตํ•ด ๊ฐ„์ ‘์ ์œผ๋กœ)์˜ ์†Œ์œ ๊ถŒ์€ ์›๋ž˜ ๋ ˆ์ด์–ด(VC ๋˜๋Š” VM)์— ๋‚จ๊ฒจ์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ @liscio ๋ฐ @sharplet ๊ณผ์˜ ์˜ค๋žœ ํ† ๋ก  ํ›„์— UIControl ๋ฐ NSControl ์™€ ์—ฐ๊ฒฐํ•˜๋Š” UIControl Action ์šฉ์œผ๋กœ ํŠน๋ณ„ํžˆ ์ œ์ž‘๋œ ์ƒˆ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ๋…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

extension Reactive where Base: UIControl {
    /// Create a trigger signal for a specific set of control events.
    public func trigger(for controlEvents: UIControlEvents) -> Signal<(), NoError>

    /// The action is weakly referenced internally.
    public func setAction<Input, Output, Error>(_ action: Action<Input, Output, Error>, for controlEvents: UIControlEvents, inputTransform: (Self, UIControlEvents) -> Input)

    public func removeAction()

    /// ... some convenience overloads of `setAction(_:for:inputTransform:)`.
}

์ด API๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด UIControl ๋ฐ NSControl ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ๋ชจ๋“  Action ๋ฐ”์ธ๋”ฉ ๋Œ€์ƒ์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. API๊ฐ€ ๋ชจ๋‘ ํฌํ•จํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋” ํฐ ์˜๋ฏธ์—์„œ ์šฐ๋ฆฌ๋Š” @IBAction ๋ฐ @IBOutlet ๋’ค์— ์žˆ๋Š” ๋ชฉํ‘œ ํ–‰๋™ ํŒจํ„ด์„ ๋ชจ๋ฐฉํ•ฉ๋‹ˆ๋‹ค.

Interface Builder์—์„œ UIButton์˜ _Sent Action_์„ UIViewController์˜ _Received Action_( @IBAction ๋ฉ”์„œ๋“œ)์— ๋ฐ”์ธ๋”ฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ UIButton์€ ์•ฝํ•œ ์ฐธ์กฐ ๋Œ€์ƒ์— ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋ƒ…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ์˜ ๊ฒฝ์šฐ ์ปจํŠธ๋กค์— ์ด๋ฒคํŠธ ์‹ ํ˜ธ ์ปฌ๋ ‰์…˜์„ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. Action ๋ฅผ ๋ฐ”์ธ๋”ฉ ๋Œ€์ƒ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด Action ๊ฐ€ @IBAction ์™€ ๋น„์Šทํ•œ ์—ญํ• ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

// Received Action <~ Sent Action
commitAction <~ confirmButton.touchUpInside

// The reverse `isEnabled` binding is now explicit & optional.
confirmButton.isEnabled <~ commitAction.isEnabled

// OR

confirmButton.setAction(commitAction, for: .touchUpInside)

์˜ ๋“ฑ๊ฐ€๋ฌผ

confirmButton.rac_pressed.value = CocoaAction(commitAction)

๊ทธ๋Ÿฌ๋‚˜ weak-to-weak ๋ฐ”์ธ๋”ฉ ์˜๋ฏธ๋ก ์„ ํ†ตํ•ด ๋ถ„๋ฆฌ๋œ ์†Œ์œ ๊ถŒ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

enhancement

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

๊ทธ๋Ÿฌ๋ฉด ์ˆจ๊ธธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•˜๊ฒŒ ์œ ์ง€ํ•˜์„ธ์š”.

๋ชจ๋“  22 ๋Œ“๊ธ€

๋™๋“ฑํ•œ ๊ธฐ๋Šฅ์„ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ๋„ ํ•„์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์žŠ์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

confirmButton.rac.isEnabled <~ commitAction.isEnabled

ํ , ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ๊ฐ„๊ณผํ–ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด Action ๋กœ ์˜ฌ์ธํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

@andersio ๊ทธ๊ฒŒ ๋ฌด์Šจ ๋ง์ธ์ง€, ์™œ ์ด ๋ฌธ์ œ๊ฐ€ ์ข…๋ฃŒ๋˜์—ˆ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

@sharplet์ด ์ œ๊ธฐํ•˜๋Š” isEnabled ์ž…๋ ฅ์œผ๋กœ ๊ฐ’ ์ „ํŒŒ๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ทธ ์‚ฌ์‹ค์„ ํŽธ๋ฆฌํ•œ ๋ฐฉ๋ฒ•/ํŒจํ„ด์— ์ˆจ๊ธฐ๋Š” ๊ฒƒ์€ ์ œ ์ƒ๊ฐ์— ์šฐ๋ฆฌ์—๊ฒŒ ๊ทธ๋‹ค์ง€ ๋„์›€์ด ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

https://github.com/ReactiveCocoa/ReactiveCocoa/pull/3210/commits/f983a746f915a9a517e9e076c19581724075c562 ์—์„œ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค

๊ฐ•ํ•œ ์ฐธ์กฐ์™€ ํ•จ๊ป˜ ์•ก์…˜์„ ์†Œ์œ ํ•˜๋Š” ๋ทฐ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์€ ์ž˜๋ชป๋œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ž‘์—…์˜ ์†Œ์œ ๊ถŒ(CocoaAction์„ ํ†ตํ•ด ๊ฐ„์ ‘์ ์œผ๋กœ)์€ ์›๋ž˜ ๋ ˆ์ด์–ด(VC ๋˜๋Š” VM)์— ๋‚จ๊ฒจ๋‘์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋™์˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์•„์š”. ๊ทธ๊ฒŒ ์™œ ๋‹น์‹ ์—๊ฒŒ ์ž˜๋ชป ๋Š๊ปด์ง€๋‚˜์š”?

์•ฝํ•œ ์ฐธ์กฐ๋Š” ์ œ์•ˆ๋œ API์˜ ์ž‘์€ ๋น„ํŠธ๋กœ, ๋ช…๋ น ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  ์ปจํŠธ๋กค์„ ํฌํ•จํ•˜๋Š” ๋‹จ์ผ ์„ธํŠธ์˜ UIControl Action ํ•ฉ๋‹ˆ๋‹ค.

Rex์—์„œ๋Š” ํŠน์ • ๊ตฌํ˜„์ด ํฌํ•จ๋œ UIButton ์ „์šฉ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

Action AFAIK๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋ช…๋ น์„ ๋‚˜ํƒ€๋‚ด๊ณ  ๋ทฐ ๋ชจ๋ธ์ด ์†Œ์œ ํ•˜๋ฉฐ ํ•ด๋‹น ์ƒํƒœ์— ๋Œ€ํ•œ ๋‚ด๋ถ€ ๋ฐ ์™ธ๋ถ€ ์ข…์†์„ฑ์„ ๋ชจ๋‘ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Cocoa target-action ํŒจํ„ด๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ช…๋ฐฑํ•œ ์†Œ์œ ์ž๊ฐ€ ์žˆ์„ ๋•Œ ๊ฐ•๋ ฅํ•œ ์ฐธ์กฐ๊ฐ€ ๋˜์–ด์•ผ ํ•˜๋Š” ์ด์œ ๋ฅผ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐ•๋ ฅํ•œ ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Rex API๋Š” CocoaAction ์ž‘๋™ ๋ฐฉ์‹์˜ ์ธ๊ณต๋ฌผ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์œผ๋ฉฐ, ๊ฐ’์ด ๋ž˜ํ•‘๋œ Action ์ „ํŒŒ๋  ์ˆ˜ ์žˆ๋„๋ก ์œ ์ง€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ์ œ์•ˆ๋œ API๋Š” ๋Œ€์‹  Action ์ง์ ‘ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋ ‰์Šค 0.12:

extension UIButton {
    public var rex_pressed: MutableProperty<CocoaAction> { get }

    // This one would become `BindingTarget`. Irrelevant to this issue.
    public var rex_title: MutableProperty<String> { get }
}

์ œ์•ˆ๋จ(๋ชจ๋“  UIControl ):

extension Reactive where Base: UIControl {
    /// The action is weakly referenced internally.
    public func setAction<Input, Output, Error>(
        _ action: Action<Input, Output, Error>,
        for controlEvents: UIControlEvents,
        inputTransform: (Self, UIControlEvents) -> Input
    )

    public func removeAction()

    /// ... some convenience overloads of `setAction(_:for:inputTransform:)`.
}

์ผ๋ฐ˜์ ์œผ๋กœ ์šฐ๋ฆฌ๋Š” ์„ธ ๊ฐ€์ง€ UI ์ƒํƒœ ํด๋ž˜์Šค์™€ Action ๋ช…๋ น ํŒจํ„ด์„ ์œ„ํ•œ ํด๋ž˜์Šค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ๊ด€์ฐฐํ•  ์ˆ˜๋‹จ์ด๋‚˜ ๊ฐ’์ด ์—†๋Š” ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ํ‚ค์ž…๋‹ˆ๋‹ค.
    ์˜ˆ: UIControl.isEnabled , UILabel.text , UIView.isHidden .

BindingTarget s๋กœ ๋ชจ๋ธ๋งํ•ฉ๋‹ˆ๋‹ค.

  1. ์ด๋ฒคํŠธ ๋ฐ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์•Œ๋ฆผ์„ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค.
    ์˜ˆ: UIControl.trigger(for: .valueChanged) , UITableViewCell.trigger(for: #selector(prepareForReuse))

Signal s๋กœ ๋ชจ๋ธ๋งํ•ฉ๋‹ˆ๋‹ค.

  1. ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ํ‚ค + ์‚ฌ์šฉ์ž ์ƒํ˜ธ ์ž‘์šฉ ์‹œ ๊ฒŒ์‹œ๋˜๋Š” ํ•ด๋‹น ์ œ์–ด ์ด๋ฒคํŠธ.
    ์˜ˆ: UITextField.text , NSTextField.text , UISwitch.isOn

#3229

  1. [ _ Action ๋ฅผ ์ปจํŠธ๋กค๊ณผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
    (์ด๊ฒƒ์€ [1]๊ณผ [2] ์œ„์— ๋นŒ๋“œ๋œ ํŽธ์˜ ํŒจํ„ด์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.)
    ์˜ˆ: UIButton.rac_command

_์ด ๋ฌธ์ œ. _

@andersio ์ €๋Š” ๋ถˆํ–‰ํžˆ๋„ removeAction() ์ด ์ž‘์—…์„ ์ œ๊ฑฐํ•˜๋ ค๋Š” ์ œ์–ด ์ด๋ฒคํŠธ๋ฅผ ์ง€์ •ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. _๋˜๋Š”_ 1.0์˜ ๊ฒฝ์šฐ ์ด๋ฆ„์„ removeAllActions() ๋ฐ”๊พธ๊ณ  setAction() ๋Š” ์ปจํŠธ๋กค์ด ํ˜„์žฌ ์ด "๊ฐ„ํŽธํ•œ API"๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฐ๊ฒฐ๋˜๋Š” ๋‹จ์ผ ์ž‘์—…๋งŒ ์ฒ˜๋ฆฌํ•จ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์–ด์จŒ๋“  99.9%์˜ ์‚ฌ๋žŒ๋“ค์ด ์ด๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ๋…ผ์Ÿ์˜ ์—ฌ์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ์—ฌ๋Ÿฌ ์ž‘์—…์ด isEnabled ๋™์‹œ์— ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— IMO ์—ฌ๋Ÿฌ ์ž‘์—…์ด ์˜๋ฏธ๊ฐ€ ์—†์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(= ๋‹ค์†Œ ๋ถˆํ™•์‹คํ•จ).

์ฃผ์–ด์ง„ ์ž‘์—…์„ ์ง์ ‘ ์„ค์ •ํ•˜๋Š” (Swift) ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

extension Reactive where Base: UIButton {
    var pressed: CocoaAction {
        get { โ€ฆ }
        set { โ€ฆ }
    } 
}

์•„๋‹ˆ๋ฉด some convenience overloads ์„น์…˜์— ํฌํ•จ๋˜์—ˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ œ๋„ค๋ฆญ API๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๊ดœ์ฐฎ์„ ๊ฒƒ ๊ฐ™์ง€๋งŒ, ํŽธ์˜์„ฑ API๊ฐ€ ๋” ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ์ œ๊ฐ€ ์„ธ์ƒ์— ์ž๋ž‘ํ•˜๊ณ  ์‹ถ์€ API์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒƒ์ด ๋งค์šฐ ์„ค๋“๋ ฅ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

button.reactive.pressed = CocoaAction(viewModel.action)

setAction(โ€ฆ) ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ•œ ์ œ๊ฑฐ๋Š” nil ์ž‘์—…์„ ์„ค์ •ํ•˜์—ฌ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ณ„๋„์˜ API๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์˜์‹ฌํ•  ์—ฌ์ง€ ์—†์ด ์ด๊ฒŒ ๋” ์ข‹์•„ ๋ณด์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ๋“ค์€ ๋ฐ˜๋“œ์‹œ ์ง€์ผœ์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์—ฌ์ „ํžˆ CocoaAction ๊ฐ€ Action ์•ฝํ•œ ์ฐธ์กฐ๋ฅผ ๊ฐ–๋„๋ก ์ œ์•ˆํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

setAction ๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜๊ณ ( 790b3e8 ) pressed ๊ฐ€ ๋‹ค์‹œ ๋Œ์•„์™”์Šต๋‹ˆ๋‹ค( 790b3e8 ).

extension Reactive where Base: UIButton {
    public var pressed: CocoaAction<Base> { get nonmutating set }
}

extension Reactive where Base: UIControl {
    public var action: CocoaAction<Base>? { get }
    public var controlEventsForAction: UIControlEvents? { get }

    /// `CocoaAction` is retained by `self`, but `CocoaAction` weakly references `Action`.
    public func setAction(
        _ action: CocoaAction<Base>?,
        for controlEvents: UIControlEvents
    )
}

API๊ฐ€ ์—ฌ๋Ÿฌ ์ž‘์—…์„ ์ง€์›ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๊ฒƒ์€ ์œ ํšจํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

button.reactive.setAction(action1, for: .touchUpInside)
button.reactive.setAction(action2, for: .touchUpOutside)
// button now has 2 actions set for 2 different events

์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ CocoaAction ์•ฝํ•˜๊ฒŒ ์ฐธ์กฐ Action ?

@mdiep

// button now has 2 actions set for 2 different events

์ด๋Š” button ์˜ ํ™œ์„ฑํ™” ์ƒํƒœ๊ฐ€ action1.isEnabled ๋ฐ action2.isEnabled ๋ชจ๋‘์— ๋ฐ”์ธ๋”ฉ๋จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ํ™œ์„ฑํ™” ์ƒํƒœ๋Š” ์–ด๋–ป๊ฒŒ ๊ฒฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ๋ชจ๋“  Action ์˜ ํ™œ์„ฑํ™” ์ƒํƒœ ์ค‘ AND ?

CocoaAction์ด Action์„ ์•ฝํ•˜๊ฒŒ ์ฐธ์กฐํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๋˜๋Œ๋ ธ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ์ง€๊ธˆ (๊ทธ๋ฆฌ๊ณ  Rex์˜ ์—ญ์‚ฌ ๋™์•ˆ) ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ค์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์ธ์ •ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋Š” ๋ฒ„ํŠผ์˜ ํ™œ์„ฑํ™” ์ƒํƒœ๊ฐ€ action1.isEnabled ๋ฐ action2.isEnabled ๋‘˜ ๋‹ค์— ๋ฐ”์ธ๋”ฉ๋จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ํ™œ์„ฑํ™” ์ƒํƒœ๋Š” ์–ด๋–ป๊ฒŒ ๊ฒฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ๋ชจ๋“  ์ž‘์—…์˜ โ€‹โ€‹ํ™œ์„ฑํ™” ์ƒํƒœ์˜ AND?

๊ทธ๋ฆฌ๊ณ  ๋‚˜์—๊ฒŒ ์˜ณ์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์˜ต์…˜์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. ํ™œ์„ฑํ™”๋ฅผ ์™„์ „ํžˆ ํฌ๊ธฐํ•˜์‹ญ์‹œ์˜ค
  2. AND ๋ชจ๋“  ์ž‘์—…์˜ โ€‹โ€‹ํ™œ์„ฑํ™” ์ƒํƒœ
  3. ๋˜๋Š” ๋ชจ๋“  ์ž‘์—…์˜ โ€‹โ€‹ํ™œ์„ฑํ™” ์ƒํƒœ
  4. ์ •ํ™•ํžˆ 1๊ฐœ์˜ ์ž‘์—…์ด ์žˆ๋Š” ๊ฒฝ์šฐ ํ™œ์„ฑํ™”
  5. .pressed ๋“ฑ์—์„œ ํ™œ์„ฑํ™”ํ•˜๊ณ  setAction(:for:) ์ง์ ‘ ํ™œ์„ฑํ™”ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

(5) ๋‚˜์—๊ฒŒ ๊ฐ€์žฅ ์ข‹์€ ํ•ด๊ฒฐ์ฑ…์ธ ๊ฒƒ ๊ฐ™๋‹ค. ์ผ๋ฐ˜ ์ผ€์ด์Šค๋Š” ์‰ฝ๊ณ  ํŽธ๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋” ๋ณต์žกํ•œ ๊ฒƒ์„ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์—ฌ์ „ํžˆ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

(5) ๋Š” setAction ๊ฐ€ ์—ฌ๋Ÿฌ actionN <~ reactive.trigger(for: .specificEvent) ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ๊ณผ ์ฐจ์ด๊ฐ€ ์—†์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ปจํŠธ๋กค์— ์—ฌ๋Ÿฌ ํŽธ์˜ ๋ช…๋ น ์Šฌ๋กฏ์ด ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉด ์–ด๋–ป๊ฒŒ ๋ฉ๋‹ˆ๊นŒ?

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ ์—์„œ ์—ฌ์ „ํžˆ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

  1. ์ทจ์†Œ๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค
  2. ์ด๋ฒคํŠธ๋‹น ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.
  3. CocoaAction ๋Œ€ํ•œ ์ž…๋ ฅ์œผ๋กœ ์ปจํŠธ๋กค์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๊ฑฐ์˜ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ดœ์ฐฎ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ณ„ํš์ด ๋‘˜ ์ด์ƒ์˜ ์ž‘์—…์„ ์ง€์›ํ•˜๋Š” ๊ฒƒ์ด๋ผ๋ฉด ์ด๋ฆ„์„ addAction ๋ณ€๊ฒฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

propagateEnablingState ์ธ์ˆ˜๋ฅผ setAction ํ•˜๋ฉด isEnabled ์˜ ๋ฒกํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ฒฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. (๊ตฌ์„ฑ ๊ฐ€๋Šฅ? ์˜ˆ: ๋ฐ/๋˜๋Š” ์ •์˜๋˜์ง€ ์•Š์Œ?)

์—ฌ๊ธฐ์—์„œ ๋…ผ์˜๋˜๋Š” "ํŽธ์˜์„ฑ ์†์„ฑ"์—์„œ 1๊ฐœ ์ด์ƒ์˜ ์ž‘์—…์„ ์ง€์›ํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‘˜ ์ด์ƒ์˜ ์ž‘์—…์ด ํ•„์š”ํ•œ ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•ด ๋Œ€์ฒด ์‚ฌ์šฉ๋ฒ•( trigger(for:) ์ž‘์—…์„ ๊ฐœ๋ณ„์ ์œผ๋กœ ํŠธ๋ฆฌ๊ฑฐ)์„ ๋‚จ๊ฒจ๋‘์—ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์šด ๋Œ€์•ˆ(๋‹ค๋ฅธ Signal/BindingTarget ํ•ญ๋ชฉ์˜ ์‚ฌ์šฉ๊ณผ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ์Œ)์„ ๊ฐ์•ˆํ•  ๋•Œ ์ด ๋ฐฉ์‹์œผ๋กœ ๋ฒ„ํŠผ์— ๋‘˜ ์ด์ƒ์˜ ์ž‘์—…์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ํƒ€๋‹นํ•œ ์ด์œ ๋ฅผ ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ "๊ฐ„๋‹จํ•œ API"๋ฅผ ์›ํ•˜๋ฉด ์—ฌ๊ธฐ์™€ ๊ฐ™์ด action ์†์„ฑ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํ™œ์„ฑํ™”๋œ ์ƒํƒœ๋Š” ๋ฒ„ํŠผ์— ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค.

>1 ์ž‘์—…์— ๋ฒ„ํŠผ์„ ์—ฐ๊ฒฐํ•˜๋ ค๋ฉด ๊ฐœ๋ณ„ trigger ๋ฅผ ์‚ฌ์šฉํ•œ ๋‹ค์Œ isEnabled BindingTarget ์— ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ž์‹ ์˜ map ๋ฅผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. BindingTarget . ํ•ฉ๋ฆฌ์ ์œผ๋กœ ๋“ค๋ฆฌ๋‚˜์š”?

๊ธฐ๋ณธ์ ์œผ๋กœ "๊ฐ„๋‹จํ•œ API"๋ฅผ ์›ํ•˜๋ฉด ์—ฌ๊ธฐ์™€ ๊ฐ™์ด action ์†์„ฑ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํ™œ์„ฑํ™”๋œ ์ƒํƒœ๋Š” ๋ฒ„ํŠผ์— ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค.

>1 ์ž‘์—…์— ๋ฒ„ํŠผ์„ ์—ฐ๊ฒฐํ•˜๋ ค๋ฉด ๊ฐœ๋ณ„ ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๊ณ ์œ ํ•œ ๋งต์„ ์—ฐ๊ฒฐํ•˜์—ฌ isEnabled BindingTarget์— ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ํ•ฉ๋ฆฌ์ ์œผ๋กœ ๋“ค๋ฆฌ๋‚˜์š”?

๊ทธ๊ฒƒ์€ ๋‚˜์—๊ฒŒ ํ•ฉ๋ฆฌ์ ์œผ๋กœ ๋“ค๋ฆฐ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด setAction(:for:) ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๊นŒ?

๊ทธ๋Ÿฌ๋ฉด ์ˆจ๊ธธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•˜๊ฒŒ ์œ ์ง€ํ•˜์„ธ์š”.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰