简体   繁体   English

自定义类中的UIButton目标操作

[英]UIButton target action inside custom class

I've been struggling with a bug, and I found a work-around, but I'd like to understand what is exactly going on. 我一直在努力解决一个错误,并且找到了一种解决方法,但是我想了解到底发生了什么。 it has something to do with UIButton target actions misfiring depending on different subview hierarchies, inside a subclass. 它与子类内部的UIButton目标操作根据不同的子视图层次结构而触发失败有关。

Brief summary: I have a subclass of NSObject with a UIView property object, a UIButton attached to it, and a target added to the button calling a function inside the subclass. 简介:我有一个NSObject的子类,带有一个UIView属性对象,一个附加的UIButton,以及一个添加到该按钮的目标,该目标调用该子类内部的函数。 Inside the main ViewController, I init the subclass and add its view to the view stack, click the button, and it throws me to main.mm with the error - EXC_BAD_ACCESS, gives me little feedback. 在主ViewController内,我初始化该子类并将其视图添加到视图堆栈中,单击按钮,它使我进入main.mm并出现错误-EXC_BAD_ACCESS,给我的反馈很少。 so the hierarchy looks like this: 因此层次结构如下所示:

-CustomClass
--UIView           <-this is added as a subview to the View Controller
---UIButton (onRelease calling a function)

so I fixed it by changing the custom class to be a subclass of UIView instead of NSObject, then add its @property UIView to be a subview of the custom class (and the button is still attached to the subview), and then in the main View Controller, I add the custom class itself as a subview, not the class's subview property object. 因此,我通过将自定义类更改为UIView的子类而不是NSObject进行了修复,然后将其@property UIView添加为自定义类的子视图(并且按钮仍附加到该子视图),然后在主菜单中在View Controller中,我将自定义类本身添加为子视图,而不是该类的subview属性对象。 then the button successfully calls the function. 然后该按钮成功调用该函数。 so the new arrangement looks like this: 因此新的安排如下所示:

-CustomClass (now UIView)     <-this is added as a subview to the View Controller
--UIView                      <-this is added as a subview to CustomClass
---UIButton (onRelease calling a function)

then, i realized i can just keep the CustomClass a subclass of UIView for both instances, the problem persists with the original setup if everything else is unchanged. 然后,我意识到我可以仅将CustomClass保留为两个实例的UIView的子类,如果其他所有条件不变,则问题仍然存在于原始设置中。

okay, more detail, here's code: 好的,更多细节,代码如下:

CustomClass: .h CustomClass:.h

@interface Temp : UIView
@property UIView *subview;
@property UIButton *but;
@end

.m .m

-(id) init{
    self = [super initWithFrame:[[UIScreen mainScreen] bounds]];
    if(self){
        _subview = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        //[self addSubview:_subview];  // FOR THE FIX
        _but = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        [_but setTitle:@"OKAY" forState:UIControlStateNormal];
        [_but setBackgroundColor:[UIColor blackColor]];
        [_but setFrame:CGRectMake(50, 50, 200, 200)];
        [_subview addSubview:_but];
        [_but addTarget:self action:@selector(pageTurn) forControlEvents:UIControlEventTouchUpInside];
    }
    return self;
}

-(void) pageTurn{
    NSLog(@"WORKS");
}

inside view controller: 内部视图控制器:

Temp *temp = [[Temp alloc] init];
[self.view addSubview:temp.subview];
//[self.view addSubview:temp];  // FOR THE FIX, instead of above line

You're messing with all kinds of view hierarchy stuff you don't need to, which is likely the cause of the problem. 您将不必要的各种视图层次结构东西弄乱了,这很可能是问题的原因。 I created a Test UIView subclass that had a UIButton instance variable that I added as a subview in the Test object, there's no need to add another view as a subview and then add the button to the subview, and then in your view controller add the button's subview to the view - it's WAY more complicated than it needs to be. 我创建了一个Test UIView子类,该子类具有一个UIButton实例变量,该变量作为子视图添加到Test对象中,无需将另一个视图添加为子视图,然后将按钮添加到子视图中,然后在视图控制器中添加按钮的子视图到视图-它比需要的复杂得多。

In a nutshell - Create the Temp UIView, add the button as a subview, then in your view controller class add the Temp UIView as a subview. 简而言之-创建Temp UIView,将按钮添加为子视图,然后在视图控制器类中将Temp UIView添加为子视图。 Simple as that, here is the code: 就这么简单,下面是代码:

- (id)init {
    self = [super initWithFrame:[[UIScreen mainScreen] bounds]];
    if(self){
        _but = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        [_but setTitle:@"OKAY" forState:UIControlStateNormal];
        [_but setBackgroundColor:[UIColor blackColor]];
        [_but setFrame:CGRectMake(100, 100, 200, 200)];
        [_but addTarget:self action:@selector(pageTurn) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:_but];
    }
    return self;
}

- (void)pageTurn {
    NSLog(@"WORKS");
}

Then added an instance to my view controller: 然后将一个实例添加到我的视图控制器中:

Test *temp = [[Test alloc] init];
temp.backgroundColor = [UIColor redColor];
[self.view addSubview:temp];

This was the result: 结果是:

在此处输入图片说明

Who's holding onto temp ? 谁在坚持temp

If temp isn't referenced by anyone then it's released. 如果没有任何人引用temp ,那么它将被释放。 At that point the target is zombie and of course you will crash. 那时目标是僵尸,您当然会崩溃。 temp.subview is being held by self.view . temp.subview正在举行self.view

In the second setup, adding temp as a subview of self.view keeps a reference to it. 在第二个设置中,将temp添加为self.view的子视图可保留对其的引用。


You can fix this by adding a Temp * property in the view controller. 您可以通过在视图控制器中添加Temp *属性来解决此问题。

self.temp = [[Temp alloc] init];
[self.view addSubview:self.temp.subview];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM