2013-11-28 36 views
6

Tôi đang triển khai mã đầu tiên của mình với https://github.com/ReactiveCocoa/ReactiveCocoa.Tại sao tín hiệu được gọi hai lần trong ReactiveCocoa?

Dành cho đăng nhập người dùng. Dòng [subscriber sendNext:user]; được gọi là hai lần, nhưng tôi hy vọng sẽ chỉ có một. Và bản đồ không được gọi là ở tất cả (vì vậy AutoLogin không bao giờ được gọi là)

Đây là triển khai thực hiện của tôi:

-(RACSignal *) login:(NSString *)email pwd:(NSString *)pwd 
{ 
    DDLogInfo(@"Login user %@", email); 

    RACSignal *login = [RACSignal createSignal:^ RACDisposable *(id<RACSubscriber> subscriber) 
    {   
     [PFUser logInWithUsernameInBackground:email password:pwd block:^(PFUser *user, NSError *error) { 

      if (error) { 
       [subscriber sendError:error]; 
      } else { 
       [subscriber sendNext:user]; 

       [subscriber sendCompleted]; 
      } 
     }]; 

     return nil; 
    }]; 

    [login map:^(PFUser *user) { 
     return [self autoLogin:user]; 
    }]; 

    return login; 
} 

Được gọi theo cách này:

NSString *email = data[@"email"]; 
NSString *pwd = data[@"pwd"]; 
[SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeBlack]; 

RACSignal *login = [[SyncEngine server] login:email pwd:pwd]; 

[login 
subscribeCompleted:^ 
{ 
    [[NSNotificationCenter defaultCenter] 
    postNotificationName:NOTIFY_LOGIN_CHANGED 
    object:self]; 

    [SVProgressHUD showSuccessWithStatus:LOC_OK]; 


    [self cancelForm]; 
}]; 

[login 
subscribeError:^(NSError *error) 
{ 
    [SVProgressHUD dismiss]; 

    [AppUrls alertError:LOC_ERROR_LOGING msg:error.userInfo[@"error"]]; 
}]; 
+0

Một bước qua mã và xem điều gì đang xảy ra. Hoặc đặt điểm ngắt tại mục nhập để gửiNext và kiểm tra ngăn xếp cuộc gọi mỗi khi được gọi. –

Trả lời

9

Điều này xảy ra bởi vì các khối truyền cho +[RACSignal createSignal:] thực hiện bất kỳ khi nào đăng ký tín hiệu được tạo và mã của bạn tạo hai đăng ký riêng biệt:

[login subscribeCompleted:^{ ... }]; 

[login subscribeError:^(NSError *error) { ... }]; 

Nếu bạn chỉ muốn tạo một thuê bao duy nhất, sử dụng phương pháp -[RACSignal subscribeError:completed:]:

[login subscribeError:^(NSError *error) { 
     [SVProgressHUD dismiss]; 

     [AppUrls alertError:LOC_ERROR_LOGING msg:error.userInfo[@"error"]]; 
    } 
    completed:^{ 
     [[NSNotificationCenter defaultCenter] 
     postNotificationName:NOTIFY_LOGIN_CHANGED 
     object:self]; 

     [SVProgressHUD showSuccessWithStatus:LOC_OK]; 


     [self cancelForm]; 
    }]; 
5

Mặc dù đôi khi this solution có thể là tất cả các bạn cần, đôi khi bạn muốn chắc chắn khối thuê bao chỉ được gọi một lần, có lẽ vì nó tạo ra các tác dụng phụ. Trong trường hợp này, bạn có thể trả lại tín hiệu gọi -replay:

return [[RACSignal createSignal:^ RACDisposable *(id<RACSubscriber> subscriber) {   
    [PFUser logInWithUsernameInBackground:email password:pwd block:^(PFUser *user, NSError *error) { 

     if (error) { 
      [subscriber sendError:error]; 
     } else { 
      [subscriber sendNext:user]; 

      [subscriber sendCompleted]; 
     } 
    }]; 

    return nil; 
}] map:^(PFUser *user) { 
    return [self autoLogin:user]; 
}] replay]; 

mới, tín hiệu có nguồn gốc này sẽ gửi các thông điệp tương tự hoặc lỗi cho tất cả các thuê bao. Nếu tín hiệu hoàn thành, và có một thuê bao mới, điều này sẽ ngay lập tức nhận được tất cả các tin nhắn là tốt.

Các vấn đề liên quan