gpt4 book ai didi

ios - 如何使用 Reactive Cocoa 以正确的方式链接信号?

转载 作者:行者123 更新时间:2023-11-29 12:26:16 25 4
gpt4 key购买 nike

我在新的 iOS 应用程序中使用 ReactiveCocoa。我是响应式(Reactive)编程的新手,所以我仍在尝试了解什么是链接信号的正确方法。现在我有以下“使用 Twitter 登录”按钮的流程。

ALTUserManager 类具有以下方法来管理整个登录阶段,方法是调用库中的一些函数,该库提供 Twitter 登录面板并执行所有 OAuth 操作:

- (RACSignal *)loginTwitter:(UIViewController *)vc {
RACSignal *loginSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[[ALTTwitter sharedInstance]isLoggedIn:^(BOOL loggedIn) {
if(loggedIn){
[subscriber sendCompleted];
}
else{
[[ALTTwitter sharedInstance]login:vc andSuccess:^{
[subscriber sendCompleted];
} failure:^(NSString *error) {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
userInfo[NSLocalizedDescriptionKey] = error;
[subscriber sendError:[NSError errorWithDomain:@"" code:1 userInfo:userInfo]];
}];
}
}];
return nil;
}];
return loginSignal;
}

我使用的是 MVVM 模式,所以在我的 ViewModel 中,我在其 init 方法中添加了以下命令:

self.twitterLoginCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
return [[ALTUserManager sharedInstance] loginTwitter:nil];
}];

在我的 View Controller 中,我正在处理表示逻辑,我在显示进度 HUD 时阻塞界面,并最终报告错误或如果一切正常则跳过登录屏幕:

self.twBtn.rac_command = self.viewModel.twitterLoginCommand;
[self.viewModel.twitterLoginCommand.executionSignals subscribeNext:^(id x) {
NSLog(@"%@", x);
[x subscribeCompleted:^{
NSLog(@"%@", @"completed");
[ALTAlert wait:@""];
[[self.viewModel appLoginWithTwitter] subscribeNext:^(id x) {
NSLog(@"%@", x);
} error:^(NSError *error) {
[ALTAlert dismiss];
[ALTAlert error:error.localizedDescription];
} completed:^{
[ALTAlert dismiss];
@strongify(self);
[self goToChart];
}];
}];
}];
[self.viewModel.twitterLoginCommand.errors subscribeNext:^(NSError *error) {
NSLog(@"Login error: %@", error);
[ALTAlert dismiss];
[ALTAlert error:error.localizedDescription];
}];

我很确定这可以用更好的方式重写。我主要关心的是 [x subscribeCompleted] 行。什么是正确的方法?谢谢!

更新我尝试将所有逻辑移动到 RACCommand 内的 ViewModel,但我仍然需要捕获 RACCommand 内发生的错误。订阅 errors 信号不是一个选项,因为 RACCommand 仍然会返回 completed 事件,从而使我的表示逻辑无法判断是否一切顺利。我还没有尝试在 RACCommand 中设置一个 BOOL 并在出现错误时产生副作用并在 View 中观察它。但无论如何,这种方法似乎有点老套。

最佳答案

您可以使用 then 帮助程序稍微简化嵌套,这将简化错误处理并防止单独的 twitterLoginCommand.errors 订阅:

[self.viewModel.twitterLoginCommand.executionSignals subscribeNext:^(id x) {
[x then:^{
NSLog(@"%@", @"completed");
[ALTAlert wait:@""];
return [self.viewModel appLoginWithTwitter];
}] subscribeNext:^(id x) {
NSLog(@"%@", x);
} error:^(NSError *error) {
[ALTAlert dismiss];
[ALTAlert error:error.localizedDescription];
} completed:^{
[ALTAlert dismiss];
@strongify(self);
[self goToChart];
}];
}];

不过,这有点奇怪。因为如果 twitterLoginCommandappLoginWithTwitter 信号完成之前再次触发,您可能会进入奇怪的状态。考虑到应用程序的其余部分,这可能是不可能的,但仅孤立地查看此代码块是我会担心的事情。

更好的做法可能是将 then block 移动到 RACCommand 中,以确保这种情况永远不会发生(作为 RACCommand 在前一个执行完之前不会再次执行。)虽然没有看到更多代码,但我不能真正说这是否是一个合理的更改。

这是一件很难进一步清理的事情,因为它本身就有副作用。如果您为 ALTAlert 类创建一个响应式桥接器,您可以清除其中的许多订阅,因为您可以只说“查看这个信号中的信号,并让您的状态反射(reflect)它”。然后你可以只传递执行信号,而不必担心在这里做一些更粗暴的事情。

那么你唯一真正的副作用是 goToChart,你可以做一些更简单的事情:

[[[self.viewModel.twitterLoginCommand.executionSignals flattenMap:^(id x) {
return [x materialize];
}] filter:^(RACEvent *event) {
return event.eventType == RACEventTypeCompleted;
}] subscribeNext:^(id x) {
@strongify(self);
[self goToChart];
}];

关于ios - 如何使用 Reactive Cocoa 以正确的方式链接信号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29005652/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com