ReactiveCocoa和代表

ReactiveCocoa和代表

我正在尝试与登录服务通信并以反应方式更新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];
        }];

    }];
}


如您所见,有很多代码对于每个委托人几乎都是相同的,这就是为什么我不确定这是否是最好的方式的原因。

最佳答案

您的观点看起来不错,但是我对模型有一些建议。要点是,通过将LoginServicePositionGlobalService上的信号移到这些服务的相应类中,可以简化它们。然后,您可以合并错误并创建单个信号,例如:

@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/

10-10 10:35