morcutt
morcutt

Reputation: 3749

Why is this button crashing my app when I tap it? UIButtion iPhone (ARC)

Whenever I tap "newButton" my app crashes. I am using automatic reference counting.

Edit: Just tried this in a different app and it works but does not work in my own.

Here is my code:

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIView *fullView = [[UIView alloc] initWithFrame:CGRectMake(0, -20, 320, 480)];
    fullView.backgroundColor = [UIColor blackColor];
    [[self view] addSubview:fullView];

    UIImage* blackButton =[[UIImage imageNamed:@"UIButtonBlack.png"]stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0];

    // Create button
    UIButton *newButton = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 30)];

    // Set button content alignment
    newButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
    newButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;

    // Set button title
    [newButton setTitle:@"Do Something" forState:UIControlStateNormal & UIControlStateHighlighted & UIControlStateSelected];
    // Set button title color
    [newButton setTitleColor:[UIColor colorWithRed:255.0f/255.0 green:255.0f/255.0 blue:255.0f/255.0 alpha:1.0] forState:UIControlStateNormal & UIControlStateHighlighted & UIControlStateSelected];
    // Add the background image
    [newButton setBackgroundImage:blackButton forState:UIControlStateNormal];
    // Add Events
    [newButton addTarget:self action:@selector(showScanner:) forControlEvents:UIControlEventTouchUpInside];
    // in case the parent view draws with a custom color or gradient, use a transparent color
    [newButton setBackgroundColor:[UIColor clearColor]];  
    // Set titleShadowColor this way (apparently, titleLabel.shadowcolor does not work)
    [newButton setTitleShadowColor:[UIColor colorWithRed:0.0f/255.0 green:0.0f/255.0 blue:0.0f/255.0 alpha:.75] forState:UIControlStateNormal & UIControlStateHighlighted & UIControlStateSelected];

    // Set button titleLabel properties  
    newButton.titleLabel.font = [UIFont fontWithName:@"PTSans-Bold" size:13.0];
    newButton.titleLabel.shadowOffset = CGSizeMake(1, 1);    

    [fullView addSubview:newButton];
}

- (void)showScanner:(id)sender
{
    NSLog(@"Do something…");
}

enter image description here

Upvotes: 1

Views: 531

Answers (2)

joerick
joerick

Reputation: 16458

You're not keeping a reference to your view controller. You either need to

  • use a standard iOS view controller manager like UITabBarController or UINavigationController to display your views
  • keep a reference (in an instance variable) to this view controller within the class that you opened it from.

Note that if you were to re-write this code with ARC turned off, you'd have a memory leak, instead of a crash.

The problem is that all references to the view controller from the view are weak references, meaning that they don't retain the controller*. So in your loading code ARC releases the view controller after you've made it and accessed its view, and it's gone.

Within your app you should keep track of all the view controllers, and access their views through them. Something like UINavigationController does this for you.

*This is because the view controller is considered to have ownership over the view, and if the view controller retained the view and the view retained the view controller, there'd be a retain loop, and neither of them would ever be released.

Upvotes: 0

chown
chown

Reputation: 52788

I believe UIControlState's cannot be & (or |) together because according to the UIControl Reference Docs:

a control can have more than one state at a time.

Try separating them out like this:

// Set button title
[newButton setTitle:@"Do Something" forState:UIControlStateNormal];
[newButton setTitle:@"Do Something" forState:UIControlStateHighlighted];
[newButton setTitle:@"Do Something" forState:UIControlStateSelected];

// Set button title color
[newButton setTitleColor:[UIColor colorWithRed:255.0f/255.0 green:255.0f/255.0 blue:255.0f/255.0 alpha:1.0] forState:UIControlStateNormal];
[newButton setTitleColor:[UIColor colorWithRed:255.0f/255.0 green:255.0f/255.0 blue:255.0f/255.0 alpha:1.0] forState:UIControlStateHighlighted];
[newButton setTitleColor:[UIColor colorWithRed:255.0f/255.0 green:255.0f/255.0 blue:255.0f/255.0 alpha:1.0] forState:UIControlStateSelected];

// Add the background image
[newButton setBackgroundImage:blackButton forState:UIControlStateNormal];

// Add Events
[newButton addTarget:self action:@selector(showScanner:) forControlEvents:UIControlEventTouchUpInside];

// in case the parent view draws with a custom color or gradient, use a transparent color
[newButton setBackgroundColor:[UIColor clearColor]];  

// Set titleShadowColor this way (apparently, titleLabel.shadowcolor does not work)
[newButton setTitleShadowColor:[UIColor colorWithRed:0.0f/255.0 green:0.0f/255.0 blue:0.0f/255.0 alpha:.75] forState:UIControlStateNormal];
[newButton setTitleShadowColor:[UIColor colorWithRed:0.0f/255.0 green:0.0f/255.0 blue:0.0f/255.0 alpha:.75] forState:UIControlStateHighlighted];
[newButton setTitleShadowColor:[UIColor colorWithRed:0.0f/255.0 green:0.0f/255.0 blue:0.0f/255.0 alpha:.75] forState:UIControlStateSelected];

// Set button titleLabel properties  
newButton.titleLabel.font = [UIFont fontWithName:@"PTSans-Bold" size:13.0];
newButton.titleLabel.shadowOffset = CGSizeMake(1, 1);

It may be crashing because button should be newButton.

Change this:

[button setTitleShadowColor:[UIColor colorWithRed:0.0f/255.0 green:0.0f/255.0 blue:0.0f/255.0 alpha:.75] forState:UIControlStateNormal & UIControlStateHighlighted & UIControlStateSelected];

To this:

[newButton setTitleShadowColor:[UIColor colorWithRed:0.0f/255.0 green:0.0f/255.0 blue:0.0f/255.0 alpha:.75] forState:UIControlStateNormal & UIControlStateHighlighted & UIControlStateSelected];

Upvotes: 3

Related Questions