2

While working through examples presented by Mark and LeMarche, I have encountered a number of situations where things don't work as expected. For example, Chapter 4 discusses 'Spiffing up a button' with an image. I can't seem to get an image stretched on the button, despite the fact that I followed the original instructions and a number of work arounds [1,2,3].

How does one determine the error encountered in a Objective C method which returns void? (IMHO, a useless paradigm). Guessing at the culprit or error is a useless waste of time, and its not working well for me.

Sorry about being snippy - I am at wits end, and I am tired of all the printf's, NSLogs, and guessing. This is no way to develop programs.

Jeff


[1] Resizing an image with stretchableImageWithLeftCapWidth

[2] stretchableImageWithLeftCapWidth:topCapHeight doesn't work in initWithCoder: of UIImageView subclass

[3] iPhone stretchableImageWithLeftCapWidth only makes "D"s


// Source code from Mark and LeMarch ('Beginning iPhone 4 Programming', Chapter 4, pp. 99-100)
// added for completeness. The same code is presented in 'Beginning iPhone 3 Programming'.
// The button type is 'Custom', and the mode is 'Scale to Fill'. Trying to use TIFFs,
// removing Alpha channels, resizing buttons so their size is image.height+1, etc - no joy.
// The buttons were provided by Apple in their UICatalog example (http://developer.apple.com/library/ios/#samplecode/UICatalog/Introduction/Intro.html).
// I've also tried to assign the image to a single button in case the resource cannot be shared.
// Finally, no ASSERTs fire (and no exceptions are thrown), so all should be OK (yea, right).
- (void)viewDidLoad
{   
    [super viewDidLoad];

    UIImage* whiteButton = [UIImage imageNamed:@"whiteButton.png"];
    ASSERT(whiteButton != nil);

    UIImage* strechableWhiteButton = [whiteButton stretchableImageWithLeftCapWidth:12.0 topCapHeight:0.0];
    ASSERT(strechableWhiteButton != nil);

    [changeSrcFileButton setBackgroundImage:strechableWhiteButton forState:UIControlStateNormal];
    [changeDestFileButton setBackgroundImage:strechableWhiteButton forState:UIControlStateNormal];

    UIImage* blueButton = [UIImage imageNamed:@"blueButton.png"];
    ASSERT(blueButton != nil);

    UIImage* strechableBlueButton = [blueButton stretchableImageWithLeftCapWidth:12 topCapHeight:0];
    ASSERT(strechableBlueButton != nil);

    [changeSrcFileButton setBackgroundImage:strechableBlueButton forState:UIControlStateHighlighted];
    [changeDestFileButton setBackgroundImage:strechableBlueButton forState:UIControlStateHighlighted];
}
Community
  • 1
  • 1
jww
  • 97,681
  • 90
  • 411
  • 885
  • If guessing at the problem is a waste of time for you, imagine how hard it is for us when you don't even show your code! ;-) I understand that you might be asking about more than just the example you give, but then why the three references? – Caleb Mar 11 '11 at 08:37
  • Hi Caleb - I'm more interested in the general (i.e., how to retrieve an error code form somewhere when something goes wrong). This way, I can fix most of my problems without wasting the time of folks on Stack Overflow. Jeff – jww Mar 11 '11 at 11:40
  • 1
    Where is the `ASSERT(changeSrcFileButton != nil);`? – Matthias Bauch Mar 11 '11 at 12:18
  • Hi fluchtpunkt - Good point. It will be added (its also an IBOutlet, just in case). I can tell you that it is not nil. Jeff – jww Mar 11 '11 at 12:47
  • Last words of a programmer that forgot to connect some IBOutlets? - "I can tell you that it is not nil". - Just joking. But if they are really not nil I could partly understand your rant. – Matthias Bauch Mar 11 '11 at 12:51
  • "Last words of a programmer that forgot to connect some IBOutlets?" You are right - famous last words. I just confirmed the buttons were connected. On a side note, I've got two Text Boxes (also IBOutlets) that I can't seem to get connected under IB. Perhaps there are some wires crossed with IB (and a delegate I tried to recently remove). – jww Mar 11 '11 at 13:40

1 Answers1

2

You're really asking two questions here, I think: "How do you stretch an image on a button?" and "What do you do when code doesn't work?" I'll take the former first. The following code works for me to create a button from scratch with a stretched image:

UIImage *image = [[UIImage imageNamed:@"ButtonPic"] stretchableImageWithLeftCapWidth:19 topCapHeight:19];
CGRect frame = CGRectMake(80, 200, 160, 40);
UIButton *button = [[UIButton alloc] initWithFrame:frame];
[button setBackgroundImage:image forState:UIControlStateNormal];
[self.view addSubview:button];
[button release];

You'll need to supply an appropriate image, naturally. My image is a 80x40 px PNG image created in Photoshop, stretched to a width of 160 px above. Here's what it looks like:

button screenshot

I don't see any significant differences between my code and the code in the book. It looks like the button in the book is loaded from a nib instead of created programmatically, but mine and theirs both call -stretchableImageWithleftCapWidth:topCapHeight: and -setBackgroundImage:forState: to do the relevant work.

That brings us to the second question: "What do you do when code doesn't work?"

There's not a single answer here, but the first thing to do is narrow the problem as much as you can. Arthur Conan Doyle wrote: "Once you eliminate the impossible, whatever remains, no matter how improbable, must be the truth." In a case like this one, where you've just got a few lines of code, an easy way to do that is to isolate the problematic code by copying it into a new project. It only takes a moment to create a new iOS project based on the view template, and you can paste the code above into the -viewDidLoad method of the supplied view controller to try it out. Then all you need to do is to supply an image. If it still doesn't work, you've removed all the other code in your app from suspicion. If it does work, you can gradually add some more code from your app in an attempt to reproduce the problem and identify the cause. Moving your code to a test project isn't always feasible, but you can usually find ways to simplify the problem.

As far as errors go, bear in mind that code often fails even when every function and method succeeds. The problem isn't with the components, but with how they're put together.

Caleb
  • 124,013
  • 19
  • 183
  • 272
  • Hi Caleb - "There's not a single answer here, but the first thing to do is narrow the problem as much as you can". In Windows, I check a BOOL. If the result is false, I call `GetLastError`. In Linux, I check a INT. If the result is < 0, I check `errno`. What method does the world's "Most Advanced Operating System" (per Apple's literature) provide to check for the result of a function call/method? The best I can tell, the only thing I can do is wait to see if the widget draws properly. If it does not draw properly, I have to grep Stack Overdlow looking for the right knobs to turn. Jeff – jww Mar 11 '11 at 12:06
  • Hi Caleb - "There's not a single answer here, but the first thing to do is narrow the problem as much as you can". I'm not trying to beat a dead horse, but there *must* be a single answer. If there were not, how can a program tell there is an error, and how can a program determine an irrecoverable state where it must not process any further? Sorry to beat a dead horse (I'm kinda worked up about this). Jeff – jww Mar 11 '11 at 12:16
  • 1
    I answered your original question to the best of my ability, and I'm now sorry that I invested the time that I did responding to what seems to be more a rant than a real question. Mechanisms for reporting errors at the various levels of API are well documented, from errno to NSError to NSException, and if you're asking in earnest I invite you to visit the documentation. Also, feel free to post your code -- I'm sure someone will spot your error in a minute or two. – Caleb Mar 11 '11 at 13:42
  • "I'm now sorry that I invested the time that I did responding to what seems to be more a rant than a real question" - Please don't feel that way. I'm new to the platform (but I have considerable time on other platforms), and I assumed that there was a way to detect errors and exceptional conditions at runtime. Obviously, my assumption was wrong (otherwise, you would have told me to 'call function XXX'). I blame Apple for the crippled implementation and missing functionality. Thank you for your time. Jeff – jww Mar 11 '11 at 14:11
  • And sorry about distracting you with a particular instance of a problem - I was interested in the general solution to 'detecting errors and exceptional conditions at runtime.' Jeff – jww Mar 11 '11 at 14:15