27

I'm losing my mind over this one. I have UIButton connected as Outlet. I want to change it's image. In the viewDidLoad function, I try to set the image like so:

[button1 setImage:[UIImage imageNamed:@"house.png"] forState:UIControlStateNormal];

Nothing happens. However, if I use ImagePicker, it somehow works. In the ImagePickers function "didFinishPickingImage", I repeat the exactly same command as above for setting image and it works, the image is displayed normally.

I've been thinking that maybe the button's image is not refreshing itself, but trying to call [button1 setNeedsDisplay], or [button1.imageView setNeedsDisplay] or even [button1.imageView.image setNeedsDisplay] does nothing.

Does anyone have any idea about this? I've wasted two hours by now and I'm really getting frustrated, because I'm certain that the reason must be so stupid it's unbelivable.

detra83
  • 739
  • 1
  • 7
  • 10
  • 1
    Just a heads-up: I believe the method you reference in your question has been [deprecated since iOS 3.0](http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIImagePickerControllerDelegate_Protocol/DeprecationAppendix/AppendixADeprecatedAPI.html#//apple_ref/occ/intfm/UIImagePickerControllerDelegate/imagePickerController:didFinishPickingImage:editingInfo:). – esqew Jan 27 '12 at 00:52
  • Split out the `UIImage` call and NSLog it, make sure it's not nil? It fails silently if it is. – smparkes Jan 27 '12 at 00:54
  • 1
    Hmmm, try putting the same code in viewWillAppear instead. It sounds like for whatever reason, "button1" is still nil when you run the code. You could check this - set a breakpoint when this line is called, and what is the value of Button1? – Jordan Smith Jan 27 '12 at 00:58
  • I didn't know about deprecation, thanks for the info. – detra83 Jan 27 '12 at 01:04
  • I just found if an UILabel object contains an UIButton directly that will cause the same issue, moving the UIButton to UIView solved it. Good luck! – Itachi Feb 08 '16 at 15:56
  • @esqew The code is not deprecated. https://developer.apple.com/documentation/uikit/uiimage/1624146-imagenamed – Naveed Abbas Aug 30 '19 at 06:41

14 Answers14

98

Please check your button type.

If your button type is "System" you should change it to "Custom"

Vlad
  • 3,465
  • 1
  • 31
  • 24
10

Two things to do here:

#1, change your code to:

[button1 setImage:[UIImage imageNamed:@"house.png"] forState:UIControlStateNormal];

and #2

make sure your UIImage returns a valid image.

In other words,

UIImage * imageToSet = [UIImage imageNamed: @"house.png"];
if(imageToSet)
{
    [button1 setImage:[UIImage imageNamed:@"house.png"] forState:UIControlStateNormal];
} else {
    // if you see this line in your console, then you know where to look for a problem
    NSLog( @"why is my image object nil?");
}
Michael Dautermann
  • 88,797
  • 17
  • 166
  • 215
  • 1
    For #1, I don't see how your code is different from the original? – Jordan Smith Jan 27 '12 at 01:01
  • Ok, figured it out, sorry for the panic attack. The button was inside table cell and the cell wasn't loaded/created yet at the viewWillAppear state, so the button was still nil at that stage. I've moved the code for loading image inside the "cellForRowAtIndexPath" function – detra83 Jan 27 '12 at 01:02
  • 1
    Hi @Jordan; before the o.p. edited his question he was using a slightly different way to call the `forState` parameter of the `setImage` method. Clicking on "edited" link under the question will show what the original looked like. And I'm glad everything worked out well. – Michael Dautermann Jan 27 '12 at 01:07
  • @MichaelDautermann ah makes sense :) detra83 - glad you've solved the problem! But not sure that this answer should be the accepted solution, as it wasn't this answer that solved you problem. Since it might be misleading to others who have the same issue and look at this answer (because it is the 'accepted' answer), it's probably best to write your own answer with your solution and accept that instead :) – Jordan Smith Jan 27 '12 at 01:16
  • Yes, the first version had a typo. I was actually using it like I've edited my post, but I didn't spot the typo right away. @Jordan: I will correct it, but due to my reputation, I can't accept my own answer until 7 or so hours have passed, so I will have to do it tomorrow. Thanks for the heads up. – detra83 Jan 27 '12 at 01:34
8

For anyone who will find themselves in a similar situation; I was using the mentioned button inside a custom cell for table view. However, the cells aren't loaded right away (i.e. inside viewDidLoad/viewWillAppear etc.), but inside the tableView:cellForRowAtIndexPath function. All my button variables were nil at that point. My solution was to load the image after the cell has been created and it has worked straight away afterwards.

detra83
  • 739
  • 1
  • 7
  • 10
3

Here are a couple additional notes. UIButton setImage: forState: is the correct method:

[button1 setImage:[UIImage imageNamed:@"house.png"] forState:UIControlStateNormal];

imageNamed is a great convenience method for grabbing the image, but make sure it returns an object. Forgetting to include the image file in the current target gets me all of the time.

[UIImage imageNamed:@"house.png"] 

You also don't need the extension. The SDK works this out.

[UIImage imageNamed:@"house"] 

And even though UIControlState is a bit mask, you cannot OR the values together. This does not not not work and I must must must remember this because it gets me every time I use the call.

// NO NO NO
[button1 setImage:[UIImage imageNamed:@"house"] forState:UIControlStateNormal|UIControlStateSelected]; 

// YES
[button1 setImage:[UIImage imageNamed:@"house"] forState:UIControlStateNormal];
[button1 setImage:[UIImage imageNamed:@"house"] forState:UIControlStateSelected]; 
Dan Loughney
  • 4,647
  • 3
  • 25
  • 40
  • The masking works for me in Swift 1.2 + Xcode 6.4 like this: button.setImage(filledStarImage, forState: UIControlState.Highlighted|UIControlState.Selected) – Bijan Aug 12 '15 at 13:29
2

Was getting the same problem when UIbutton was in UITableViewCell.

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:[UIImage imageNamed:@"detail.png"] forState:UIControlStateNormal];

should work in UITableViewCell

Shamsiddin Saidov
  • 2,281
  • 4
  • 23
  • 35
Wasim
  • 921
  • 12
  • 14
2

Glad to know that the problem is solved but none of the answers actually addresses the problem.

Generally, if the code is correct, then the error shifts from "syntax error" to the "logical error" category. There is no definite guide to handle it but here is a small checklist that can help anyone to troubleshoot their code.

1) The IBOutlet is not connected or renamed.

2) Make sure that the UIButton type is custom.

3) The image is set (more than once), somewhere else in the code.

4) You are trying to set the Image through any sync method which is not using the main thread. (There are several threads on that alone).

5) If you are nesting the images as subviews, make sure the problem isn't with their parent view.

6) If it is appearing in Simulator but not in the device, It's a lettercase (Uppercase, lowercase difference in the code and the filename.

7) Modern simulators works with very low GPU memory on older machines. You can tweak the simlator options to make it appear. E.g (Command + Right Arrow) twice to change the simulator orientation and your changes will appear.

There are few other but common pitfalls where developers usually overlook

1) The image doesn't exist OR you are making a spelling mistake.

2) The filetype is different than mentioned. (JPG, PNG).

Naveed Abbas
  • 1,157
  • 1
  • 14
  • 37
1

Last thing you'll want to check - make sure you're setting the image on the main thread! Just ran into an issue where I was setting a button image in a callback from ALAssetLibrary (fetching images from photo library). The image wouldn't update until I tapped the button. Turns out the callback was happening off main...

tyler
  • 2,865
  • 1
  • 23
  • 28
1

for those having issues with system images not appearing, just use systemName: instead of named

if let starImg = UIImage(systemName: "star.fill") {
    button.setImage(starImg, for: .normal)
}

It's for ios13 and later...

vomi
  • 993
  • 8
  • 18
0

For me it was to move the line:

[button1 setImage:[UIImage imageNamed:@"house.png"] forState:UIControlStateNormal];

from awakeFromNib method

to viewDidLoad method

evya
  • 3,381
  • 1
  • 25
  • 28
0

I guess, don't create like this UIButton *nextButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; by this create method ,UIButton is create by use default type,so your background image is not work. try this, UIButton *nextButton = [[UIButton alloc] initWithFrame:CGRectMake(9, 154, 300, 48)]; or other,except buttonWithType

0

This is happening because the state of the Button doesn't stays selected once clicked by default. I solved it by making an IBaction on that button click and toggling the selected state. -(IBAction) checkButtonClicked:(id)sender{ checkButton.selected = !checkButton.selected; }

palzarena
  • 1
  • 1
0

In my case, it is drawn by custom animation code and not set by the image, so it doesn't work by setting any image, it has to change the animation code.

Yao Li
  • 2,071
  • 1
  • 25
  • 24
0

With images, you have to import them into the project not as references but as copies. So when you go to add files to project, choose "Create groups" instead of "Create folder references". Also make sure "Copy items if needed" is checked.

This is confusing because importing as references works when you are using images as textures (e.g. for Sprites). However, it doesn't work when you want to use images for buttons (e.g. for using image name in [UIImage imageNamed:@"house.png"]

Lenka Pitonakova
  • 979
  • 12
  • 14
0

I faced this same issue of the image not being shown on the UIButton.

I had to change this line -

myButton.setImage(<my_UIImage_object>, for: [.normal, .focused])

to this -

myButton.setImage(<my_UIImage_object>, for: .normal)
Dhruv Saraswat
  • 858
  • 9
  • 13