Objective-C - 为什么 UITapGestureRecognizer 会导致应用程序崩溃?
Objective-C - why the UITapGestureRecognizer crashing the app?
我将动态 UIView 作为 Array droplet。当点击那些随机的 UIView 对象时,我需要在那个特定的 droplet 上做 activity。所以当我触发这个 UITapGestureRecognizer *gesRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(ui_view_array_clicked)];
[ui_view addGestureRecognizer:gesRecognizer];
应用程序崩溃时。
可能出了什么问题?我也尝试过 @selector(ui_view_array_clicked:i)
但在这两种情况下,只要我单击 gesRecognizer
附带的任何一个 UIView,就会崩溃
错误:
2017-03-14 02:16:33.322 testing[80405:5647302] -[ViewController ui_view_array_clicked]: unrecognized selector sent to instance 0x7f9733d01f70
2017-03-14 02:16:33.337 testing[80405:5647302] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ViewController ui_view_array_clicked]: unrecognized selector sent to instance 0x7f9733d01f70'
*** First throw call stack:
(
0 CoreFoundation 0x000000010fc85d4b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x000000010f6e721e objc_exception_throw + 48
2 CoreFoundation 0x000000010fcf5f04 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
3 CoreFoundation 0x000000010fc0b005 ___forwarding___ + 1013
4 CoreFoundation 0x000000010fc0ab88 _CF_forwarding_prep_0 + 120
5 UIKit 0x00000001105e5409 -[UIGestureRecognizerTarget _sendActionWithGestureRecognizer:] + 57
6 UIKit 0x00000001105ed1a8 _UIGestureRecognizerSendTargetActions + 109
7 UIKit 0x00000001105eac77 _UIGestureRecognizerSendActions + 227
8 UIKit 0x00000001105e9f03 -[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:] + 891
9 UIKit 0x00000001105d5f7e _UIGestureEnvironmentUpdate + 1395
10 UIKit 0x00000001105d59c3 -[UIGestureEnvironment _deliverEvent:toGestureRecognizers:usingBlock:] + 521
11 UIKit 0x00000001105d4ba6 -[UIGestureEnvironment _updateGesturesForEvent:window:] + 286
12 UIKit 0x000000011011ac1d -[UIWindow sendEvent:] + 3989
13 UIKit 0x00000001100c79ab -[UIApplication sendEvent:] + 371
14 UIKit 0x00000001108b472d __dispatchPreprocessedEventFromEventQueue + 3248
15 UIKit 0x00000001108ad463 __handleEventQueue + 4879
16 CoreFoundation 0x000000010fc2a761 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
17 CoreFoundation 0x000000010fc0f98c __CFRunLoopDoSources0 + 556
18 CoreFoundation 0x000000010fc0ee76 __CFRunLoopRun + 918
19 CoreFoundation 0x000000010fc0e884 CFRunLoopRunSpecific + 420
20 GraphicsServices 0x0000000113a71a6f GSEventRunModal + 161
21 UIKit 0x00000001100a9c68 UIApplicationMain + 159
22 testing 0x000000010f11053f main + 111
23 libdyld.dylib 0x0000000112ae768d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
代码:
#import "ViewController.h"
@interface ViewController ()
@property (copy, nonatomic) NSMutableArray *randomSelection;
@property (assign, nonatomic) NSInteger phone_height;
@property (assign, nonatomic) NSInteger phone_width;
-(void)ui_view_array_clicked:(int)array_id;
@end
@implementation ViewController
-(void)ui_button_submit:(UIButton*)sender {
int phone_height = self.view.frame.size.height;
int phone_width = self.view.frame.size.width;
self.phone_height = phone_height;
self.phone_width = phone_width;
NSMutableArray *randomSelection = [[NSMutableArray alloc] init];
// Set - UIView
int j = 0;
int k = 0;
int l = 0;
for (int i = 0; i <= 50; i++) {
int col = floor(self.phone_width/50);
int logic = floor(i/col);
int xx = (i * 50);
if (logic == 1) {
xx = (j * 50);
j++;
}
else if (logic == 2 ) {
xx = (k * 50);
k++;
}
else if (logic == 3 ) {
xx = (l * 50);
l++;
}
NSLog(@">>> %d %d %d %d" , xx , logic , i, j);
UIView *ui_view = [[UIView alloc] initWithFrame:CGRectMake(xx, 50 * logic , 50,50)];
[randomSelection addObject:ui_view];
UITapGestureRecognizer *gesRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(ui_view_array_clicked)];
[ui_view addGestureRecognizer:gesRecognizer];
if(i%2==0) {
ui_view.backgroundColor = [UIColor blueColor];
}
else {
ui_view.backgroundColor = [UIColor redColor];
}
[self.view addSubview:ui_view];
}
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Made 50 RED UIView"
message:@"Will make them Black now" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
for (int i = 0; i <= 50; i++) {
NSLog(@"<<< %d" , i);
UIView *test = [randomSelection objectAtIndex:i];
//test.backgroundColor = [UIColor blackColor];
if(i%2==0) {
test.backgroundColor = [UIColor redColor];
}
else {
test.backgroundColor = [UIColor blueColor];
}
}
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
}
-(void)ui_view_array_clicked:(int)array_id {
NSLog(@">>> clicking: %d", array_id);
}
-(void)ui_button {
self.view.backgroundColor = [UIColor blackColor];
UIButton *but = [[UIButton alloc] init];
[but setTitle:@"--- Add ---" forState:UIControlStateNormal];
[but setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[but addTarget:self action:@selector(ui_button_submit:)
forControlEvents:UIControlEventTouchUpInside];
int startHeight = 167;
int frameHeight = self.view.frame.size.height - startHeight;
[but setFrame:CGRectMake(0, startHeight, 320, frameHeight)];
[but setTranslatesAutoresizingMaskIntoConstraints:false];
[but setImage:[UIImage imageNamed:@"Image"] forState:UIControlStateNormal];
[self.view addSubview:but];
NSDictionary *viewsDict = @{@"button" : but};
[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"V:[button]-0-|"
options:0 metrics:nil views:viewsDict]];
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:but
attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual
toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0
constant:0];
constraint.active = true;
[self.view addConstraint:constraint];
[self.view layoutIfNeeded];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self ui_button];
}
@end
你应该改变初始化方法
UITapGestureRecognizer *gesRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(ui_view_array_clicked:)];
函数应声明为
- (void) ui_view_array_clicked: (UITapGestureRecognizer *)recognizer
{
// Do something
}
您的手势识别器的动作方法是
ui_view_array_clicked
但是你在视图控制器中没有相应的方法。
你有有
-(void)ui_view_array_clicked:(int)array_id
但这是不同的方法/签名。
另外
- gestureRecognizer 目标的签名不采用任何参数或采用单个参数。单参数版本的参数需要是特定类型的:即发送消息的手势识别器。
因此以下任一模式都有效:
UITapGestureRecognizer *gesRecognizer =
[[UITapGestureRecognizer alloc]
initWithTarget:self
action:@selector(gestureSelector)];
//selector
- (void)gestureSelector
或...
UITapGestureRecognizer *gesRecognizer =
[[UITapGestureRecognizer alloc]
initWithTarget:self
action:@selector(gestureSelector:)];
//selector
- (void)gestureSelector:(UITapGestureRecognizer*)gestureRecognizer
还有...
使用 snake_case
对于 ObjectiveC 来说是非常不习惯的...推荐使用 camelCaseAtAllTimes
,尤其是对于方法。
你应该试试下面的答案
UIView *ui_view = [[UIView alloc] initWithFrame:CGRectMake(xx, 50 * logic , 50,50)];
[randomSelection addObject:ui_view];
UITapGestureRecognizer *gesRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(ui_view_array_clicked:)];
[ui_view addGestureRecognizer:gesRecognizer];
这将在您的 view
上设置点击手势
在您的方法中访问点击的 view
- (void)gestureSelector:(UITapGestureRecognizer*)gestureRecognizer{
UIView *your_tapped_view = gestureRecognizer.view;
}
使用此代码。
不要忘记在手势方法声明中添加 :
。
我将动态 UIView 作为 Array droplet。当点击那些随机的 UIView 对象时,我需要在那个特定的 droplet 上做 activity。所以当我触发这个 UITapGestureRecognizer *gesRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(ui_view_array_clicked)];
[ui_view addGestureRecognizer:gesRecognizer];
应用程序崩溃时。
可能出了什么问题?我也尝试过 @selector(ui_view_array_clicked:i)
但在这两种情况下,只要我单击 gesRecognizer
错误:
2017-03-14 02:16:33.322 testing[80405:5647302] -[ViewController ui_view_array_clicked]: unrecognized selector sent to instance 0x7f9733d01f70
2017-03-14 02:16:33.337 testing[80405:5647302] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ViewController ui_view_array_clicked]: unrecognized selector sent to instance 0x7f9733d01f70'
*** First throw call stack:
(
0 CoreFoundation 0x000000010fc85d4b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x000000010f6e721e objc_exception_throw + 48
2 CoreFoundation 0x000000010fcf5f04 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
3 CoreFoundation 0x000000010fc0b005 ___forwarding___ + 1013
4 CoreFoundation 0x000000010fc0ab88 _CF_forwarding_prep_0 + 120
5 UIKit 0x00000001105e5409 -[UIGestureRecognizerTarget _sendActionWithGestureRecognizer:] + 57
6 UIKit 0x00000001105ed1a8 _UIGestureRecognizerSendTargetActions + 109
7 UIKit 0x00000001105eac77 _UIGestureRecognizerSendActions + 227
8 UIKit 0x00000001105e9f03 -[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:] + 891
9 UIKit 0x00000001105d5f7e _UIGestureEnvironmentUpdate + 1395
10 UIKit 0x00000001105d59c3 -[UIGestureEnvironment _deliverEvent:toGestureRecognizers:usingBlock:] + 521
11 UIKit 0x00000001105d4ba6 -[UIGestureEnvironment _updateGesturesForEvent:window:] + 286
12 UIKit 0x000000011011ac1d -[UIWindow sendEvent:] + 3989
13 UIKit 0x00000001100c79ab -[UIApplication sendEvent:] + 371
14 UIKit 0x00000001108b472d __dispatchPreprocessedEventFromEventQueue + 3248
15 UIKit 0x00000001108ad463 __handleEventQueue + 4879
16 CoreFoundation 0x000000010fc2a761 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
17 CoreFoundation 0x000000010fc0f98c __CFRunLoopDoSources0 + 556
18 CoreFoundation 0x000000010fc0ee76 __CFRunLoopRun + 918
19 CoreFoundation 0x000000010fc0e884 CFRunLoopRunSpecific + 420
20 GraphicsServices 0x0000000113a71a6f GSEventRunModal + 161
21 UIKit 0x00000001100a9c68 UIApplicationMain + 159
22 testing 0x000000010f11053f main + 111
23 libdyld.dylib 0x0000000112ae768d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
代码:
#import "ViewController.h"
@interface ViewController ()
@property (copy, nonatomic) NSMutableArray *randomSelection;
@property (assign, nonatomic) NSInteger phone_height;
@property (assign, nonatomic) NSInteger phone_width;
-(void)ui_view_array_clicked:(int)array_id;
@end
@implementation ViewController
-(void)ui_button_submit:(UIButton*)sender {
int phone_height = self.view.frame.size.height;
int phone_width = self.view.frame.size.width;
self.phone_height = phone_height;
self.phone_width = phone_width;
NSMutableArray *randomSelection = [[NSMutableArray alloc] init];
// Set - UIView
int j = 0;
int k = 0;
int l = 0;
for (int i = 0; i <= 50; i++) {
int col = floor(self.phone_width/50);
int logic = floor(i/col);
int xx = (i * 50);
if (logic == 1) {
xx = (j * 50);
j++;
}
else if (logic == 2 ) {
xx = (k * 50);
k++;
}
else if (logic == 3 ) {
xx = (l * 50);
l++;
}
NSLog(@">>> %d %d %d %d" , xx , logic , i, j);
UIView *ui_view = [[UIView alloc] initWithFrame:CGRectMake(xx, 50 * logic , 50,50)];
[randomSelection addObject:ui_view];
UITapGestureRecognizer *gesRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(ui_view_array_clicked)];
[ui_view addGestureRecognizer:gesRecognizer];
if(i%2==0) {
ui_view.backgroundColor = [UIColor blueColor];
}
else {
ui_view.backgroundColor = [UIColor redColor];
}
[self.view addSubview:ui_view];
}
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Made 50 RED UIView"
message:@"Will make them Black now" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
for (int i = 0; i <= 50; i++) {
NSLog(@"<<< %d" , i);
UIView *test = [randomSelection objectAtIndex:i];
//test.backgroundColor = [UIColor blackColor];
if(i%2==0) {
test.backgroundColor = [UIColor redColor];
}
else {
test.backgroundColor = [UIColor blueColor];
}
}
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
}
-(void)ui_view_array_clicked:(int)array_id {
NSLog(@">>> clicking: %d", array_id);
}
-(void)ui_button {
self.view.backgroundColor = [UIColor blackColor];
UIButton *but = [[UIButton alloc] init];
[but setTitle:@"--- Add ---" forState:UIControlStateNormal];
[but setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[but addTarget:self action:@selector(ui_button_submit:)
forControlEvents:UIControlEventTouchUpInside];
int startHeight = 167;
int frameHeight = self.view.frame.size.height - startHeight;
[but setFrame:CGRectMake(0, startHeight, 320, frameHeight)];
[but setTranslatesAutoresizingMaskIntoConstraints:false];
[but setImage:[UIImage imageNamed:@"Image"] forState:UIControlStateNormal];
[self.view addSubview:but];
NSDictionary *viewsDict = @{@"button" : but};
[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"V:[button]-0-|"
options:0 metrics:nil views:viewsDict]];
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:but
attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual
toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0
constant:0];
constraint.active = true;
[self.view addConstraint:constraint];
[self.view layoutIfNeeded];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self ui_button];
}
@end
你应该改变初始化方法
UITapGestureRecognizer *gesRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(ui_view_array_clicked:)];
函数应声明为
- (void) ui_view_array_clicked: (UITapGestureRecognizer *)recognizer
{
// Do something
}
您的手势识别器的动作方法是
ui_view_array_clicked
但是你在视图控制器中没有相应的方法。
你有有
-(void)ui_view_array_clicked:(int)array_id
但这是不同的方法/签名。
另外
- gestureRecognizer 目标的签名不采用任何参数或采用单个参数。单参数版本的参数需要是特定类型的:即发送消息的手势识别器。
因此以下任一模式都有效:
UITapGestureRecognizer *gesRecognizer =
[[UITapGestureRecognizer alloc]
initWithTarget:self
action:@selector(gestureSelector)];
//selector
- (void)gestureSelector
或...
UITapGestureRecognizer *gesRecognizer =
[[UITapGestureRecognizer alloc]
initWithTarget:self
action:@selector(gestureSelector:)];
//selector
- (void)gestureSelector:(UITapGestureRecognizer*)gestureRecognizer
还有...
使用 snake_case
对于 ObjectiveC 来说是非常不习惯的...推荐使用 camelCaseAtAllTimes
,尤其是对于方法。
你应该试试下面的答案
UIView *ui_view = [[UIView alloc] initWithFrame:CGRectMake(xx, 50 * logic , 50,50)];
[randomSelection addObject:ui_view];
UITapGestureRecognizer *gesRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(ui_view_array_clicked:)];
[ui_view addGestureRecognizer:gesRecognizer];
这将在您的 view
在您的方法中访问点击的 view
- (void)gestureSelector:(UITapGestureRecognizer*)gestureRecognizer{
UIView *your_tapped_view = gestureRecognizer.view;
}
使用此代码。
不要忘记在手势方法声明中添加 :
。