我正在尝试与登录服务通信并以反应方式更新UI。关键是我的登录服务适用于委托,而我发现的几乎每个示例都适用于块。
我写了一个可行的解决方案,但似乎有点笨拙,我不确定这是否是最好的方法:
LoginViewController:
- (void) viewDidLoad
{
[super viewDidLoad];
//Assign the "loginCommand" command to the button. It'll get executed on button pressed and the button is only enabled when the command says so.
self.entrarBtn.rac_command = self.viewModel.loginCommand;
//Subscribe and respond to command's successful signals
@weakify(self);
[self.viewModel.loginCommand.executionSignals subscribeNext:^(RACSignal *loginSignal) {
[loginSignal subscribeNext:^(id x) {
@strongify(self);
[self.viewPresenter enterMainNavigation];
}];
}];
//Subscribe and respond to command's error signals
[self.viewModel.loginCommand.errors
subscribeNext:^(NSError* error) {
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"ERROR" message:[NSString stringWithFormat:@"Error: %@", error.localizedDescription] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
}];
}
LoginViewModel:
- (id)init
{
self = [super init];
if(self) {
self.loginCommand = [[RACCommand alloc] initWithEnabled:self.enableLoginSignal
signalBlock:^RACSignal *(id input) {
return [self loginSignal];
}];
}
return self;
}
- (RACSignal *)loginSignal
{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
//LOGIN OK
RACDisposable* loginOKDisposable = [[self rac_signalForSelector:@selector(loginServiceDidReceiveLoginOK)
fromProtocol:@protocol(LoginServiceDelegate)] subscribeNext:^(id x) {
PositionGlobalService *positionGlobalService = [PositionGlobalService sharedInstance];
positionGlobalService.delegate = self;
[positionGlobalService getPositionGlobal];
}];
//GETTING USER INFO DELEGATE THEN SEND THE COMPLETED SIGNAL
RACDisposable* positionOKDisposable = [[self rac_signalForSelector:@selector(positionGlobalServiceDidReceivePositionGlobal)
fromProtocol:@protocol(PositionGlobalServiceDelegate)] subscribeNext:^(id x) {
[subscriber sendNext:nil];
[subscriber sendCompleted];
}];
RACDisposable* positionErrorDisposable = [[self rac_signalForSelector:@selector(positionGlobalServiceDidReceivePositionGlobalError:)
fromProtocol:@protocol(PositionGlobalServiceDelegate)] subscribeNext:^(id x) {
NSError* error = [NSError errorWithDomain:LoginErrorDomain code:LoginErrorGettingUserInfo userInfo:nil];
[subscriber sendError:error];
}];
//ERRORS
RACDisposable* loginKODisposable = [[self rac_signalForSelector:@selector(loginServiceDidReceiveLoginKO)
fromProtocol:@protocol(LoginServiceDelegate)] subscribeNext:^(id x) {
NSError* error = [NSError errorWithDomain:LoginErrorDomain code:LoginErrorKO userInfo:nil];
[subscriber sendError:error];
}];
RACDisposable* deniedDisposable = [[self rac_signalForSelector:@selector(loginServiceDidReceiveLoginKOAccessDenied)
fromProtocol:@protocol(LoginServiceDelegate)] subscribeNext:^(id x) {
NSError* error = [NSError errorWithDomain:LoginErrorDomain code:LoginErrorAccessDenied userInfo:nil];
[subscriber sendError:error];
}];
RACDisposable* connectionErrorDisposable = [[self rac_signalForSelector:@selector(loginServiceDidReceiveConnectionError)
fromProtocol:@protocol(LoginServiceDelegate)] subscribeNext:^(id x) {
NSError* error = [NSError errorWithDomain:LoginErrorDomain code:LoginErrorConnectionError userInfo:nil];
[subscriber sendError:error];
}];
RACDisposable* genericErrorDisposable = [[self rac_signalForSelector:@selector(loginServiceDidReceiveGenericError:)
fromProtocol:@protocol(LoginServiceDelegate)] subscribeNext:^(id x) {
NSError* error = [NSError errorWithDomain:LoginErrorDomain code:LoginErrorGenericError userInfo:nil];
[subscriber sendError:error];
}];
LoginService *loginService = [LoginService sharedInstance];
loginService.delegate = self;
[loginService checkLogin:self.usuario withPassword:self.password documentType:LoginDocumentTypeNIF saveLogin:YES];
return [RACDisposable disposableWithBlock:^{
[loginOKDisposable dispose];
[positionOKDisposable dispose];
[positionErrorDisposable dispose];
[loginKODisposable dispose];
[deniedDisposable dispose];
[connectionErrorDisposable dispose];
[genericErrorDisposable dispose];
}];
}];
}
如您所见,有很多代码对于每个委托人几乎都是相同的,这就是为什么我不确定这是否是最好的方式的原因。
最佳答案
您的观点看起来不错,但是我对模型有一些建议。要点是,通过将LoginService
和PositionGlobalService
上的信号移到这些服务的相应类中,可以简化它们。然后,您可以合并错误并创建单个信号,例如:
@interface LoginService : SomeSuperclass<LoginServiceDelegate>
- (RACSignal *)loginWithID:(NSString *)userid password:(NSString *password);
@end
@implementation LoginService()
- (RACSignal *)loginWithID:(NSString *)userid password:(NSString *)password {
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
RACDisposable *errorDisposable = [[RACSignal merge:@[[[self rac_signalForSelector:@selector(loginServiceDidReceiveLoginKO) fromProtocol:@protocol(LoginServiceDelegate)] mapReplace:[NSError errorWithDomain:LoginErrorDomain code:LoginErrorKO userInfo:nil]],
[[self rac_signalForSelector:@selector(loginServiceDidReceiveLoginKOAccessDenied) fromProtocol:@protocol(LoginServiceDelegate)] mapReplace:[NSError errorWithDomain:LoginErrorDomain code:LoginErrorAccessDenied userInfo:nil]],
[[self rac_signalForSelector:@selector(loginServiceDidReceiveConnectionError) fromProtocol:@protocol(LoginServiceDelegate)] mapReplace:[NSError errorWithDomain:LoginErrorDomain code:LoginErrorConnectionError userInfo:nil]],
[[self rac_signalForSelector:@selector(loginServiceDidReceiveGenericError) fromProtocol:@protocol(LoginServiceDelegate)] mapReplace:[NSError errorWithDomain:LoginErrorDomain code:LoginErrorGenericError userInfo:nil]]]] subscribeNext:^(id x) {
[subscriber sendError:x];
}];
RACDisposable *loginDisposable = [[self rac_signalForSelector:@selector(loginServiceDidReceiveLoginOK) fromProtocol:@protocol(LoginServiceDelegate)] subscribeNext:^(id x) {
[subscriber sendNext:x];
[subscriber sendCompleted];
}];
[self checkLogin:userid withPassword:password documentType:LoginDocumentTypeNIF saveLogin:YES];
return [RACDisposable disposableWithBlock:^{
[errorDisposable dispose];
[loginDisposable dispose];
}];
}
}
@end
然后,您的登录功能可以变成这样(尽管我可能会重命名此功能,因为它做了两件事):
- (RACSignal *)loginSignal
{
return [[[LoginService sharedInstance] loginWithID:self.usuario password:self.password] then:^RACSignal *{
return [[PositionGlobalService sharedInstance] getPositionGlobalSignal];
}];
}];
关于ios - ReactiveCocoa和代表,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25781567/