My UIPicker is crashing if the NSArray of objects is greater than 3, with the following error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSAutoreleasePool pickerView:titleForRow:forComponent:]: unrecognized selector sent to instance
Here is my code for the functions:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.glassPickerOptions = [[NSArray alloc] initWithObjects:#"3mm",#"4mm",#"DG4+4",#"DG4+6",nil];
[glassPicker setFrame:CGRectMake(0, 0, 320, 162)];
[glassPicker selectRow:1 inComponent:0 animated:NO];
}
- (NSInteger) numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
NSInteger glassPickerOptionsCount = self.glassPickerOptions.count;
NSLog(#"%i", glassPickerOptionsCount);
return glassPickerOptionsCount;
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return (NSString*) [self.glassPickerOptions objectAtIndex:row];
}
Hopefully I havent missed anything. Thanks in advance
It seems that you overrelease your picker view, you can see this because the message is being sent to an autoreleasepool and not the object you expect, you should check out your retain/releases for your picker see whats going on, cant really tell from the code posted...
Related
I'm trying to do a double picker, one part of text and the other with images. But the code gives me an error: Thread 1: Program received signal: "EXC_BAD_ACCESS". I can't see the trouble. Here is the code, Array content Images and Array2 content text. Thanks.
#synthesize Array, picker, Array2;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
UIImage *one = [UIImage imageNamed:#"6-12AM.png"];
UIImageView *oneView = [[UIImageView alloc] initWithImage:one];
NSArray *Array1 = [[NSArray alloc] initWithObjects:oneView, nil];
NSString *fieldName = [[NSString alloc] initWithFormat:#"Array"];
[self setValue:Array1 forKey:fieldName];
Array2 = [[NSArray alloc] initWithObjects:#"Hello", #"trouble", nil];
[super viewDidLoad];
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;
{
return 2;// giving number of components in PickerView
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent: (NSInteger)component;
{
return [self.Array2 count];// counting the number of rows in each component
}
#pragma mark Picker Delegate Methods
- (UIView *)pickerView:(UIPickerView *)pickerView
viewForRow:(NSInteger)row
forComponent:(NSInteger)component
reusingView:(UIView *)view
{
if (component == 1) {
return [self.Array objectAtIndex:row];
}
} //In this line is where the error occurs
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component; {
if (component == 0) {
return [self.Array2 objectAtIndex:row];
}
}
Your error is due to the fact that you do not offer an alternative to the if statement. A non-void function must return something in every case, so you need to provide an else statement in each one of your two functions that returns a value (like nil).
I dont see you allocating or initializing Array. Hence the bad access. Did you mean to use Array1?
Also several things:
Memory allocated several places never deallocated. Leaks all over
Variable names should start with small caps like array1, array2
[self setValue:Array1 forKey:fieldName]; //what is this doing?
I'm new to iOS dev, so this is probably easy to fix. I have a custom view controller in which I'm adopting the protocols to control a UIPickerView in a nib. Everything works fine unless, in the iPad simulator, I scroll the picker beyond the first item in the list or the last item in the list and release. It kicks the following error:
Thread 1: Program received signal: "EXC_BAD_ACCESS"
on this line of my main.m class:
int retVal = UIApplicationMain(argc, argv, nil, nil);
Relevant code follows:
ViewController.h
#interface BirdColorViewController : UIViewController <UIPickerViewDelegate, UIPickerViewDataSource> {
IBOutlet UIPickerView *birdColorPicker;
NSArray *birdColors;
}
#property (nonatomic,retain) IBOutlet UIPickerView *birdColorPicker;
Viewcontroller.m
- (void)dealloc
{
[birdColorPicker release];
[super dealloc];
}
...
- (void)viewDidLoad
{
[super viewDidLoad];
birdColors = [NSArray arrayWithObjects:#"Blue",#"Yellow",#"Red",nil];
birdColorPicker.delegate = self;
birdColorPicker.dataSource = self;
}
...
#pragma mark - UIPickerViewDataSource methods
//(UIPickerView *)thePickerView
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [birdColors count];
}
#pragma mark - UIPickerViewDelegate methods
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return [birdColors objectAtIndex:row];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
// Set value in prefs/model
}
Try:
birdColors = [[NSArray alloc] initWithObjects:#"Blue",#"Yellow",#"Red",nil];
instead of birdColors = [NSArray arrayWithObjects:#"Blue",#"Yellow",#"Red",nil];
Make birdColors a property also (nonatomic, retain) like you do with the pickerView.
Your array is not being retained, so you're accessing zombie memory.
Set NSZombieEnabled=YES in the properties/General panel of your Executable. That will tell you exactly what is being accessed.
I'm in a view that has a UIPickerView. Here is where I'm making my sortedArray.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSMutableArray *studentNames = [[NSMutableArray alloc] init];
for (Student *student in course.students)
[studentNames addObject:student.name];
sortedArray = [studentNames sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
[picker selectRow:(kRowMultiplier*sortedArray.count)/2 inComponent:0 animated:NO];
}
I can do an NSLog([sortedArray componentsJoinedByString:#", "]); in these two methods and it works:
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
and
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
but when I do that same trace in this method it doesn't work (It crashes):
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
I don't understand why the sortedArray works everywhere but in this one method.
From documentation of sortedArrayUsingSelector::
The new array contains references to the receiver’s elements, not copies of them.
Maybe the original strings are already released?
BTW, I see that you don't release the studentNames - memory leak...
Is there a way to set a default value for a picker? I save the last selected row from all the pickers and I want to be able to have the pickers load those saved rows at start up. As of now I have found this code:
[settingsPagePicker selectRow:3 inComponent:0 animated:YES];
It works but only when the user taps the picker. I need it to work when the app is first loaded. If I put this code at viewDidLoad the app will crash.
Anyone know where the proper place to put this in my code to make it work?
Thank you for your time!
Have you checked your data source for the settingsPagePicker before calling -selectRow:inComponent:animated to make sure there is data available at that index (3 in your sample code)?
How are you loading your data for your data source? You can initialize your data source in viewDidLoad first and then call selectRow once you know there is data available.
UPDATE: Here is what your code should look like or something like it:
- (void)viewDidLoad
{
[super viewDidLoad];
pickerDataSource = [[NSMutableArray alloc] init];
[pickerDataSource addObject:#"Item 01"];
[pickerDataSource addObject:#"Item 02"];
[pickerDataSource addObject:#"Item 03"];
[pickerDataSource addObject:#"Item 04"];
// Might want to move this to -viewWillAppear:animated
[settingsPagePicker selectRow:3 inComponent:0 animated:YES];
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
if (pickerView == settingsPagePicker)
{
return [pickerDataSource objectAtIndex:row];
}
return #"";
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
if (pickerView == settingsPagePicker)
{
return [pickerDataSource count];
}
return 0;
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView
{
return 1;
}
Here some methods from my class.
- (void)viewDidLoad {
[super viewDidLoad];
currentNumbersOfComponents = 1;
//[picker selectRow:2 inComponent:0 animated:NO];
}
- (void) viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[picker selectRow:2 inComponent:0 animated:YES];
}
#pragma mark picker view data source methods
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return currentNumbersOfComponents;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return 5;
}
picker.dataSource is self
I am trying to develop a simple search mechanism on a UIPicker. The approach I am using is to keep two arrays. My problem is that for some reason I am getting this run-time error.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[UIView numberOfComponentsInPickerView:]
Here are the array declarations.
//data source for UIPicker NSArray
*arrayCountryChoices;
//search results buffer
NSMutableArray *arraySearchResults;
//properties
#property(nonatomic,retain) NSArray*arrayCountryChoices;
#property(nonatomic,retain) NSMutableArray *arraySearchResults;
Here is where I initialize the data
//create data
arrayCountryChoices = [NSArray arrayWithObjects:#"foo",#"bar",#"baz",nil];
//copy the original array to searchable array
arraySearchResults = [arrayCountryChoices mutableCopy];
An the picker methods.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {
return [arraySearchResults count];
}
- (NSString *)pickerView:(UIPickerView *)thePickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
return [arraySearchResults objectAtIndex:row];
}
- (void)pickerView:(UIPickerView *)thePickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
//grab the selected country
strUserChoice = [arraySearchResults objectAtIndex:row];
}
Here is the search code for completeness although not really relevant yet as the app dies before we ever get here.
//filter on search term
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", strSearchText];
[arraySearchResults filterUsingPredicate: predicate];
[pickerCountry reloadComponent:0];
I have also dragged datasource and delegate connections from the UIPicker to Files Owner in Interface Builder.
Any ideas?
Thanks in advance.
Looks like you've got the picker's data source set to something other than the object that implements the code you've posted there—apparently a UIView somewhere. Make sure the picker's outlets point to your actual data-source object.