How can I store UIButtons in an array? - iphone

I have a method tied to four buttons. I want to create an array containing each button, and later retrieve and interact w/ a button from the array. The code I was tinkering with below. When I try to get a button from the array and send it a message, it goes kablooie.
Any thoughts on what I'm doing wrong?
Hack_DumpViewController.h
#import <UIKit/UIKit.h>
#interface Hack_DumpViewController : UIViewController {
IBOutlet UIButton *redButton;
IBOutlet UIButton *greenButton;
IBOutlet UIButton *blueButton;
IBOutlet UIButton *yellowButton;
NSArray *buttonMapping;
}
- (IBAction) changeToYo:(id)sender;
#property (nonatomic, retain) UIButton *redButton;
#property (nonatomic, retain) UIButton *greenButton;
#property (nonatomic, retain) UIButton *blueButton;
#property (nonatomic, retain) UIButton *yellowButton;
#property (nonatomic, retain) NSArray *buttonMapping;
#end
Hack_DumpViewController.m
#import "Hack_DumpViewController.h"
#implementation Hack_DumpViewController
#synthesize redButton;
#synthesize greenButton;
#synthesize yellowButton;
#synthesize blueButton;
#synthesize buttonMapping;
- (IBAction) changeToYo:(id)sender {
NSLog(#"changing numbers!");
for (UIButton *b in buttonMapping) {
[b setTitle:#"yo!"];
}
NSLog(#"changed to numbers!");
}
- (void)viewDidLoad {
buttonMapping = [[NSArray alloc] initWithObjects:greenButton, redButton, yellowButton, blueButton, nil];
}

[NSArray arrayWithObjects:...] returns an autoreleased array, so by the time you use it, it no longer exists and you end up messaging an invalid pointer. What you want is [[NSArray alloc] initWithObjects:...] (remembering to release it in your dealloc).

Why not tag the views in interface builder and then treat them like an array, much easier

Related

Memory leak vs Zombie - iPhone

My iPhone app is either crashing due to to a zombie, or leaking memory.. I've narrowed it down to 3 lines of code and can reliably get one of the two things to happen by commenting/uncommenting the code. The bugs occur when navigation between a list of results (tableView) and a details page containing a map and a few labels, memory leak happens the first time I navigation from the map back to the list of results, the zombie occurs after maybe 5/6 times navigating to different results and back.
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#define METERS_PER_MILE 1609.344
#interface ResDetailsPageVC : UIViewController <MKMapViewDelegate, UIAlertViewDelegate> {
UISegmentedControl *mapTypeSwitcher;
MKMapView *mapView;
UILabel *nameLabel;
UIButton *addressLabel;
UILabel *telephoneLabel;
NSString *address;
}
#property (nonatomic, retain) IBOutlet UISegmentedControl *mapTypeSwitcher;
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
#property (nonatomic, retain) IBOutlet UILabel *nameLabel;
#property (nonatomic, retain) IBOutlet UIButton *addressLabel;
#property (nonatomic, retain) IBOutlet UILabel *telephoneLabel;
- (IBAction)segmentedControlIndexChanged;
- (IBAction)callButtonClick;
- (IBAction)addressClick;
- (void) callNumber;
#end
#synthesize mapView;
#synthesize mapTypeSwitcher;
#synthesize nameLabel, addressLabel, telephoneLabel;
- (void)dealloc {
// if these lines are commented out - memory leak
// if not - zombie?!
/*self.telephoneLabel = nil;
self.addressLabel = nil;
self.nameLabel = nil;*/
self.mapView = nil;
self.mapTypeSwitcher = nil;
[super dealloc];
}
Somewhere some other piece of code is using the same object whose address is stored in one of those three properties, but that other piece of code has not properly retained the object.
I recommend this to you:
- (void)dealloc {
[telephoneLabel release]; telephoneLabel = nil;
[addressLabel release]; addressLabel = nil;
....
[super dealloc];
}

Calling a function in viewcontroller from appdelegate

I want to call a function in a viewController from my appDelegate but with the following code, it doesn't get called. What am I doing wrong?
AppDelegate.h:
#import <UIKit/UIKit.h>
#import "DetailsToTransfer.h"
#class AccountDetailTransferViewController;
#interface AccountDetailTransferAppDelegate : NSObject <UIApplicationDelegate> {
DetailsToTransfer *objDetailsToTransfer;
}
#property (nonatomic, retain) DetailsToTransfer *objDetailsToTransfer;
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet AccountDetailTransferViewController *viewController;
-(void)sendToTransferScreen:(NSArray *)detailsArray;
#end
AppDelegate.m:
....
-(void)sendToTransferScreen:(NSArray *)detailsArray {
[objDetailsToTransfer setLabels:detailsArray];
objDetailsToTransfer = [[DetailsToTransfer alloc]initWithNibName:#"DetailsToTransfer" bundle:nil];
[self.window addSubview:objDetailsToTransfer.view];
}
DetailsToTransfer.h:
#import <UIKit/UIKit.h>
#interface DetailsToTransfer : UIViewController {
NSArray *accountDetailsArray;
UILabel *nameLabel;
UILabel *accountLabel;
IBOutlet UIButton *btnTransfer;
IBOutlet UIButton *btnBack;
}
#property (nonatomic, retain) NSArray *accountDetailsArray;
#property (nonatomic, retain) IBOutlet UILabel *nameLabel;
#property (nonatomic, retain) IBOutlet UILabel *accountLabel;
-(IBAction)sendDetails;
-(IBAction)goBack;
-(void)setLabels:(NSArray *)array;
#end
DetailsToTransfer.m
....
-(void)setLabels:(NSArray *)array {
NSLog(#"Setting Labels");
self.nameLabel.text = [array objectAtIndex:0];
self.accountLabel.text = [array objectAtIndex:1];
}
....
I would like to add that all the properties have been synthesized and that I'm calling the method in the appDelegate properly (i checked using NSLogs)
In AppDelegate.m:
Looks as if you are calling a method on your object before the object has been created. Until you have alloc / init your object, there will be no labels to set text.
Try changing your method to this:
-(void)sendToTransferScreen:(NSArray *)detailsArray {
if (!objDetailsToTransfer) {
objDetailsToTransfer = [[DetailsToTransfer alloc]initWithNibName:#"DetailsToTransfer" bundle:nil];
[objDetailsToTransfer setLabels:detailsArray];
[self.window addSubview:objDetailsToTransfer.view];
}
}
The problem might be that you are trying to set the values on a object that hasn't been created yet. I also provided an if statement to prevent the object from being created multiple times.

Play a sound based on the button pressed on the IPhone/xcode

I'm trying to play a sound based on which button is pressed using AVAudioPlayer.
(This is not a soundboard or fart app.)
I have linked all buttons using this code in the header file:
#interface appViewController : UIViewController <AVAudioPlayerDelegate> {
AVAudioPlayer *player;
UIButton *C4;
UIButton *Bb4;
UIButton *B4;
UIButton *A4;
UIButton *Ab4;
UIButton *As4;
UIButton *G3;
UIButton *Gb3;
UIButton *Gs3;
UIButton *F3;
UIButton *Fs3;
UIButton *E3;
UIButton *Eb3;
UIButton *D3;
UIButton *Db3;
UIButton *Ds3;
UIButton *C3;
UIButton *Cs3;
}
#property (nonatomic, retain) AVAudioPlayer *player;
#property (nonatomic, retain) IBOutlet UIButton *C4;
#property (nonatomic, retain) IBOutlet UIButton *B4;
#property (nonatomic, retain) IBOutlet UIButton *Bb4;
#property (nonatomic, retain) IBOutlet UIButton *A4;
#property (nonatomic, retain) IBOutlet UIButton *Ab4;
#property (nonatomic, retain) IBOutlet UIButton *As4;
#property (nonatomic, retain) IBOutlet UIButton *G3;
#property (nonatomic, retain) IBOutlet UIButton *Gb3;
#property (nonatomic, retain) IBOutlet UIButton *Gs3;
#property (nonatomic, retain) IBOutlet UIButton *F3;
#property (nonatomic, retain) IBOutlet UIButton *Fs3;
#property (nonatomic, retain) IBOutlet UIButton *E3;
#property (nonatomic, retain) IBOutlet UIButton *Eb3;
#property (nonatomic, retain) IBOutlet UIButton *D3;
#property (nonatomic, retain) IBOutlet UIButton *Db3;
#property (nonatomic, retain) IBOutlet UIButton *Ds3;
#property (nonatomic, retain) IBOutlet UIButton *C3;
#property (nonatomic, retain) IBOutlet UIButton *Cs3;
- (IBAction) playNote;
#end
Buttons are all linked to the event "playNote" in interfaceBuilder and each note is linked to the proper referencing outlet according to note name.
All *.mp3 sound files are named after the UIButton name (IE- C3 == C3.mp3).
In my implementation file, I have this to play a only one note when the C3 button is pressed:
#import "sonicfitViewController.h"
#implementation appViewController
#synthesize C3, Cs3, D3, Ds3, Db3, E3, Eb3, F3, Fs3, G3, Gs3, A4, Ab4, As4, B4, Bb4, C4;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
NSString *path = [[NSBundle mainBundle] pathForResource:#"3C" ofType:#"mp3"];
NSLog(#"path: %#", path);
NSURL *file = [[NSURL alloc] initFileURLWithPath:path];
AVAudioPlayer *p = [[AVAudioPlayer alloc]
initWithContentsOfURL:file error:nil];
[file release];
self.player = p;
[p release];
[player prepareToPlay];
[player setDelegate:self];
[super viewDidLoad];
}
- (IBAction) playNote {
[self.player play];
}
Now, with the above I have two issues:
First, the NSLog reports NULL and crashes when trying to play the file. I have added the mp3's to the resources folder and they have been copied and not just linked. They are not in an subfolder under the resources folder.
Secondly, how can I set it up so that when say button C3 is pressed, it plays C3.mp3 and F3 plays F3.mp3 without writing duplicate lines of code for each different button? playNote should be like
NSString *path = [[NSBundle mainBundle] pathForResource:nameOfButton ofType:#"mp3"];
instead of defining it specifically (#"C3").
Is there a better way of doing this and why does the *path report NULL and crash when I load the app?
I'm pretty sure it's something as simple as adding additional variable inputs to - (IBAction) playNote:buttonName and putting all the code to call AVAudioPlayer in the playNote function but I'm unsure of the code to do this.
Performing multiple actions with same selector is a common task. Just set a tag property for each button and use a NSArray of NSStrings to store file names. Your even need not create each button separately. See code sample for similar question problem with selector in iphone? answer.
Check if your files is realy copied to bundle. For example in simulator
log your bundle directory with NSLog(#"myBundle:%#",[[NSBundle mainBundle] bundlePath]);
and look at files.

iPhoneSDK : view is not loading data for the first time but loads it subsequently

I am trying to load a UIView with multiple data. The problem is data is not displays in first load but loads it in subsequent clicks. Can you help me trace the problem.
FirstViewController.h
#import <UIKit/UIKit.h>
#class SecondViewController;
#interface FirstViewController : UIViewController {
IBOutlet SecondViewController *mySecondViewController;
IBOutlet UIImageView *myimage1;
IBOutlet UIImageView *myimage2;
IBOutlet UILabel *mylabel1;
IBOutlet UILabel *mylabel2;
}
#property (nonatomic, retain) IBOutlet SecondViewController *mySecondViewController;
#property (nonatomic, retain) IBOutlet UIImageView *myimage1;
#property (nonatomic, retain) IBOutlet UIImageView *myimage2;
#property (nonatomic, retain) IBOutlet UILabel *mylabel1;
#property (nonatomic, retain) IBOutlet UILabel *mylabel2;
- (IBAction)bringNextView:(id)sender;
- (IBAction)bringNextView2: (id)sender;
#end
FirstViewController.m
#import "FirstViewController.h"
#import "SecondViewController.h"
#implementation FirstViewController
#synthesize mySecondViewController,myimage1, myimage2, mylabel1, mylabel2;
- (IBAction)bringNextView:(id)sender {
mySecondViewController.name.text = #"Paul";
mySecondViewController.myimageview.image = [UIImage imageNamed:#"Paul.png"];
mySecondViewController.statmsg.text = #"Doing iPhone Development";
[[self navigationController] pushViewController:mySecondViewController animated:YES];
}
SecondViewController.m
#import "SecondViewController.h"
#implementation SecondViewController
#synthesize myimageview, name, statmsg
- (void)viewDidLoad {
[self setTitle:#"Details"];
[super viewDidLoad];
}
Properties are not coming for the first time. But are displays after returning from view and then loading view again.
I am loading SecondViewController from FirstViewController.
Hi I have solved this. Actually I was pushing my view controller after setting up the property and that caused this issue.
Instead of :
mySecondViewController.name.text = #"Paul";
mySecondViewController.myimageview.image = [UIImage imageNamed:#"Paul.png"];
mySecondViewController.statmsg.text = #"Doing iPhone Development";
[[self navigationController] pushViewController:mySecondViewController animated:YES];
It should be :
[[self navigationController] pushViewController:mySecondViewController animated:YES];
mySecondViewController.name.text = #"Paul";
mySecondViewController.myimageview.image = [UIImage imageNamed:#"Paul.png"];
mySecondViewController.statmsg.text = #"Doing iPhone Development";

iPhone UIImageView Array

So I'm declaring a NSMutableArray to hold 5 UIImageViews.
.h file:
#interface ImageDisplay : UIViewController {
IBOutlet UIImageView *img1;
IBOutlet UIImageView *img2;
IBOutlet UIImageView *img3;
IBOutlet UIImageView *img4;
IBOutlet UIImageView *img5;
NSMutableArray *imageHolderArray;
}
#property (nonatomic, retain) IBOutlet UIImageView *img1;
#property (nonatomic, retain) IBOutlet UIImageView *img2;
#property (nonatomic, retain) IBOutlet UIImageView *img3;
#property (nonatomic, retain) IBOutlet UIImageView *img4;
#property (nonatomic, retain) IBOutlet UIImageView *img5;
#property (nonatomic, retain) IBOutlet NSMutableArray *imageHolderArray;
#end
In the .m file:
//All objects are synthesized, just easier not to crowd the screen
- (void)viewDidLoad {
[super viewDidLoad];
imageHolderArray = [[NSMutableArray alloc] initWithObjects: img1,img2,img3,img4,img5,nil];
NSLog(#"imageHolderArray count: %i",[imageHolderArray count]); //Returns count of 1
}
So my question is, why is this happening? Why isn't it picking up all the objects in the Array? I'm not well versed in Objective-C programming so I'd appreciate it if someone could clue me in here. Thank you.
Because you didn't wire the IBOutlets to their views in Interface Builder. Looks like you probably wired img1, but didn't wire img2, so img2 is nil, which marks the end of your list of objects for -initWithObjects: even if later outlets are wired.