2011-12-05 28 views
31

Tôi có một phương thức gọi lại mà tôi đã làm việc, nhưng tôi muốn biết cách chuyển các giá trị cho nó.Trình xử lý gọi lại mục tiêu-C

Những gì tôi có điều này là:

@interface DataAccessor : NSObject 
{ 
    void (^_completionHandler)(Account *someParameter); 

} 


- (void) signInAccount:(void(^)(Account *))handler; 

Đoạn mã trên công trình, nhưng tôi muốn vượt qua giá trị cho phương pháp này. Cái này trông như thế nào? Một cái gì đó như:

- (void) signInAccount:(void(^)(Account *))handler user:(NSString *) userName pass:(NSString *) passWord; 

?

Trả lời

112

Tôi không hoàn toàn chắc chắn những gì bạn đang cố gắng làm ở đó - gọi lại của bạn là một khối ... là có chủ ý? Tôi mong đợi phương pháp của bạn trông giống như thế này:

- (void)signInAccountWithUserName:(NSString *)userName password:(NSString *)password; 

Nếu dự định gọi lại để thực hiện một số mã bổ sung (được chỉ định khi bạn gọi phương thức) hoàn thành thì khối sẽ hữu ích. Ví dụ, phương pháp của bạn sẽ trông như thế này:

- (void)signInAccountWithUserName:(NSString *)userName 
         password:(NSString *)password 
         completion:(void (^)(void))completionBlock 
{ 
    // ... 
    // Log into the account with `userName` and `password`... 
    // 

    if (successful) { 
     completionBlock(); 
    } 
} 

Và sau đó gọi phương thức như vậy:

[self signInAccountWithUserName:@"Bob" 
         password:@"BobsPassword" 
        completion:^{ 
         [self displayBalance]; // For example... 
        }]; 

gọi phương pháp này sẽ đăng nhập người dùng vào tài khoản và sau đó càng sớm càng đã hoàn tất , hiển thị số dư. Đây rõ ràng là một ví dụ giả tạo, nhưng hy vọng bạn có được ý tưởng.

Nếu đây không phải là loại điều bạn dự định, thì chỉ cần sử dụng chữ ký phương thức giống như chữ trên.


EDIT (Một ví dụ tốt hơn bằng cách sử dụng biến successful):

Một thiết kế tốt hơn sẽ được vượt qua một Boolean lại trong khối hoàn thành mô tả như thế nào đăng nhập đi:

- (void)signInAccountWithUserName:(NSString *)userName 
         password:(NSString *)password 
         completion:(void (^)(BOOL success))completionBlock 
{ 
    // Log into the account with `userName` and `password`... 
    // BOOL loginSuccessful = [LoginManager contrivedLoginMethod]; 

    // Notice that we are passing a BOOL back to the completion block. 
    if (completionBlock != nil) completionBlock(loginSuccessful); 
} 

Bạn cũng sẽ thấy rằng khoảng thời gian này, chúng tôi đang kiểm tra tham số completionBlock không phải là nil trước khi gọi - điều này rất quan trọng nếu bạn muốn cho phép od được sử dụng mà không cần khối hoàn thành. Bạn có thể sử dụng phương pháp này như sau:

[self signInAccountWithUserName:@"Bob" 
         password:@"BobsPassword" 
        completion:^(BOOL success) { 
         if (success) { 
          [self displayBalance]; 
         } else { 
          // Could not log in. Display alert to user. 
         } 
        }]; 

Vẫn còn tốt hơn (! Nếu bạn có thể tha các swaths ví dụ), nếu nó sẽ có ích cho người sử dụng biết lý do của sự thất bại, trả về một đối tượng NSError:

- (void)signInAccountWithUserName:(NSString *)userName 
         password:(NSString *)password 
         completion:(void (^)(NSError *error))completionBlock 
{ 
    // Attempt to log into the account with `userName` and `password`... 

    if (loginSuccessful) { 
     // Login went ok. Call the completion block with no error object. 
     if (completionBlock != nil) completionBlock(nil); 
    } else { 
     // Create an error object. (N.B. `userInfo` can contain lots of handy 
     // things! Check out the NSError Class Reference for details...) 
     NSInteger errorCode; 
     if (passwordIncorrect) { 
      errorCode = kPasswordIncorrectErrorCode; 
     } else { 
      errorCode = kUnknownErrorCode; 
     } 
     NSError *error = [NSError errorWithDomain:MyLoginErrorDomain code:errorCode userInfo:nil]; 
     if (completionBlock != nil) completionBlock(error); 
    } 
} 

người gọi sau đó có thể tận dụng các NSError trong khối hoàn thành để quyết định cách thức tiến hành (có khả năng nhất, để mô tả cho người sử dụng những gì đã xảy ra).Kiểu mẫu này hơi ít phổ biến hơn (mặc dù hoàn toàn hợp lệ); chủ yếu NSError s được trả về bởi con trỏ gián tiếp, ví dụ như trong NSFileWrapper s -initWithURL:options:error: phương pháp:

NSError *error; 
NSFileWrapper *fw = [[NSFileWrapper alloc] initWithURL:url options:0 error:&error]; 
// After the above method has been called, `error` is either `nil` (if all went well), 
// or non-`nil` (if something went wrong). 

Trong ví dụ đăng nhập, tuy nhiên, chúng ta có lẽ mong đợi nỗ lực đăng nhập để mất một khoảng thời gian để hoàn thành (ví dụ đăng nhập vào một tài khoản trực tuyến), do đó, nó là hoàn toàn hợp lý để sử dụng một trình xử lý hoàn thành mà vượt qua một lỗi trở lại.

+0

Cảm ơn bạn, điều này đã giúp tôi. Vâng, đó là cố ý. – Jesse

+2

Tôi có lẽ sẽ thiết kế nó với 2 khối: thành công và thất bại – vikingosegundo

+1

@vikingosegundo: Có, đề xuất tốt. Mặc dù, tùy thuộc vào ngữ cảnh nó có thể dễ dàng hơn để trả về thành công đó như là một 'BOOL', hoặc có thể truyền vào một đối tượng' NSError' bằng con trỏ-indirection để xác định mức độ đăng nhập. – Stuart

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