rxswiftcommunity / action Goto Github PK
View Code? Open in Web Editor NEWAbstracts actions to be performed in RxSwift.
License: MIT License
Abstracts actions to be performed in RxSwift.
License: MIT License
just
-> Observable.just
Variable
is no longer a direct ObservableType
empty()
-> Observable.empty
MainScheduler.sharedInstance
-> MainScheduler.instance
create
-> Observable.create
combineLatest
-> Observable.combineLatest
lookupControlEvent = self.rx_primaryAction
should be changed to
lookupControlEvent = self.rx.primaryAction
Hello. Thanks for this great library.
I am having problem building master branch with RxSwift 4.0.0-rc.0
. Here is a very simple project reproducing my problem
https://github.com/orakaro/Test-Swift4
Build and run with iPhone 8 simulator gave me following error:
dyld: lazy symbol binding failed: Symbol not found: __T07RxSwift14ObservableTypePAAE5shareAA0C0Cy1EQzGyF
Referenced from: /Users/orakaro/Library/Developer/CoreSimulator/Devices/A7E83BA1-576E-4E5F-B1AF-19F9EB0FAE0F/data/Containers/Bundle/Application/DCB0E2FE-6D99-4CE1-974A-1F2D5985D419/Test-Swift4.app/Frameworks/Action.framework/Action
Expected in: /Users/orakaro/Library/Developer/CoreSimulator/Devices/A7E83BA1-576E-4E5F-B1AF-19F9EB0FAE0F/data/Containers/Bundle/Application/DCB0E2FE-6D99-4CE1-974A-1F2D5985D419/Test-Swift4.app/Frameworks/RxSwift.framework/RxSwift
dyld: Symbol not found: __T07RxSwift14ObservableTypePAAE5shareAA0C0Cy1EQzGyF
Referenced from: /Users/orakaro/Library/Developer/CoreSimulator/Devices/A7E83BA1-576E-4E5F-B1AF-19F9EB0FAE0F/data/Containers/Bundle/Application/DCB0E2FE-6D99-4CE1-974A-1F2D5985D419/Test-Swift4.app/Frameworks/Action.framework/Action
Expected in: /Users/orakaro/Library/Developer/CoreSimulator/Devices/A7E83BA1-576E-4E5F-B1AF-19F9EB0FAE0F/data/Containers/Bundle/Application/DCB0E2FE-6D99-4CE1-974A-1F2D5985D419/Test-Swift4.app/Frameworks/RxSwift.framework/RxSwift
Questions like this one are pretty common and demonstrate incomplete documentation and examples.
init
method should be generalised to allow work factories returning PrimitiveSequence
or other ObservableConvertibleType
func save(_ message: String) -> Completable {
// something that either completes successfully or fail with an error
}
let saveAction: Action<Void, Never> = Action { save($0) }
First failure here: https://travis-ci.org/RxSwiftCommunity/Action/builds/220553535
/Users/travis/build/RxSwiftCommunity/Action/Sources/Action/Action.swift:99:14: error: value of type 'Observable' has no member 'bindTo'
Looks like RxSwift might not be adhering to semver? Help would be welcome here ๐
I have a hard time to dispose an observable produced by the action's workFactory. It seems that Observable
returned by execute is not the same as Observable
returned by work factory. Disposing it does not dispose an internal observer and does not reset enabled. What is the recommended way to programmatically stop execution of an observable that was created by workFactory and currently being executed by Action?
Here is my ugly test code:
import RxSwift
import Action
import UIKit
class ViewController: UIViewController {
let action = Action<Void, Int> { _ in Observable<Int>.interval(1, scheduler: MainScheduler.instance) }
var actionDisposable = Disposable?.none
@IBAction func initiateAction() {
actionDisposable = action.execute().bind(onNext: { print("\($0)") })
}
@IBAction func stopAction() {
actionDisposable?.dispose()
}
}
It does stop printing, but it does not re-enable action, as well as does not stop timer.
Action
can do only one action at the same time. This works very nice.
However, it can not be used in scenes like incremental search.
Like this.
let searchText = Variable<String>("")
let action = Action<Input, Result> { input in
return networkRequest()
}
searchText.asObservable()
.throttle(0.5, scheduler: MainScheduler.instance)
.distinctUntilChanged()
.bind(to: action.inputs)
.disposed(by: disposeBag)
Even if it is input during the request, a notEnabled error will flow.
To do this I wrote an LatestAction
using flatMapLatest
https://gist.github.com/Econa77/a1bb84d386a40017ba52d0602113b439
Can this LatestAction
be included in the Action.framework
? What do you think?
I have updated to 2.1.0 recently and im experiencing that some actions not enabled by default.
This means i immediately get an error notEnabled
, but the work factory seems to execute. Theres never a call back to my subscription on elements.
I looked around in the recent changes and this seems peculiar:
public init(
enabledIf: Observable<Bool> = Observable.just(true),
workFactory: @escaping WorkFactory) {
self._enabledIf = enabledIf
self.workFactory = workFactory
let enabledSubject = BehaviorSubject<Bool>(value: false)
enabled = enabledSubject.asObservable()
I'm not 100% sure whats going on, but it seems to me _enabledIf
defaults true and enabled
defaults to false
?
Thanks for putting the effort into this ๐.
I see that currently Changelog.md is used to track changes. Since tags are also being used, could the same data be put into the releases tab? That way, it would make it easy for users to know where to go to without looking for the changelog file. Similar to RxSwift
I cannpt add Action to my project using Carthage
I'm getting
dyld: Library not loaded: @rpath/RxBlocking.framework/RxBlocking
Referenced from: ...app/Frameworks/Action.framework/Action
Reason: image not found
at runtime and obviously RxBlocking is Test library
NOTE: adding RxBlocking fixed runtime issue but I cannot push the binary to itunesconnect
The current implementation of Action
doesn't allow you to receive the Swift.Error
when .execution
is called. But we get an ActionError
type which is not really useful because you always have to switch within it to the underlyingError
.
I think it would be nice for the framework to have something like var underlyingErrors: Observable<Swift.Error>
which will only emit when .execution
actually has an error
The current version of Action
reads s.version = "3.3.0-alpha.1
A clear strategy on how to better do the versioning of Action
if I may suggest we could follow the RxSwift
versioning since we are depending on it as our main dependency framework
It's <Void, Void>
right now, but it would be awesome to somehow feed input into it. The problem is we can't define a property using generics on a non-generic type. I haven't given this a tonne of thought, so there might be an obvious solution.
Hi @ashfurrow, thanks for doing all this great work! Trying to use Action
in my current project and have gotten into a bit of a jam - I have a download button that will pull several files from our backend and I am creating a CocoaAction
for it. But I don't know how I can pull progress from the underlying Observable
that actually does the work (I have a Observable<Int>
that emits progress events, each event is one percent of overall progress upto 100% when it sends onComplete
). Seems like CocoaAction
's signature is Action<Void, Void>
which means it takes no argument (makes sense because a button calls it) and it emits no values in its elements
Observable
(I've used your trick from here to map to Void
).
I'm sure I'm missing something trivial but how can I observe my download progress and get a notification when the whole process/action is done (onComplete)?
Thanks in advance!
Hey,
Thanks for the library! I think I'm starting to understand it. I was using rx_tap on a button but have since switched to trying CocoaAction for the enabling/disabling functionality.
Can you just quickly sense check a few of my understandings? I have the following block of code that is just an Action. When it's invoked, it completes after a 4.5 sec delay.
let newAction = CocoaAction {
let requestObservable: Observable<Bool> = Observable.create { (observer) -> Disposable in
//Pretend we're doing a network request
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(4.5 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
observer.onNext(true)
observer.on(.Completed)
}
return AnonymousDisposable{}
}
return requestObservable.flatMap{_ in
// Pretend I do something useful with my result from the first Observable.
// Now CocoaAction is expecting a Observable<Void,Void> return value so I...
return Observable.empty()
}
}
requestObservable
. I have to return an Observable<Void, Void>
.rx_action
is expecting an Observable
so it can use.bindTo(self.x_enabled)
etc.Does that sound about right?
Waiting on ReactiveX/RxSwift#276
RxCocoa (~> 3.4.0)
required byAction (3.1.0)
when trying to update to RxSwift 3.5
Can we replace this requirement with ~> 3.4
?
See #9, too.
And Moya/Moya#332
The move to Swift 4 works because I applied just the minimal fixes needed for Quick to run in the case of Action. But playing with Quick revealed that there are many more tasks to complete to bring it up to part with Swift 4.
I think it would be a good idea to drop the Quick/Nimble dependencies for testing, and only rely on RxSwift and RxCocoa which are the true one dependencies this frameworks depends on.
While the library API is pretty stable, some fixes and refactoring introduced some breaking changes to its behavior (e.g. removing replay from elements
). Also, while the overall usage is well documented with examples, this might not be the case for how exposed properties are behaving.
It is required to provide a documentation for how public API properties should behave along with corresponding unit tests to reflect this behavior to avoid any regressions during future refactoring. Candidate members include;
elements
inputs
errors
executing
func execute(_:)
It'd be great if this repo included an Xcode project file, both to facilitate use with carthage and simply to build the micro framework without Cocoapods. I'll see if I can take a stab at it sometime soon.
Currently Action
might be exposing more properties than needed. Optimally, it should look something like
Action<Input, Element>
+----------------------------------------------+
| enabledIf: Observable<Bool>, |
inputs ------->| workFactory: (Input) -> Observable<Elemenet> |------> elements
(AnyObserver<Input>) | | (Observable<Element>)
+------------------------------+---------------+
|
|
|
+------> errors: Observable<Error>
|
+------> isExecuting: Observable<Bool>
|
+------> isEnabled: Observable<Bool>
Thus, following changes to be applied;
enabled
, should be renamed to isEnabled
in conformance with Swift API design guidelines.executing
, should be renamed to isExecuting
in conformance with Swift API design guidelines_enabledIf
to be declared as private
workFactory
to be declared as private
inputs
type to be changed to an ObserverType<Input>
.Some questions open for discussion;
executionObservables
remain public
?errors
be Observable<ActionError>
or Observable<Swift.Error>
? (may be related to #119 )inputs
be AnyObserver<Input>
or Binder<Input>
?InputSubject
?Hi.
I have accidentally googled this issue in RxSwift: ReactiveX/RxSwift#573
and decided to check CocoaActions.
class ReleaseMe {
var name: String
init(name: String) {
self.name = name
}
deinit {
print("deinit for \(name)")
}
}
func request() -> Observable<Void> {
let captured = ReleaseMe(name: "captured")
return Observable.just(ReleaseMe(name: "just"))
.map {_ in
captured.name
}
.map(void)
}
private func bindModel() {
loginButton.rx_action = CocoaAction() {[unowned self] in
return self.request()
}
}
ReleaseMe objects are not freed when i tap the button.
I managed to make it work only after i got rid of ReplaySubject and addDisposableTo in Action class, but i guess it is not an option :)
#51 changed how we access the extension property on UIKit elements, we need to update the readme to match.
I'm new to Rx, and I've just started looking at Actions too. This question may sound silly, so please bear with me.
I have a screen with a text field and a button to submit the form.
What I would like to do is bind the button to an Action while passing the text field text observable as input to the action. How can I do this?
What I would like to do is something like this:
button.rx.bind(to: viewModel.action, input: textField.rx.text)
Or, if I have two text fields:
button.rx.bind(to: viewModel.action, input: Observable.combineLatest(textField1.rx.text, textField2.rx.text))
Is this possible? Does this even make sense to you guys?
I know that I can pass input using another way (see below), but I would like to avoid capturing self if possible. And also, the code above seems more reactive to me.
button.rx.bind(to: viewModel.action) { _ in return self.textField.text }
Thoughts?
Hey ,guys ,Thanks for your working, There is a problem when I used this library, there is a Controller that can edit some info, also have a button to commit the change, I want button bind an action with it. But CocoaAction is an <Void, Void> signature, I tried to bindInput with Action, but if I want to bindTo button , there will be an input when binding. That`s not good, So can you help me out?
I see that this pull request should fix the RxSwift dependency issue, but it seems like this has not been released to cocoapods.
If you check the .podspec
on their end, it still contains the old dependencies.
Did 2.1.1's podspec get published? I'm still seeing 2.1.0 as the latest in cocoapods.
Action
can do only one action at the same time. This works very nice.
However, it can not be used in scenes like incremental search.
Like this.
let searchText = Variable<String>("")
let action = Action<Input, Result> { input in
return networkRequest()
}
searchText.asObservable()
.throttle(0.5, scheduler: MainScheduler.instance)
.distinctUntilChanged()
.bind(to: action.inputs)
.disposed(by: disposeBag)
Even if it is input during the request, a notEnabled error will flow.
To do this I wrote an LatestAction
using flatMapLatest
https://gist.github.com/Econa77/a1bb84d386a40017ba52d0602113b439
Can this LatestAction
be included in the Action.framework
? What do you think?
Travis builds are taking hours just to queue, we need to switch to Circle to get faster feedback. I'll get to this eventually, if someone else wants to take it on, by all means ๐
I should have some time this weekend to finalize a release of the changes that were merged yesterday; is there anything else we want to get in before that goes out? If so, I can try to tackle it, otherwise I'm going to touch up the Readme and give the docs a once-over and open a PR with that to get started.
@kzaher has a great idea for building this by composing existing functionality, which sounds ๐ฏ
I'm not sure if I have time to do it right now, since I just want to get my project compiling again ๐ฌ But I think the external API we have now is well-defined and we should definitely implement his suggested approach as soon as possible.
How do you make an action failable?
I would like to do something like this:
class SomeClass {
var cancelAction: CocoaAction
init() {
cancelAction = CocoaAction {
if someBooleanExpression {
return failWith(CancelError.UnsavedChanges)
}
return just()
}
}
}
but the compiler throws up and says:
Variable 'self.cancelAction' used before being initialized
Which apparently has something to do with the if
statement in an initializer.
I can't find any examples on doing this, so how would you go around and implement this correctly?
While there is no guarantees for thread-safety on Action
. CocoaAction
exposed public API should guarantee delivering events on main thread to ensure safe binding to UI.
I could be misunderstanding this, but my thinking is that subscription closures passed into Action.execute().subscribe()
should receive values, errors, etc from that particular invocation of execute()
. I noticed I was never getting called back in the onCompleted
closure, and found that I always receive a ActionError.notEnabled
. This happens even when I create my Action with an explicit enabledIf: Observable.just(true)
.
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
This is probably a quick fix, but I'm not certain how we'd want to version it, nor am I terribly familiar with Carthage. tl;dr bindTo()
-> bind(to:)
If error or completed flows in PublishSubject of inputs, further action can not be fired.
https://github.com/RxSwiftCommunity/Action/blob/master/Sources/Action/Action.swift#L30
How do you think inputs should receive onNext only?
I think ReactorKit's ActionSubject is a good example.
https://github.com/ReactorKit/ReactorKit/blob/master/Sources/ActionSubject.swift
If you accept the feature request I will create a PR.
It looks like the 1.0.0 tag was not correctly set to the podspec bump. I'm not sure what the policy is here with force pushes or whether this warrants one but I thought I should bring it up ๐
Hi guys,
thanks for this great library, lack of actions was preventing me to move from RAC to RX :)
I've bootstrapped a project with RxSwift and Action, cocoapods chose RxSwift 3.1 which should be compatible with the latest version of Action.
It seems that the "executing" state of the Action doesn't get properly updated when the Observable returned is created with .just()
and execute()
d with parameters.
Seems that this block of code
let executionStart = executionObservables
let executionEnd = executionObservables
.flatMap { observable -> Observable<Void> in
return observable
.flatMap { _ in Observable<Void>.empty() }
.concat(Observable.just())
.catchErrorJustReturn()
}
executing = Observable
.of(executionStart.map { _ in true }, executionEnd.map { _ in false })
.merge()
.startWith(false)
is not respecting the expected "order" of executionStart and executionEnd, and the true
of the executingStart
observable is being sent AFTER the executingEnd
's false
This is currently preventing me from using the same action more than once in my project (the secondo time I execute the action, it's still disabled because of wrong value sent by the executing observable).
I've also checked the tests:
context("trigger via execute() method")
is failing twice in your test suite, (line 138 and 297 of ActionTest.swift) with something like this
XCTAssertEqual failed: ("[next(false) @ 0, next(false) @ 10, next(true) @ 10, next(false) @ 20, next(true) @ 20]") is not equal to ("[next(false) @ 0, next(true) @ 10, next(false) @ 10, next(true) @ 20, next(false) @ 20]")
As you can see, we have false(10) BEFORE true(10). I would expect (and so do the tests) to see true(10) (executing) and then false(10) (finished executing).
I have a good experience with ReactiveCocoa/ReactiveSwift but I'm quite unexperienced with RxSwift (although they're seem almost identical to me). I don't know what clever trick could allow us to sort this out, I've tried with a delay of 0.0 seconds on the executionEnd observable, it seems to works for my purposes (== in my project) but is breaking almost ALL the tests XD
Thanks
How are we doing on Swift 3.0? Is somebody already working on a branch, or?
Can't install RxSwift
and RxCocoa
alphas since Action
requires 2.x
.
Can we please get the podspec pushed to the main specs repo? Looks like this got lost in the update shuffle again.
I created a new tag for Carthage. Please update the podspec as well.
Hi,
Is this project last repo already extensively tested and passing tests with swift4 ?
I am getting EXC_BAD_ACCESS called at Action:100 :
Observable .combineLatest(executing, enabledIf) { !$0 && $1 } .bind(to: enabledSubject) .disposed(by: disposeBag)
in .bind(to...)
at: override func subscribe<O : ObserverType>(_ observer: O) -> Disposable where O.E == Element { if !CurrentThreadScheduler.isScheduleRequired { // The returned disposable needs to release all references once it was disposed. let disposer = SinkDisposer() let sinkAndSubscription = run(observer, cancel: disposer) disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink, subscription: sinkAndSubscription.subscription)
in disposer.setSink...
Thats my only problem using RxSwift and not sure where is the problem.
I'm excluding UIButton from tvos but I shouldn't need to โ just a difference between rx_tap
and rx_primaryAction
.
See: RxSwiftCommunity/contributors#4
Copy steps from: RxSwiftCommunity/NSObject-Rx#3 :
It should actually, like, explain how to use the library.
workFactory
.enabledIf
.CocoaAction
is.UIButton
extension works.Hi,
I went back on a project on which I didn't work recently. Then I realised that my Actions were not executed anymore. I updated to Action 2.2.1 after seeing that some fix were added after other issues but it's still not working.
Here is the function I am trying to execute :
func presentSetNewPasswordViewController(_ presentingViewController: UIViewController) -> CocoaAction {
return CocoaAction { _ in
return Observable.create { observer -> Disposable in
let navVC = self.instantiateEmbedSetNewPasswordViewController()
navVC.modalPresentationStyle = UIModalPresentationStyle.formSheet
presentingViewController.present(navVC, animated: true) {
observer.onCompleted()
}
return Disposables.create()
}
}
}
And I execute it like this:
authenticationWireframe.presentSetNewPasswordViewController(window.rootViewController!).execute()
Am I doing something wrong here? Because this is definitely working on the prod app.
Thanks.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.