2010-10-05 17 views
18

Theo tài liệu iOS, chuỗi trả lời được sử dụng để truyền các sự kiện chạm "lên chuỗi". Nó cũng được sử dụng cho các hành động được tạo ra bởi các điều khiển. Khỏe.Đi bộ chuỗi trả lời để chuyển các sự kiện tùy chỉnh. Điều này có sai không?

Điều tôi thực sự muốn làm là gửi sự kiện tùy chỉnh "lên chuỗi". Người trả lời đầu tiên để nhận sự kiện sẽ xử lý nó. Điều này có vẻ giống như một mô hình khá phổ biến, nhưng tôi không thể tìm thấy bất kỳ lời giải thích tốt về cách làm điều đó "iOS/Cocoa cách".

Kể từ khi chuỗi trả lời chính xác là những gì tôi cần, tôi đã đưa ra một giải pháp như thế này:

// some event happened in my view that 
// I want to turn into a custom event and pass it "up": 

UIResponder *responder = [self nextResponder]; 

while (responder) { 

    if ([responder conformsToProtocol:@protocol(ItemSelectedDelegate)]) { 
     [responder itemSelected:someItem]; 
     break; 
    } 

    responder = [responder nextResponder]; 
} 

này hoạt động hoàn hảo, nhưng tôi có một cảm giác rằng cần có cách khác để xử lý này. Đi theo chuỗi bằng tay theo cách này dường như không ... rất đẹp.

Lưu ý rằng thông báo không phải là giải pháp tốt ở đây, vì tôi chỉ muốn các đối tượng trong cấu trúc phân cấp xem có liên quan và thông báo là toàn cầu.

Cách tốt nhất để xử lý điều này trong iOS (và Cocoa cho vấn đề đó) là gì?

EDIT:

Tôi muốn đạt được điều gì?

Tôi có một bộ điều khiển chế độ xem, trong đó có chế độ xem, trong đó có các bản xem trước vv ... Một số xem phụ thuộc loại cụ thể hiển thị một mục từ cơ sở dữ liệu. Khi người dùng chạm vào chế độ xem này, tín hiệu sẽ được gửi tới bộ điều khiển để điều hướng đến trang chi tiết của mục này.

Chế độ xem xử lý thao tác nhấn là một vài cấp bên dưới chế độ xem chính trong cấu trúc phân cấp chế độ xem. Tôi phải nói với bộ điều khiển (hoặc trong một số trường hợp một subview cụ thể "lên chuỗi") rằng một mục đã được chọn.

Lắng nghe thông báo sẽ là một tùy chọn, nhưng tôi không thích giải pháp đó vì chọn mục không phải là sự kiện toàn cầu. Nó được gắn chặt với bộ điều khiển xem hiện tại.

+0

"... Tôi có cảm giác rằng có những cách khác để xử lý việc này ..." Có thể có, nhưng thật khó để nói mà không biết chính xác lý do bạn muốn chuyển sự kiện tùy chỉnh lên chuỗi. Mục tiêu cuối cùng của bạn là gì? –

+0

Xem phần giải thích đã thêm của tôi trong câu hỏi. –

+0

Re câu hỏi năm tuổi này ... đây là cách Swift hiện đại đẹp để làm một số nhiệm vụ như thế này http://stackoverflow.com/a/37515358/294884 – Fattie

Trả lời

12

Bạn đang ở khá gần. Tiêu chuẩn sẽ như thế nào hơn là như sau:

@implementation NSResponder (MyViewController) 
- (void)itemSelected:(id)someItem 
{ 
    [[self nextResponder] itemSelected:someItem]; 
} 
@end 

Thông thường, các sự kiện được chuyển qua chuỗi theo mặc định. Sau đó, trong bộ điều khiển phù hợp, hãy ghi đè phương thức đó để thay thế thực hiện hành động tùy chỉnh.

Đây có thể không phải là mẫu phù hợp cho những gì bạn muốn đạt được, nhưng đó là cách hay để truyền tin nhắn lên chuỗi trả lời.

+0

Điều đó thật tuyệt vời. Làm cho cảm giác hoàn hảo, và nó chắc chắn sẽ giúp giải quyết vấn đề của tôi. Mẫu này có được mô tả ở mọi nơi không? –

+0

Không phải với kiến ​​thức của tôi. Ngoài ra tôi nhận ra tôi đã trả lời về Cocoa, nhưng tất cả nên được áp dụng cho Cocoa Touch. –

+1

Tại sao mẫu này không được ghi lại ở bất kỳ đâu? –

13

UIApplication has a method for just this purpose, cũng như its Cocoa cousin. Bạn có thể thay thế tất cả mã đó trong câu hỏi của mình bằng một tin nhắn.

+1

Tôi đã đọc điều này và bằng cách nào đó tôi đã không nhận thấy dòng trong tài liệu có nội dung * "Nếu mục tiêu là không, ứng dụng sẽ gửi tin nhắn đến người trả lời đầu tiên, từ khi nó tiến hành chuỗi trả lời cho đến khi nó được xử lý." *. Cảm ơn rất nhiều vì câu trả lời này! Rất hữu ích! –

+1

Câu hỏi tiếp theo: Đây có vẻ là một giải pháp tuyệt vời, nhưng nó giả định bạn luôn làm việc với các đối tượng UIEvent. Đối tượng UIEvent rất hạn chế về phạm vi (chỉ chạm, cử chỉ, v.v ...).Điều gì sẽ xảy ra nếu tôi muốn một sự kiện tùy chỉnh cấp cao hơn như "mục x đã chọn" hoặc "mục x đã xóa"? Điều đó sẽ không hoạt động với "sendAction" –

+0

trong khi bạn thực sự có thể thay thế tất cả mã bằng 1 tin nhắn, bạn mất khả năng gửi một số dữ liệu hoặc thông số cùng? Là sendAction: tới: from: forEvent: không hỗ trợ điều này, trừ khi bạn lạm dụng thông số từ hoặc sự kiện. Bạn có thể lấy dữ liệu từ tham số từ chính mình, nhưng tôi muốn dữ liệu hoặc ngữ cảnh được đóng gói và độc lập. –

4

Giải pháp của Peter hoạt động nếu bạn chắc chắn rằng phản hồi đầu tiên được đặt chính xác. Nếu bạn muốn kiểm soát nhiều hơn đối tượng nào được thông báo về các sự kiện, bạn nên sử dụng targetForAction:withSender: để thay thế.

Điều này cho phép bạn chỉ định chế độ xem đầu tiên có thể xử lý sự kiện và từ đó sẽ thu thập thông tin chuỗi trả lời cho đến khi tìm thấy đối tượng có thể xử lý thư.

Đây là một chức năng fully documented bạn có thể sử dụng:

@interface ABCResponderChainHelper 
/*! 
Sends an action message identified by selector to a specified target's responder chain. 
@param action 
    A selector identifying an action method. See the remarks for information on the permitted selector forms. 
@param target 
    The object to receive the action message. If @p target cannot invoke the action, it passes the request up the responder chain. 
@param sender 
    The object that is sending the action message. 
@param userInfo 
    The user info for the action. This parameter may be @c nil. 
@return 
    @c YES if a responder object handled the action message, @c NO if no object in the responder chain handled the message. 
@remarks 
    This method pushes two parameters when calling the target. This design enables the action selector to be one of the following: 
@code 
- (void)action 
- (void)action:(id)sender 
- (void)action:(id)sender userInfo:(id)[email protected] 
*/ 
+ (BOOL)sendResponderChainAction:(SEL)action to:(UIResponder *)target from:(id)sender withUserInfo:(id)userInfo; 
@end 

Thực hiện:

@implementation ABCResponderChainHelper 
+ (BOOL)sendResponderChainAction:(SEL)action to:(UIResponder *)target from:(id)sender withUserInfo:(id)userInfo { 
    target = [target targetForAction:action withSender:sender]; 
    if (!target) { 
     return NO; 
    } 

    NSMethodSignature *signature = [target methodSignatureForSelector:action]; 
    const NSInteger hiddenArgumentCount = 2; // self and _cmd 
    NSInteger argumentCount = [signature numberOfArguments] - hiddenArgumentCount; 
    switch (argumentCount) { 
     case 0: 
      SuppressPerformSelectorLeakWarning([target performSelector:action]); 
      break; 
     case 1: 
      SuppressPerformSelectorLeakWarning([target performSelector:action withObject:sender]); 
      break; 
     case 2: 
      SuppressPerformSelectorLeakWarning([target performSelector:action withObject:sender withObject:userInfo]); 
      break; 
     default: 
      NSAssert(NO, @"Invalid number of arguments."); 
      break; 
    } 

    return YES; 
} 
@end 

Lưu ý: đây sử dụng SuppressPerformSelectorLeakWarning vĩ mô.

Công trình này tuyệt vời trong UITableView. Hãy tưởng tượng bạn có một bộ nhận dạng cử chỉ trên ô, và bạn cần thông báo cho bộ điều khiển xem của hành động đã được thực hiện. Thay vì phải tạo một đại biểu cho ô, và sau đó chuyển tiếp tin nhắn đến đại biểu, bạn có thể sử dụng chuỗi trả lời thay thế.

sử dụng mẫu (người gửi):

// in table view cell class: 
- (void)longPressGesture:(UILongPressGestureRecognizer *)recognizer { 
    // ... 
    [ABCResponderChainHelper sendResponderChainAction:@selector(longPressCell:) to:self from:self withUserInfo:nil]; 
} 

Đây self đề cập đến các tế bào của chính nó. responderchain đảm bảo rằng phương thức được gửi đầu tiên đến UITableViewCell, sau đó là UITableView và cuối cùng là đến UIViewController.

sử dụng mẫu (receiver):

#pragma mark - Custom Table View Cell Responder Chain Messages 
- (void)longPressCell:(UITableViewCell *)sender { 
    // handle the long press 
} 

Nếu bạn cố gắng làm điều tương tự với sendAction:to:from:forEvent:, bạn có hai vấn đề:

  • Để cho nó để làm việc với các chuỗi responder, bạn phải vượt qua trong nil tham số to, tại thời điểm đó, nó sẽ bắt đầu nhắn tin theo số phản hồi đầu tiên thay vì đối tượng bạn chọn. Việc kiểm soát phản hồi đầu tiên có thể rất cồng kềnh. Với phương pháp này, bạn chỉ cần cho nó biết đối tượng nào cần bắt đầu.
  • Bạn không thể dễ dàng vượt qua đối số thứ hai với dữ liệu tùy ý. Bạn would need to subclass UIEvent và thêm thuộc tính như userInfo và chuyển số đó cùng trong đối số sự kiện; một giải pháp vụng về trong trường hợp này.
Các vấn đề liên quan