RACCommand compilation failure on swift 1.2 - ios

I have a login button with a RACCommand assigned to it to perform a login request and return me a user object.
I want to handle the errors from the buttons signal errors.
loginButton.rac_command.executionSignals.flatten()
.logAll()
.subscribeNext { (_:AnyObject!) -> Void in
println("Sent next")
}
so i added the doError block before the subscribeNext block but now the code doesn't compile:
loginButton.rac_command.executionSignals.flatten()
.logAll()
.doError { (err:NSError) -> Void in
println(err.description)
}
.subscribeNext { (_:AnyObject!) -> Void in
println("Sent next")
}
Now it comes back with the error:
cannot invoke 'subscribeNext' with an argument list of type '(AnyObject! -> Void)'
Since the signature of doError is :
- (RACSignal *)doError:(void (^)(NSError *error))block;
I'm assuming that its giving me back the same signal that was passed to the doError block so i can subscribeNext to it.
Not sure why this fails to compile at all though.
Any insight to this issue is much appreciated.

Typo is in argument of doError() (and incorrectly identified by compiler): it should be of type (NSError!) -> Void instead of (NSError) -> Void. Modified like this it compiles fine:
loginButton.rac_command.executionSignals.flatten()
.logAll()
.doError { (err:NSError!) -> Void in
println(err.description)
}
.subscribeNext { (_:AnyObject!) -> Void in
println("Sent next")
}
Additional remarks
Errors from RACCommand are caught internally and sent on errors()
signal, so none are sent on executionSignals() signal.
doNext(), doError(), doComplete() methods are to be used for
injecting side effects to the signal. So you typically use them while
creating signal, not when handling its events. You might want to use
subscribeNext(nextBlock:error:completed:) method (or one of its convenience forms) instead.

Related

Sharing Mono with the publish method doesn't work as expected

I have two service calls. The second one accepts a value that the first returns. I need to return the result of the first call only if the second succeeds. The following is my prototype implementation, however, the resulting mono is always empty. Please explain why it doesn't work and how to implement it the proper way.
#Test
public void testPublish() {
callToService1().publish(
mono -> mono.flatMap(resultOfCall1 -> callToService2(resultOfCall1))
.then(mono)
)
.map(Integer::valueOf)
.as(StepVerifier::create)
.expectNext(1)
.verifyComplete();
}
Mono<String> callToService1() {
return Mono.just("1");
}
Mono<Integer> callToService2(String value) {
// parameter that used in a call to service2
return Mono.empty();
}
Not sure why you used publish(Function). Sounds like your requirement would be fulfilled by a simple direct flatMap:
callToService1()
.flatMap(v1 -> callToService2(v1)
.thenReturn(v1)
);
if callToService2 throws or produces an onError, that error will be propagated to the main sequence, terminating it.
(edited below for requirement of emitting value from service1)
otherwise, inside the flatMap the callToService2 is completed then we ignore the result and emit the still in scope v1 value thanks to thenReturn (which also propagates onError if callToService2 emits onError)

Java Reactor inapporiate blocking method inside Mono flatMap method

This part of code inside mono.flatMap(() -> ()) is giving me an error(or warning?) verifyClient.sms(request.phoneNumber(). Error is "Inappropriate blocking method call". I guess SMS call is a blocking call from a third party(TeleSign) sdk.
Error is shown in the picture.
#Override
public Mono<ResponseEntity<SuccessResponse>> postSms(
Mono<SendSmsDetail> sendSmsDetail, ServerWebExchange exchange) {
return sendSmsDetail.doOnNext(this::validate)
.flatMap(request -> {
try {
return Mono.just(verifyClient.sms(request.phoneNumber(),
buildSmsParam(request)));
} catch (Exception e) {
return Mono.error(new RuntimeException("Fail to verify", e));
}
})
.onErrorResume(this::defaultOrderErrorHandler);
}
Screenshot of the error:
Can someone please tell me how to resolve it? Just started using Reactor. By the way, if you notice the screenshot and the actual pasted code has differences on .flatMap(tlr -> tlr.) part. Code currently won't compile due to different return type. I am also trying to make it compile by returning Mono<ResponseEntity<SuccessResponse>>. That's what I am trying to do with the second flatMap. Change "tlr"(TeleSignResponse) to my own "SuccessResponse".
I may need a second post on how to make this compile.

Send object to subscriber of RxSwift Action

I used to use ReactiveCocoa in Objective-C but I've since switched to RxSwift as I found it easier to understand than RAC4. However there's something I used to do in RAC that was useful:
#weakify(self);
[[RACCommand alloc] initWithEnabled:RACObserve(self, valid) signalBlock:^RACSignal *(id input) {
#strongify(self);
return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
//make network call
//send responseObject to subscriber
[subscriber sendNext:responseObject];
[subscriber sendCompleted];
return nil;
}] materialize];
}];
This allowed me to subscribe to the command for it's executing state as well as its execution signals so that I could observe data that is returned from the call.
I'm not sure how to reproduce this with RxSwift Action. I am only able to subscribe to its executing observable:
var loader: NotificationType?
formButton.rx_action!.executing.subscribeNext({ [weak self] (executing) -> Void in
if executing {
loader = self?.showNotification(.Loading, title: self?.viewModel.loaderTitle.value, message: "Please wait".localized, timeout: -1)
}
else {
if let loader = loader {
loader.dismiss()
}
}
}).addDisposableTo(disposeBag)
But I then have to create an additional PublishSubject to send my response data:
viewModel.submitSubject.subscribe(onNext: { (response) -> Void in
print(response)
}, onError: { (error) -> Void in
print(error)
}, onCompleted: { () -> Void in
//completed
}) { () -> Void in
}.addDisposableTo(disposeBag)
Is there a way to create a similar pattern in RxSwift with Action?
This is possible with Action but currently it's not straightforward. The problem is that to set an Action property on an object, that object's property must declare the full generic type of Action, which is typically Action<Void, Void> (this is typealias'd to CocoaAction). The two generic types are the input and output, respectively. We chose Void because it represents the fact that work has been done, but doesn't care about what work it is. It's not a perfect solution, since it leads to the problem you're currently facing, and I'm sorry about that.
You want to subscribe to the output of the action's signal, but due to using Void as the output, you can't. The PublishSubject approach you have here is one workaround, another solution would be to use the Void as an output type; you could use errors to indicate failure and Void() to indicate success, but all the work you want to do would need to be encapsulated in the Action's signal. I'd probably use the second approach, but it might not work in all cases.
We have an issue to deal with this but I haven't had time to give it much thought. Any suggestions or resources you have would be awesome 🙇

Synchronous Save in Parse using Swift

Using Swift 2.1 (Xcode 7.2.) and Parse 1.12.0, I'm getting an error that PFObject.save() is unavailable in Swift. My code is:
let operation = NSBlockOperation { () -> Void in
do {
let success = try rating.save()
}
catch let er as NSError {
error = er
}
}
In PFObject+Synchronous.h, there is this:
///--------------------------------------
#pragma mark - Saving Objects
///--------------------------------------
/**
*Synchronously* saves the `PFObject`.
#return Returns whether the save succeeded.
*/
- (BOOL)save PF_SWIFT_UNAVAILABLE;
/**
*Synchronously* saves the `PFObject` and sets an error if it occurs.
#param error Pointer to an `NSError` that will be set if necessary.
#return Returns whether the save succeeded.
*/
- (BOOL)save:(NSError **)error;
So it seems as if Xcode can't tell which function to use: it should try to use the one that handles the error. Is there a way of forcing this, or am I calling the function incorrectly?
Although the function not marked as unavailable to swift:
-(BOOL)save:(NSError **)error
is defined to return a bool, the Swift implementation (which throws) apparently does not, so the code compiles fine if I'm not expecting to receive a return value, i.e.:
let operation = NSBlockOperation { () -> Void in
do {
try rating.save()
}
catch let er as NSError {
error = er
}
}
I'm still now sure how I could have determined this without trial and error.
The first overload is marked unavailable to Swift, hence it is not visible.
The second overload is made available, but as you discovered yourself, it requires a try since it returns a NSError output parameter. The BOOL return value in Cocoa is there to indicate whether the operation was successful or not. In Swift, this is handled by catching the NSError instead. This behaviour was introduced in (I think) Swift 2.0, and is documented here.
To summarize, an Obj-C method
- (BOOL) doSomething:(NSError**)error {}
maps to the following Swift method
func doSomething() throws

Passing a method to EventListenerList "add" method

I want to do something like the following:
void handleClick(){
//do stuff
}
void addHandlerToButton(){
window.document.query('#somebutton').on.click.add(handleClick);
}
Dart editor's static checking reports '() -> void' is not assignable to 'EventListener'
I have a feeling I'm missing something really obvious.
Click handlers gets the click event passed as a argument (so you for example can get the screen coordiantes, target element etc.). So your handler method signature must be
void handleClick(Event event){
// do stuff with event
}
The error you are reciving is actually telling you that (although in a cryptic way):
'() -> void' is not assignable to 'EventListener'
Here EventListener is basically any function type with signature void handle(Event event) so the function you add with on.click.add must match this signature.

Resources