Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

quilpole

macrumors newbie
Original poster
Dec 10, 2008
9
0
I have a UIPickerView which has four components, each with ten rows. The UIPickerView is setup (via the titleForRow method) to have each of the digits from '0' to '9'.

The control works perfectly ... except that when the user scrolls down to the bottom of a component (to the '9' position), the control keeps going!!

As an experiment (and to stop it blowing up with an exception), I setup the titleForRow method to return a "FOO" string if the "row" argument was out of the range 0-9.

Now, when the user scrolls down to "9", and infinite number of "FOO" rows will appear in the component!! If I scroll the other way, back up to ")", it stops (as one would expect) at the ")" row (after a cute little "bounce").

Is there some parameter I'm missing in the setup of this control that needs to be set to stop it from keeping on going when at the limit of it's motion?
 
That doesn't sound normal. Care to share your code for the titleForRow method (and anything else you think would help), so we can see if we can better determine what's going on? Of the top of my head, I would say that there might be an issue with zero-indexing somewhere...
 
Thanks for the quick reply. The following code fragments show what's going on :) It's weird how it correctly "bounces" when you try to go "up" too far, but will just keep going when you try to go "down". I'm sure there might be a use for this behavior, but not for me!

The delegate header ...

//
// JointPicker.h
// Picker1
//
// Created by Quilpole on 5/31/09.
// Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import <UIKit/UIKit.h>


@interface JointPicker : UIPickerView <UIPickerViewDelegate> {

NSArray *pickerViewArrayWidths;
NSArray *pickerViewArrayDepths;
NSInteger widthValue;
NSInteger depthValue;

}

@property(nonatomic) IBOutlet NSInteger widthValue;
@property(nonatomic) IBOutlet NSInteger depthValue;

@end


The delegate body ...

//
// JointPicker.m
// Picker1
//
// Created by Quilpole on 5/31/09.
// Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import "JointPicker.h"


@implementation JointPicker

@synthesize widthValue;
@synthesize depthValue;


- (id) init {

self = [super init];

if (self) {
pickerViewArrayWidths = [[NSArray arrayWithObjects:mad:"1/8\"",@"1/4\"",@"3/8\"",@"1/2\"",@"5/8\"",@"3/4\"",@"7/8\"",@"1\"",nil] retain];
pickerViewArrayDepths = [[NSArray arrayWithObjects:mad:"1/8\"",@"1/4\"",@"3/8\"",@"1/2\"",nil] retain];
}

return self;

}


- (void)dealloc {
[pickerViewArrayWidths release];
[pickerViewArrayDepths release];
[super dealloc];
}



// Implement PickerView delegate methods.

- (void) pickerView:(UIPickerView *) pickerView didSelectRow:(NSInteger) row inComponent:(NSInteger) component {

// Note the selection.

if (component == 0) {
widthValue = row + 1;
} else {
depthValue = row + 1;
}

}


- (NSString *) pickerView:(UIPickerView *) pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {

NSString *returnStr;

if (component == 0) {
if (row < [pickerViewArrayWidths count]) {
returnStr = [pickerViewArrayWidths objectAtIndex:row];
} else {
// If the method is somehow called with a "row" that is out of range, then
// simply return a nil.
returnStr = nil;
};
} else {
if (row < [pickerViewArrayDepths count]) {
returnStr = [pickerViewArrayDepths objectAtIndex:row];
} else {
// If the method is somehow called with a "row" that is out of range, then
// simply return a nil.
returnStr = nil;
}
}

return returnStr;

}


- (CGFloat) pickerView:(UIPickerView *) pickerView widthForComponent:(NSInteger) component {

CGFloat componentWidth;

if (component == 0) {
componentWidth = 50.0; // First column size for Width Names
} else {
componentWidth = 50.0; // Second column size for Depth Names
}

return componentWidth;

}


- (CGFloat) pickerView:(UIPickerView *) pickerView rowHeightForComponent:(NSInteger) component {

return 30.0;

}


- (CGFloat) pickerView:(UIPickerView *) pickerView numberOfRowsInComponent:(NSInteger) component {

CGFloat rowCount;

if (component == 0) {
rowCount = [pickerViewArrayWidths count];
} else {
rowCount = [pickerViewArrayDepths count];
}

return rowCount;

}


- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *) pickerView {

return 2;

}

@end


Declared in the view controller using ...

JointPicker *myJointPicker;


Initialized in the view controller using ...

- (CGRect) pickerJointFrameWithSize:(CGSize) size {

//CGRect screenRect = [[UIScreen mainScreen] applicationFrame];

CGRect pickerRect = CGRectMake(60.0, 180, 200, 100); // x,y,w,h.

return pickerRect;

}

... and ...

- (void) createJointPicker {

myJointPicker = [[JointPicker alloc] init];

// Position the picker at the bottom.

myPickerView = [[UIPickerView alloc] initWithFrame:CGRectZero];
CGSize pickerSize = [myPickerView sizeThatFits:CGSizeZero];

myPickerView.frame = [self pickerJointFrameWithSize:pickerSize];

myPickerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
myPickerView.delegate = myJointPicker;
myPickerView.showsSelectionIndicator = YES;

// Add picker to our view controller

myPickerView.hidden = NO;
[self.view addSubview:myPickerView];

}
 
Hmm, don't you want:
Code:
if (row < [pickerViewArrayWidths count]) {
to be:
Code:
if (row <= [pickerViewArrayWidths count]) {
?
(Same with pickerViewArrayDepths)

P.S. Please used the
HTML:
[CODE]...[/CODE]
tags for code snippets. The # icon in the toolbar provides easy access.
 
I was assuming that the "row" argument was zero-based, and would always be in the range 0..n (where n is the number of rows).

So, in the case of this example, one array has 4 elements and the other 8 elements, so I assumed the row would be in the ranges 0..3 and 0..7 respectively.

So, that's why I used the "<" rather than "<=". Does this make sense (and am I right about the zero-based thing)?

Either way, it still doesn't seem to explain why it allows infinite movement "down"!! And I don't think it does this in the simulator!

Thanks again for the feedback on this. It's been driving me crazy.
 
Well, thanks for responding :) This has baffled me for days. I'm thinking of just telling the control it has 100 rows, then using modulus to feed it the same 4 (or 8) text strings. To the user, it will then appear that the controls are circular, and then the whole infinite moving down thing will not seem strange. Actually, that might be a nicer functionality anyway ;) Hmm, maybe I've stumbled on an improvement to the interface :) :) :) Bizarre!
 
It's not set! I couldn't figure out what it was used for ;)

I already set the delegate property, and that's the guy who handles all the requests (how many rows do I have? How wide are the rows, what is the text, and so on).

What does the datasource do for me?

(yes, I'm a real noob ;) I only started working with this stuff a few weeks ago).
 
I already set the delegate property, and that's the guy who handles all the requests (how many rows do I have? How wide are the rows, what is the text, and so on).
Incorrect. The delegate (UIPickerViewDelegate) handles the height, width, row title, and the view content for the rows in each component. It is the datasource (UIPickerViewDataSource) that handles the number of rows and components it needs to display the data in the picker view.

Based on your code, you'll want to add a line like this:
Code:
myPickerView.datasource = myJointPicker;
...probably just after or before you set the myPickerView.delegate
 
Yeah, I think I started having that line a few days ago, but I received a compilation error and ended up taking it out.

When I add the line (after the line setting up the delegate) :-

myPickerView.datasource = myJointPicker;

The error is :-

"error:request for member 'datasource' in something not a structure or union."

My Objective c knowledge is not strong enough to interpret that error to produce an action ;)
 
You also need to make sure that JointPicker conforms to the UIPickerViewDataSource protocol:
Code:
@interface JointPicker : UIPickerView <UIPickerViewDelegate, UIPickerViewDataSource >

I'm gonna suggest that you need to step back from the real coding for a bit and go back and review the basics of Objective-C and iPhone coding before you continue.
 
Well, thank you once more for your assistance with this :) I'll go back to my Maher Ali book and see if it can offer any inspiration :) :)

I added the additional protocol to my delegate classes, but the same error persisted ... and a few extra warnings! Grrrrrr. I'm sure this gets easier with a lot more practice, but for now I'm feeling as much a rookie as in the early 70s when I started with this stuff ;) ;)

Maybe my brain is just too old to be programming ;) Maybe sheep farming might be a better fit!
 
I added the additional protocol to my delegate classes, but the same error persisted ... and a few extra warnings
Oops. I forgot. Based on the way I've normally seen it done, I think you also want to subclass UIPickerViewController and not UIPickerView. Which is gonna affect the whole approach you have for using JointPicker. So, I'm not sure where you need to go from here.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.