2014-09-11 51 views
0

我試圖與登錄服務進行通信並更新UI的反應方式。問題是,我的登錄服務與代表一起工作,並且幾乎找到了我找到的與塊有關的所有示例。ReactiveCocoa和代表

我寫了一個可行的解決方案,但似乎有點笨重,我不知道這是最好的方法:

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]; 
     }]; 

    }]; 
} 

正如你可以看到有一堆代碼幾乎相同對於每個代表,這就是爲什麼我不確定這是否是最好的方式。

回答

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]; 
    }]; 
}]; 
+0

這正是我正在尋找的答案,我會嘗試並讓你知道。 – Odrakir 2014-09-11 15:20:51

+1

完美!我錯過了mapReplace位,它看起來更好地知道「合併」 – Odrakir 2014-09-11 15:43:59