UIButton that cycles through images when clicked - iphone

I have three images that I want to cycle through when clicking on a UIButton.
How would I go about doing this?
This is what I have so far, but it's not really working.
//the images
NSString* imageNames[] = {"MyFirstImage", "AnotherImage", whatever else};
int currentImageIndex = 0;
and
- (IBAction)change{
UIImage* imageToShow = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource: imageNames[currentImageIndex] ofType:#"png"];
if( currentImageIndex++ == sizeof(imageNames)/sizeof(NSString)) //check to see if you hit the last image
{
currentImageIndex = 0; //start over
}
}
Ideas?
Any help will be greatly appreciated! Thanks!

Steven's suggestion to subclass UIButton is a good one. Once you get a some more experience with Objective C, you should consider his approach, but I can tell by the code you've posted that you're new to Objective C, so you may need to learn to use the basic Foundation classes first.
One reason your code isn't working is because you're trying to pass C string literals to pathForResource:, which requires an NSString object. NSStrings are objects in Objective C, not character pointers as they are in C. You can construct an NSString object using the literal syntax, #"quotes-with-an-at-in-front".
Here is code that implements the algorithm you attempted to write, using Objective C Foundation classes rather than C data types:
// YourController.h
#interface YourController : UIViewController {
NSArray *imageNames;
NSInteger currentImageIndex;
UIButton *yourButton;
}
#property (nonatomic, retain) NSArray *imageNames;
#property (nonatomic, retain) IBOutlet UIButton *yourButton; // Presumably connected in IB
- (IBAction)change;
#end
// YourController.m
#import "YourController.h"
#implementation YourController
#synthesize imageNames, yourButton;
- (void)dealloc {
self.imageNames = nil;
self.yourButton = nil;
[super dealloc];
}
- (void)viewDidLoad {
self.imageNames = [NSArray arrayWithObjects:#"MyFirstImage", #"AnotherImage", nil];
currentImageIndex = 0;
[super viewDidLoad];
}
- (IBAction)change {
UIImage* imageToShow = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:[imageNames objectAtIndex:currentImageIndex] ofType:#"png"];
currentImageIndex++;
if (currentImageIndex >= imageNames.count) {
currentImageIndex = 0;
}
[yourButton setImage:imageToShow forState:UIControlStateNormal];
}
#end

You will want to subclass UIButton and add a new property that maintains state. You will also want to have three properties to maintain the images of the three new states. Then in your "drawRect:" method, swap out the standard buttons images based on your state and then call the [super drawRect:] method.

Related

Storing and opening data in a variable

I'm making an app that calculates certain things.
I need it to be able to take the input from the first textfields, for example 4+4 and save the result in a variable.
In the second text fields there could be 8+8 for example, and the result of that will also be saved into a variable (possibly the same).
Third row of textfields could yield more numbers etc, etc..
In the end there will be a button "Calculate" for example. And that will take the results from first, second, third etc textfields and calculate all of those together and output the end result.
The calculations are of course more advanced than this, but I just need the basic/simple idea of how to do this.
There is no need for saving the data to a file just now, it should just be in the app while the other textfields are being filled.
For 0x8badf00d:
Header.
#interface UnitConverterViewController : UIViewController {
NSMutableArray *calculationsArray;
UITextField *m1Text;
UITextField *m2Text;
}
#property (nonatomic, retain) IBOutlet UITextField *m1Text;
#property (nonatomic, retain) IBOutlet UITextField *m2Text;
#property (nonatomic, retain) IBOutlet NSMutableArray *calculationsArray;
#end
Implementation:
#implementation UnitConverterViewController
#synthesize m1Text, m2Text, calculationsArray;
#synthesize resultTotal = _resultTotal;
-(id)init {
if(self = [super init]){
calculationsArray = [[NSMutableArray alloc] init];
}
}
- (void)compute{
NSString* sumString = [NSString stringWithFormat:#"%d",[m1Text.text intValue]+[m2Text.text intValue]];
[calculationsArray addObject:sumString];
}
-(IBAction)calculate{
int total=0;
for(NSString* sumStr in calculationsArray){
total = total+[sumStr intValue];
}
NSLog(#"Total: %d", total);
[calculationsArray release], calculationsArray = nil;
}
I must be doing something wrong, and I know I need a way to output this, a label and such. But for now I need to know if what I've done so far is correct, and what the best way of outputting it would be.
You should declare the variables to store the results in your header file, these are than accessible from anywhere in your .m file, the same goes for your text fields.
For example:
Calculator.h
#interface Calculator: SuperclassName{
UITextField *_fldOne;
UITextField *_fldTwo;
UITextField *_fldThree;
UITextField *_fldFour;
int resultOne;
int resultTwo;
int _resultTotal;
}
#property(nonatomic, readonly) int resultTotal;
- (void) calculate;
#end
Calculator.m
#implementation Calculator
#synthesize resultTotal = _resultTotal;
- (void) calculate{
resultOne = [_fldOne.text intValue] * [_fldTwo.text intValue];
resultTwo = [_fldThree.text intValue] / [_fldFour.text intValue];
totalResult = resultOne + resultTwo;
}
#end
In this example resultOne and Two, and all the textfields are available throughout your class to work with, the totalResult is set as a readonly property and synthesized to create a getter automaticaly (which returns the value stored in _totalResult because of synchronizing like totalResult = _totalResult) as so it is available to read from outside the class.
As long as it all happens on one screen it should be more than enough, but of course you could make an NSDictionary or NSArray but that seems unnecessary here.
Hope this helps
Save the result to array. Lets say you have NSMutableArray* calculationsArray;//iVar
//initialize calculationsArray in init method
-(id)init
{
if(self = [super init])
{
calculationsArray = [[NSMutableArray alloc] init];
}
}
- (void)compute
{
NSString* sumString = [NSString stringWithFormat:#"%d",[textField1.text intValue]+[textField2.text intValue]);
[calculationsArray addObject:sumString];
}
- (IBAction)calculate
{
int total=0;
for(NSString* sumStr in calculationsArray)
{
total = total+[sumStr intValue];
}
NSLog(#"Total: %d",total);
[calculationsArray release],calculationsArray = nil;
}

Hiding all UILabels in NSMutableArray

I have various UILabels that I would like to hide using a for-loop.
#interface MyViewController : UIViewController {
NSMutableArray * labelArray;
}
#property (nonatomic, retain) IBOutlet UILabel *label1, *label2, *label3;
...
-(void)viewDidLoad {
[super viewDidLoad];
[labelArray initWithObjects:label1,label2,label3,nil];
for(int i=0; i<sizeof(labelArray); i++){
UILabel *label = [labelArray objectAtIndex:i];
label.hidden = !label.hidden;
}
}
When this is executed, the labels are not hidden. They have been "hooked up" in Interface Builder. What am I doing incorrectly? Thanks!
That is not what sizeof is for. That's a compiler construct that tells you how many bytes a value takes up, which has no clue how many elements are in an NSMutableArray at runtime. You want:
for (UILabel *label in labelArray) {
label.hidden = !label.hidden;
}
If that doesn't work, then your array does not contain the objects you believe it does — quite possibly, you've forgotten to actually create the array — simply sending init to nil does not create an object. Either way, you should probably be doing labelArray = [[NSMutableArray alloc] initWithObjects:label1,label2,label3,nil];. alloc and init go together hand-in-glove.

Problem With NSArray

i have the following code
#interface TestYourInfoViewController : UIViewController {
IBOutlet UIImageView * questionImage;
NSArray *historyQuestions;
int questionHistoryNo;
}
#property(nonatomic,retain) UIImageView * questionImage;
#property(nonatomic,retain) NSArray *historyQuestions;
#property int questionHistoryNo;
-(IBAction)solution:(id)sender;
#end
- (void)viewDidLoad
{
NSArray* array = [[NSArray alloc]init];
historyQuestions = array;
historyQuestions=UmRandomOrder(49, 1, 0);
questionImage.image = [UIImage imageNamed:[NSString stringWithFormat:#"h%#.jpg",[self.historyQuestions objectAtIndex:0]]];
[array release];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
-(IBAction)solution:(id)sender{
questionHistoryNo= questionHistoryNo+1;
questionImage.image = [UIImage imageNamed:[NSString stringWithFormat:#"h%#.jpg",[self.historyQuestions objectAtIndex:questionHistoryNo]]];
}
when i press the action button it gives me exception in the line [self.historyQuestions objectAtIndex:questionHistoryNo]
i believe the problem is in the nsarray somehow but i don't know what is it.. the exception is
can anyone help me ..
Actually DarkDust has it correct: the source code for UMRandomOrder shows that it properly returns an autorelease NSMutableArray. So, just change the first three lines of your viewDidLoad from:
NSArray* array = [[NSArray alloc]init];
historyQuestions = array;
historyQuestions=UmRandomOrder(49, 1, 0);
to just:
self.historyQuestions=UmRandomOrder(49, 1, 0);
And you'll be fine.
To be specific, there's no need to alloc/init/assign an array you're about to write over, and by using the property setter (self.historyQuestions = ), you'll automatically do a proper retain, as well as avoiding a potential memory leak. That also explains why it works in viewDidLoad (the autoreleased UmRandomOrder is still valid), but not in the action button (it has since been released).

Objective-c Novice - Needs help with animation

Im trying to add an animation of a monkey using a NSMutablAarray of UIImageViews. Im following a tutorial on youtube but when i compile i get a strange error: "stray '\357' in program." on the line "UIImage *img = [UIImage imageName: pictureName];"
Here are my h and m files..
#import "WinGameView.h"
#implementation WinGameView
#synthesize monkeyAnimation;
#synthesize monkeyImages;
-(IBAction)pushBack{
[self dismissModalViewControllerAnimated:YES];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
monkeyImages = [[NSMutableArray alloc] init];
for(int i = 1; i < 10; i++)
{
NSString *pictureName = [NSString stringWithFormat:#"monkey%d.gif",i];
UIImage *img = [UIImage imageName: pictureName];
if (img) [monkeyImages addObject:img];
}
[monkeyAnimation setAnimationImages:monkeyImages];
[monkeyAnimation setAnimationDuration:1.2f];
[monkeyAnimation startAnimating];
[super viewDidLoad];
}
and
#import <UIKit/UIKit.h>
#interface WinGameView : UIViewController {
IBOutlet UILabel *labelWin;
IBOutlet UILabel *labelWin2;
IBOutlet UIButton *buttonBack;
IBOutlet UIImageView *monkeyAnimation;
NSMutableArray *monkeyImages;
}
#property(nonatomic,retain)UIImageView *monkeyAnimation;
#property(nonatomic, retain)NSMutableArray *monkeyImages;
-(IBAction)pushBack;
#end
Does anyone know what i am doing wrong or why i am getting these wierd message. I have tried to look it up online but to no avail.
There is a stray "byte order mark" on that line (or even the line above or below). Retype the inside of the for loop by hand.

iPhone - SubClassing UIToolbar the right way?

I created a new Class named
CustomToolbar
Then i created an empty nib, added a
toolbar to it, and set the toolbar
class to "CustomToolbar".
What is the proper way of initializing CustomToolbar In code so that my class uses the nib file?
I already have written the code to do that but i know it's not the correct way and it has a leak.
#interface CustomToolbar : UIToolbar {
}
#property (nonatomic, retain) IBOutlet UIBarButtonItem *button;
#end
#implementation CustomToolbar
- (id)initWithDelegate
{
NSArray *objects = [[NSBundle mainBundle]
loadNibNamed:#"CustomToolbar"
owner:nil
options:nil];
if (self = (CustomToolbar*) [objects objectAtIndex:0])
{
//do some work here
}
return self;
}
#end
The NIB will call initWithCoder: on your custom class, like this:
- (id)initWithCoder:(NSDecoder*)aDecoder {
self = [super initWithCoder:aDecoder];
if( self ) {
// Do something
}
return self;
}
If you really want to load it the way you do now, you need to retain the object returned from loadNibNamed.