Phi*_*ert 18 iphone events cocoa ios
根据iOS文档,响应者链用于"向上传递"触摸事件.它也用于控件生成的操作.精细.
我真正想做的是发送自定义事件"上链".接收事件的第一响应者将处理它.这似乎是一个非常常见的模式,但我找不到任何关于如何做到"iOS/Cocoa方式"的好解释.
由于响应链正是我所需要的,我提出了这样的解决方案:
// 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];
}
Run Code Online (Sandbox Code Playgroud)
这很有效,但我觉得应该有其他方法来处理这个问题.手动走链子这种方式似乎不太好......
请注意,通知在这里不是一个好的解决方案,因为我只希望参与视图层次结构中的对象,并且通知是全局的.
在iOS中处理这个问题的最佳方法是什么(和Cocoa一样)?
编辑:
我想要完成什么?
我有一个视图控制器,它有一个视图,有子视图等...几个子视图是一个特定类型,显示数据库中的项目.当用户点击此视图时,应将信号发送到控制器以导航到此项目的详细信息页面.
处理点击的视图位于视图层次结构中主视图下方的几个级别.我必须告诉控制器(或在某些情况下,特定的子视图"向上链")选择了一个项目.
听通知是一种选择,但我不喜欢这种解决方案,因为选择一个项目不是全局事件.它严格依赖于当前的视图控制器.
Pet*_*sey 14
UIApplication有一个方法就是为了这个目的,它的Cocoa表兄也是如此.您可以使用一条消息替换问题中的所有代码.
Mik*_*lah 12
你很亲密.更标准的是这样的事情:
@implementation NSResponder (MyViewController)
- (void)itemSelected:(id)someItem
{
[[self nextResponder] itemSelected:someItem];
}
@end
Run Code Online (Sandbox Code Playgroud)
这通常是事件默认情况下如何传递链.然后在右侧控制器中,覆盖该方法,而不是采取自定义操作.
这可能不是您想要实现的正确模式,但它是将消息传递到响应者链的好方法.
如果您确定第一响应者设置正确,则 Peter 的解决方案有效。如果你想更多地控制哪个对象被通知事件,你应该使用targetForAction:withSender:代替。
这允许您指定应该能够处理事件的第一个视图,然后它会从那里爬上响应者链,直到找到可以处理消息的对象。
这是您可以使用的完整记录的功能:
@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)userInfo@endcode
*/
+ (BOOL)sendResponderChainAction:(SEL)action to:(UIResponder *)target from:(id)sender withUserInfo:(id)userInfo;
@end
Run Code Online (Sandbox Code Playgroud)
执行:
@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
Run Code Online (Sandbox Code Playgroud)
注意:这使用SuppressPerformSelectorLeakWarning宏。
这在 UITableView 中效果很好。想象一下,您在单元格上有一个手势识别器,您需要将执行的操作通知给视图控制器。您不必为单元创建委托,然后将消息转发给委托,而是可以使用响应者链。
示例用法(发件人):
// in table view cell class:
- (void)longPressGesture:(UILongPressGestureRecognizer *)recognizer {
// ...
[ABCResponderChainHelper sendResponderChainAction:@selector(longPressCell:) to:self from:self withUserInfo:nil];
}
Run Code Online (Sandbox Code Playgroud)
这里self
指的是细胞本身。所述应答器 链可确保该方法首先被发送到的UITableViewCell
,那么UITableView
,最终的UIViewController
。
示例用法(接收器):
#pragma mark - Custom Table View Cell Responder Chain Messages
- (void)longPressCell:(UITableViewCell *)sender {
// handle the long press
}
Run Code Online (Sandbox Code Playgroud)
如果你试图用sendAction:to:from:forEvent:做同样的事情,你有两个问题:
nil
给to
参数,此时它会开始在消息第一反应者,而不是你所选择的对象。控制第一响应者可能很麻烦。使用此方法,您只需告诉它从哪个对象开始。UIEvent
并添加一个属性,例如userInfo
并在事件参数中传递它;在这种情况下,一个笨拙的解决方案。