Action icon indicating copy to clipboard operation
Action copied to clipboard

How to Action bright CocoaAction

Open liyanhuadev opened this issue 9 years ago • 10 comments

hi, thank you for you library. i have a question: let loadAction: Action<Void, String>

observer result: loadAction.elements.subscribeNext { (result) in // do something } and i can use rx_action btn.rx_action = viewModel.loadAction.toCocoaAction()

What I want to do toCocoaAction

liyanhuadev avatar Aug 11 '16 07:08 liyanhuadev

Neat idea! What do you think, @alexvbush?

ashfurrow avatar Aug 11 '16 15:08 ashfurrow

I like the idea! As far as I recall CocoaAction's signature is Action<Void, Void> ... We need to figure out how to convert to that (I believe we can use that mapping trick you used Ash). I'll get back online tonight and look at it again On Thu, Aug 11, 2016 at 8:07 AM Ash Furrow [email protected] wrote:

Neat idea! What do you think, @alexvbush https://github.com/alexvbush?

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/RxSwiftCommunity/Action/issues/40#issuecomment-239190159, or mute the thread https://github.com/notifications/unsubscribe-auth/AAS_JbhELJp52F5Cov8AQbF-IGp6moBSks5qezq3gaJpZM4Jh4Pd .

alexvbush avatar Aug 11 '16 16:08 alexvbush

@ashfurrow did you create CocoaAction as a typealias to Action<Void, Void> because that was the only way to use it in public var rx_action: CocoaAction? uibutton extension?

At first I thought - why do we even need CocoaAction if we could just use Action<Input, Element> where Input and Element are generics. But it seems like we can't do something like this in Swift:

public extension UIButton<Input, Element> {
....
   public var rx_action: Action<Input, Element>? {
        .....
   }

}

the compiler complains with cannot specify non-generic type UIButton....

Also I found that there is a proposal for generic typealias for Swift 3 https://github.com/apple/swift-evolution/blob/master/proposals/0048-generic-typealias.md Looks cool and will be useful if it will be included.

If I'm correct that we can't have generics in UIButton extension than I think our best bet is to do something like what you did here https://github.com/RxSwiftCommunity/Action/issues/26 in proposed toCocoaAction method.

What do you think?

alexvbush avatar Aug 12 '16 03:08 alexvbush

hey, i found a way, in ReactiveCocoa https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/ReactiveCocoa/Swift/ObjectiveCBridging.swift

public protocol ActionProtocol {

associatedtype Input

  associatedtype Element
    var action: Action<Input, Element> { get }
}
extension Action: ActionProtocol {

    public var action: Action<Input, Element> {
        return self
    }
}
public extension ActionProtocol where Input == Void {

    public func toCocoaAction() -> CocoaAction {

        let voidAction = Action<Void, Void> { _ in
            return Observable.create({ (observer) -> Disposable in
                let dispose = self.action.execute(Void()).subscribe({ (event) in
                    switch event {
                    case .Next(_):
                        observer.onNext(Void())
                    case .Completed:
                        observer.onCompleted()
                    case .Error(let error):
                        observer.onError(error)
                    }
                })
                return dispose
            })
        }

        return voidAction
    }
}

So, i can use like this:

let requestAction = Action<Void, String> { () -> Observable<String> in
            return Observable.just("request data") // mock
        }

        button.rx_action = requestAction.toCocoaAction()


        requestAction.elements.subscribeNext { (result) in
            print(result)
        }

thank you for your help.

liyanhuadev avatar Aug 12 '16 04:08 liyanhuadev

Looks great! That's exactly the reasoning behind the decision. What parts of your code do you think should be added to this codebase?

ashfurrow avatar Aug 13 '16 14:08 ashfurrow

Spent some time looking into this the other day. It's so unfortunate that we can't have generics in protocols and extensions and have to do something like @liyanhuadev did...

alexvbush avatar Aug 17 '16 16:08 alexvbush

Hi, is there anything new on this? I really enjoy using Action, but I would like a button to be able to hold an action that produces elements. But I cannot find a way to implement a toCocoaAction, or make the UIButton hold anything but a CocoaAction. How do you get around this? in the mean time I had to do

CocoaAction { _ in
                    self?.vm.onCreateAccountTap.execute()
                    return .just()
                }

yoavschwartz avatar Sep 05 '17 12:09 yoavschwartz

Hi @yoavschwartz – I don't think there's been any progress but someone should try again using Swift 4? Anyone available?

ashfurrow avatar Sep 05 '17 18:09 ashfurrow

After talking to @fpillet, for future reference this is the best solution I came to, if anyone is facing the same problem

extension Reactive where Base: UIButton {
    func bindAction<Output>(_ action: Action<Void,Output>) {
        var button = base
        let cocoaAction = CocoaAction {
            action.execute()
            return .just()
        }
        button.rx.action = cocoaAction
    }
}

yoavschwartz avatar Sep 05 '17 19:09 yoavschwartz

extension Action where Input == Void {
    func asCocoaAction() -> CocoaAction {
        return CocoaAction { [weak self] _ in
            return self?.execute(()).map { _ in Void() } ?? .empty()
        }
    }
}

adamsmaka avatar Sep 19 '17 05:09 adamsmaka