通过委托为另一个类中的手势识别器调用选择器

Posted

技术标签:

【中文标题】通过委托为另一个类中的手势识别器调用选择器【英文标题】:calling selector for a gesture recognizer in another class via delegation 【发布时间】:2014-06-28 12:46:35 【问题描述】:

我有一个自定义视图,它使用调用方法handleSingleTap 的手势识别器。如果手势识别器的设置和它调用的选择器在同一个自定义视图 (CircleView) 中,这可以正常工作。但是,我需要 viewController 中的 handleSingleTap 方法,所以我 (1) 在自定义视图中创建了一个协议(CircleView),(2)在视图中创建了委托属性,当我(3)创建手势识别器时,我将self.delegate设置为handleSingleTap的目标(而不是像最初那样只是self) .在viewController.h中,(4)我说它符合协议并声明了方法handleSingleTap。在视图控制器的 .m 文件中,我为自定义视图 (CircleView) 创建了一个属性,然后在 .m 文件的 viewDidLoad 中,将self 设置为自定义视图的委托。但是,当我点击自定义视图中的圆圈时,不会在 viewController 中调用 handleSingleTap 方法。

你能解释一下为什么选择器 handleSingleTap 没有在 viewController 中被调用吗?

1) 创建协议

@protocol CircleViewDelegate <NSObject>
-(void)handleSingleTap:(UITapGestureRecognizer *) tapper;

@end

2) 创建委托属性

@property (nonatomic, weak) id <CircleViewDelegate> delegate;

在圆形视图中 3) 创建手势识别器,目标为self.delegate

-(void)setUpGestureRecognizers

    UITapGestureRecognizer *singleFingerTap =
    [[UITapGestureRecognizer alloc] initWithTarget:self.delegate action:@selector(handleSingleTap:)];
    singleFingerTap.numberOfTapsRequired=1;
    [self addGestureRecognizer:singleFingerTap]; 

4) 在 vi​​ewController.h 中,

   @interface ViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate, CircleViewDelegate>
    -(void)handleSingleTap:(UITapGestureRecognizer *) tapper;

在 viewController.m 中

@property (strong, nonatomic) CircleView *overlay;

viewDidLoad

self.overlay.delegate = self;

viewController 中的这个方法没有被调用

-(void)handleSingleTap:(UITapGestureRecognizer *) tapper 
     NSLog(@"never getting called");


【问题讨论】:

您是否在overlay 上启用了用户交互?而且,你什么时候打电话给setUpGestureRecognizers?你在哪里添加你的overlay?如果您创建您的overlay,并在您的init 方法中调用setUpGestureRecognizers CircleView,那么它当然不会被调用,因为您在设置手势后设置了代理。 你真的打电话给setUpGestureRecognizers吗? @dasdom 代表应该总是很弱。 @nhgrif 是的,setUpGestureRecognizers 被调用,这就是 OP 的第一句话应该暗示的(即一切正常,直到我将 handleSingleTap 方法移动到 viewController 中) @FahriAzimov 用户交互不是问题(请参阅 OP 的新的第二和第三句 - 在我将选择器移动到视图控制器之前一切正常)。但是,是的,我在 CircleView 的 init 中调用了 setUpGestureRecognizers,所以我想我是在设置手势之后设置委托 【参考方案1】:

这是适合您的一种解决方案。当然你也可以用选择器来做,但这肯定也可以。

.h

#import <UIKit/UIKit.h>

@protocol CircleViewDelegate <NSObject>

@required
- (void) circleViewPressedByOneTap;

@end

@interface CircleView : UIView

@property (nonatomic,assign) id<CircleViewDelegate> delegate;

- (id)initWithFrame:(CGRect)frame andWithDelegate:(id<CircleViewDelegate>)del;

@end

.m:

#import "CircleView.h"

@interface CircleView () <UIGestureRecognizerDelegate>

@end

@implementation CircleView

@synthesize delegate;

- (id)initWithFrame:(CGRect)frame andWithDelegate:(id<CircleViewDelegate>)del

    self = [super initWithFrame:frame];
    if (self) 
        // Initialization code
        delegate = del;
        [self setUpGestureRecognizers];
    
    return self;


-(void)setUpGestureRecognizers

    UITapGestureRecognizer *singleFingerTap =
    [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
    singleFingerTap.numberOfTapsRequired=1;
    [self addGestureRecognizer:singleFingerTap];


-(void)handleSingleTap:(UITapGestureRecognizer *) tapper
    [delegate circleViewPressedByOneTap];

在你的 ViewController .m 中:

#import "YouClassViewController.h"
#import "CircleView.h"

@interface YouClassViewController () <CircleViewDelegate>

@end

@implementation YouClassViewController


- (void)viewDidLoad

    [super viewDidLoad];
    // Do any additional setup after loading the view.

    CircleView* yourCircleView = [[CircleView alloc] initWithFrame:CGRectMake(0, 0, 50, 50) andWithDelegate:self];
    [self.view addSubview:yourCircleView];


- (void) circleViewPressedByOneTap
    NSLog(@"Yeaah you pressed it ! :) ");

【讨论】:

Delegate 必须是assign,或者weak property,因为它会导致内存retain循环...这不是不安全的,你应该这样使用它。 如果您的代码具有强委托,我认为您必须阅读一些内存管理。 @incmiko 没有人推荐代表是strong。建议针对weak 而不是assign。当 assign 属性引用的对象被解除分配时,您现在可以潜在地调用被解除分配的对象的方法,这会导致崩溃。弱属性不会导致保留循环,但是当它们指向的对象被释放时,弱属性会自动设置为nil,因此如果使用weak,则无法在释放的对象上调用方法。你真的应该只对原始数据类型属性使用assign @dasdom 如果您将strong 用于委托属性,那么您的程序中存在设计缺陷。如果对象 A 是委托,则对象 B 应该对它有一个弱引用,并且对象 B 只需要在 A 存在时才存在。其他东西应该持有对对象 A 的强引用。然后当其他东西让我们离开 A 时,A 和 B 都可以解除分配。 @nhgrif 是的,你在 ARC 中是对的,弱引用应该是正确的方法,但在非弧中,没有弱,只有分配,是的,如果你使用分配,你有关心这些分配的代表,确保您的程序不会崩溃。

以上是关于通过委托为另一个类中的手势识别器调用选择器的主要内容,如果未能解决你的问题,请参考以下文章

UIGestureRecognizer,从另一个类调用选择器

从另一个类调用选择器的 UIGestureRecognizer

Swift 3使用选择器将按钮/手势识别器动作传递给其他功能

Swift:手势识别器无法识别的选择器发送到实例

无法调用选择器和手势委托 iOS 13.2

将 initWithCoder: implementation 转换为 Swift 时未触发手势识别器选择器