ReactiveCocoa和代表

时间:2014-09-11 07:28:46

标签: ios objective-c reactive-cocoa

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

    }];
}

正如您所看到的那样,每个代表的代码几乎相同,这就是为什么我不确定这是否是最好的方法。

1 个答案:

答案 0 :(得分:4)

您的观点看起来很不错,但我对该模型有一些建议。重点是我通过将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];
    }];
}];