Xcode 4.2.1: UIPickerView causing memory leak, using ARC - ios

For one of my last school projects, I am creating an iPad/iPhone application. For some days now I've been working on an issue with a certain memory leak. My application starts out on a specific view-controller (VCMainStatistics_iPad). From there, I push another view-controller (VCSocialMedia_iPad). Afterwards, I go back to the first view-controller.
When I repeat this sequence, I notice (by using Instruments - Activity Monitor) that the memory usage of the app keeps increasing. By disabling parts of the code, I eventually found out it has something to do with the pickerView. This code gives no leaks:
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return 0;
}
However, when I increase the number of rows, leaks start emerging (roughly 0.07 MB per row). Obviously, this is why I believe the pickerView is the cause of the leaks. I've been trying to remove the subviews from the pickerView before deallocation, setting pickerView to nil, and lots of other things... nothing fixes the issue. To hopefully make things a bit clearer, I'll post some more code.
The header file:
#import "UniversalViewController.h"
#define DATATYPE_SOCIALMEDIA 0
#interface VCSocialMedia_iPad : UniversalViewController <UIPickerViewDataSource, UIPickerViewDelegate>
{
NSArray *lMediaTypes;
NSMutableArray *lMediaData;
__weak IBOutlet UIPickerView *pkSocialMedia;
__weak IBOutlet UILabel *lblGraph;
}
#end
PickerView delegate methods:
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
// Get key of requested row
NSString *title = [[lMediaTypes objectAtIndex:row] capitalizedString];
// Capitalize first letter
title = [title capitalizedString];
// Return
return title;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
// Make or clear data lists
if( lGraphDayDataX[iSelectedServerIndex][DATATYPE_SOCIALMEDIA] == nil ){
lGraphDayDataX[iSelectedServerIndex][DATATYPE_SOCIALMEDIA] = [[NSMutableArray alloc] init];
}
else{
[lGraphDayDataX[iSelectedServerIndex][DATATYPE_SOCIALMEDIA] removeAllObjects];
}
if( lGraphDayDataY[iSelectedServerIndex][DATATYPE_SOCIALMEDIA] == nil ){
lGraphDayDataY[iSelectedServerIndex][DATATYPE_SOCIALMEDIA] = [[NSMutableArray alloc] init];
}
else{
[lGraphDayDataY[iSelectedServerIndex][DATATYPE_SOCIALMEDIA] removeAllObjects];
}
// Get required key
NSString *dictKey = [lMediaTypes objectAtIndex:row];
if( [dictKey isEqualToString:#"total_views"] ){
return;
}
// Adjust graph label
lblGraph.text = [NSString stringWithFormat:#"Stats from %#", dictKey];
// Get data of selected row
NSArray *mediaData = [lMediaData objectAtIndex:row];
// Add each day to data lists: inversed order
for( int day = [mediaData count]-1; day >= 0; day-- ){
NSDictionary *dayData = [mediaData objectAtIndex:day];
dictKey = #"wpsd_trends_date";
NSString *date = [dayData objectForKey:dictKey];
// Remove 00:00:00
date = [date stringByReplacingOccurrencesOfString:#" 00:00:00" withString:#""];
[lGraphDayDataX[iSelectedServerIndex][DATATYPE_SOCIALMEDIA] addObject:date];
dictKey = #"wpsd_trends_stats";
NSString *stats = [dayData objectForKey:dictKey];
[lGraphDayDataY[iSelectedServerIndex][DATATYPE_SOCIALMEDIA] addObject:stats];
}
// Update the graphs
[self updateGlobalScreen];
}
PickerView datasource methods:
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [lMediaTypes count];
}
Deallocation:
- (void)dealloc
{
pkSocialMedia = nil;
lblGraph = nil;
lMediaData = nil;
lMediaTypes = nil;
}
I only recently converted the project to Objective-C ARC, so there is a good chance this issue has something to do with my lack of experience with the concept. Apart from that, this is also my first Xcode project ever. Hopefully, someone here can help out: please let me know if I need to post more code to clarify things.
Thanks in advance!

Try removing the -(void)dealloc method. It shouldn't be implemented when you're using ARC. If you aren't using ARC, it needs to call [super dealloc].

Never found the solution itself, so I used a workaround: by replacing the NSPickerView with a NSTableView component, the leak did not occur anymore. For everyone who noticed the issue and tried to find a solution: thank you for trying!

I'm having a similar issue. It only happens when the UIPickerView is outside the bounds. The way I fixed it is to never have the UIPickerView move out of bounds (simply fade in and fade out to unhide/hide the UIPickerView). Probably a bug in UIKit.

Related

I am trying to make a conversion calculator with Xcode

I have made the basic build and it includes a picker. So whatever units of conversion the user selects from the picker, the labels should be updated to show the names of the units for that conversion and once the user enters the number in the text box and hits the button, the answer should be displayed in the second text box. Now the code executes, but the problem is no matter what I pick in the picker, it always does the weight conversion. I know I need a switch statement in there, but I'm not sure how or where I need to implement it.
Another problem is that the labels update, but only when the "Convert" button is pressed, so please help me fix this.
This is my ViewController.h file
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
<UIPickerViewDelegate, UIPickerViewDataSource> {
IBOutlet UITextField *field1;
IBOutlet UITextField *field2;
IBOutlet UIPickerView *picker;
IBOutlet UILabel *label1;
IBOutlet UILabel *label2;
}
#property (weak, nonatomic) IBOutlet UILabel *textLabelData1;
#property (weak, nonatomic) IBOutlet UILabel *textLabelData2;
#property (nonatomic, retain) UIPickerView *picker;
-(IBAction) currencyConvert:(id)sender;
-(IBAction) weightConvert:(id)sender;
-(IBAction) distanceConvert:(id)sender;
#end
This is my ViewController.m file
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize picker;
static NSString *pd[3] = {#"Currency", #"Weight", #"Speed"};
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark UIPickerViewDelegate & UIPickerViewDataSource methods
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView
numberOfRowsInComponent:(NSInteger)component
{
return 3;
}
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:
(NSInteger)row forComponent:(NSInteger)component;
{
return pd[row];
}
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:
(NSInteger)row inComponent:(NSInteger)component
{
NSLog(#"didSelectRow %li, inComponent: %li", row, component);
}
-(IBAction)currencyConvert:(id)sender
{
if (pd[0])
{
self.textLabelData1.text = #"Dollar";
self.textLabelData2.text = #"Rupees";
float dollar = [[field1 text] floatValue];
float rupees = dollar * 64.15;
[field2 setText: [NSString stringWithFormat: #"%3.3f", rupees]];
}
/* self.textLabelData1.text = #"Dollar";
self.textLabelData2.text = #"Rupees";
float dollar = [[field1 text] floatValue];
float rupees = dollar * 64.15;
[field2 setText: [NSString stringWithFormat: #"%3.3f", rupees]]; */
}
-(IBAction)weightConvert:(id)sender
{
if (pd[1])
{
self.textLabelData1.text = #"Kilogram";
self.textLabelData2.text = #"Lbs";
float kilogram = [[field1 text] floatValue];
float pounds = kilogram * 2.20462;
[field2 setText: [NSString stringWithFormat: #"%3.3f", pounds]];
}
}
-(IBAction)distanceConvert:(id)sender
{
if (pd[2])
{
self.textLabelData1.text = #"Mile";
self.textLabelData2.text = #"Kilometer";
float miles = [[field1 text] floatValue];
float kilometers = miles * 1.60934;
[field2 setText: [NSString stringWithFormat: #"%3.3f", kilometers]];
}
}
/* Pseudocode for switch statement
-- I tried doing this here, but it gives me an
error saying that "row" is undefined. I understand that
it is a local variable, but how else would I write the
switch statement?
Also, is the placement of the switch statement appropriate here
or will I need to implement it in a function?
switch (row)
{
case 1:
call currencyConvert
case2:
call weightConvert
case3:
call distanceConvert
}
*/
The link to the picture of my Main.storyboard
This isn't the ideal UI and creates inefficiencies, but its your app. I just wanted to point out that you might want to spend time working on its design and structure.
As for a solution to your problem, I cant fix everything for you, but I'll point out some things to make it easier for you.
The reason your labels are not updating is because you are not updating anything until you hit the convert button. The below function is where you'll get the event for the picker's new row
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:
(NSInteger)row inComponent:(NSInteger)component
{
NSLog(#"didSelectRow %li, inComponent: %li", row, component);
}
Try this instead:
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:
(NSInteger)row inComponent:(NSInteger)component
{
NSLog(#"didSelectRow %li, inComponent: %li", row, component);
switch (row) {
case 0:
self.textLabelData1.text = #"Dollar";
self.textLabelData2.text = #"Rupees";
break;
case 1:
// and so on
}
}
Your next issue is that you're not telling your "convert" functions what row is currently selected, and your conditional if does nothing.
In obj-c conditional statements used directly on a variable are basically just checks for initialization. if(x) simply means has x been initialized as a variable = true, if not = false. That's probably not the logic you're looking for in this case.
Next, It appears you're trying to link 3 different functions to the same button press? This is where your above if related issue is causing problems, all three functions are firing at the same time... but only one gets the last say. Presumably the one you linked last, though i cant say for sure. I'd suggest a single function that handles the button press and then relays to the correct methods.
Last, you're never telling the functions anything about the state of the picker. You need to set it as an IBOutlet so your variables will have access to it. Then you can use the picker's selected row function to determine which conversion to use.
The things I highlighted will fix your problems, BUT I would highly recommend checking out some tutorials so you'll learn more about why things do what. I'd recommend: https://www.raywenderlich.com/
Hope that helps!

xcode - UIPickerView without ARC

I am testing a simple UIPickerView app so that I can use it as a class in my project...
the code works beautifully with ARC but as soon as I turn ARC off the build succeeds but crashes when I click on the display of the picker...the error displayed is "EXC_BAD_ACCESS(code=2, address=oxc)" at the line
return [pickerData1 objectAtIndex:row];
will be extremely grateful if someone can help...I have spent more than 7 working days [60hours+] trying all sorts of options given on the stackoverflow website but just can't get around the issue...needless to say I am trying to learn...
...i have learnt this much that there is a problem with the array...it is being released whereas it should be retained till the 'objectAtIndex' call...but I have tried countless ways of going about this none worked...its because i don't have an in-depth understanding of xcode as yet...trying to learn by doing...usually i am successful in figuring out how to apply sample code in my project and have successfully completed many complex parts of my project (it is an iPad app that deploys augmented reality technology), but am desperately stuck at this rather simple component...
this is the header file:
#import <UIKit/UIKit.h>
#interface PickerText : UIViewController<UIPickerViewDataSource, UIPickerViewDelegate>
{
NSArray *pickerData1;
}
#property (retain, nonatomic) IBOutlet UIPickerView *picker1;
#property (retain, nonatomic) IBOutlet UIButton *buttonForSelection1;
#end
and this is the implementation file
#import "PickerText.h"
#interface PickerText ()
//set tags to enable future incorporation of multiple pickers
#define kPICKER1COLUMN 1
#define kPICKER1TAG 21
#define kButton1Tag 31
#end
#implementation PickerText
#synthesize picker1;
#synthesize buttonForSelection1;
- (void)viewDidLoad
{
[super viewDidLoad];
// assign data in array
pickerData1 = #[#"[tap to select]", #"Item 1", #"Item 2", #"Item 3", #"Item 4", #"Item 5", #"Item 6"];
// Connect data
picker1.tag = kPICKER1TAG;
self.picker1.dataSource = self;
self.picker1.delegate = self;
picker1.hidden = YES;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
// set number of columns of data in picker view
- (int)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
if (pickerView.tag == kPICKER1TAG)
return kPICKER1COLUMN;
else { return 0; }
}
// The number of rows of data
- (int)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
if (pickerView.tag == kPICKER1TAG)
return [pickerData1 count];
else { return 0; }
}
// The data to return for the row and component (column) that's being passed in (ie set the data in picker view)...
//method using NSString
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
if (pickerView.tag == kPICKER1TAG)
return [pickerData1 objectAtIndex:row];
else { return 0; }
}
// Capture the picker view selection
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
if (pickerView.tag == kPICKER1TAG)
{
NSString *selection1 = [pickerData1 objectAtIndex:[picker1 selectedRowInComponent:0]];
//check selection
NSLog(#"%#", selection1);
//change display text on button
[buttonForSelection1 setTitle:selection1 forState:UIControlStateNormal];
[buttonForSelection1 setTitle:selection1 forState:UIControlStateSelected];
}
//to hide picker view after selection
pickerView.hidden=YES;
}
- (IBAction)showPicker:(id)sender
{
if ([sender tag] == kButton1Tag)
{
picker1.hidden = NO;
}
}
#end
many thanks in advance!!
And in case if you want to know what the issue is with ARC turned off. The Problem is here:(1)
#interface PickerText : UIViewController<UIPickerViewDataSource, UIPickerViewDelegate>
{
NSArray *pickerData1;
}
and here(2) -
pickerData1 = #[#"[tap to select]", #"Item 1", #"Item 2", #"Item 3", #"Item 4", #"Item 5", #"Item 6"];
You see, in ARC the default association is strong so when you write the second line, THE pickerData1 holds a strong reference to the autorelease array and it all works properly. But without ARC the default association is assign hence , since in line 2 you have assigned an autorelease array (which is getting released at some later point of time), you are getting the crash. You can learn the difference between assign and strong in the Apple documents.
Better you change the array to a strong property. Though without ARC, strong will simply mean retain.
Cheers, have fun.
Don't bother turning ARC off. You have the option to enable/disable ARC on a file-by-file basis:
-fobjc-arc to turn ARC on for a file in a project that doesn't work with ARC
-fno-objc-arc vice-versa

PickerView shows up with no options, even though I have set them

I have a UIPickerView, and it is showing up, but it just shows (null). Why is this? I have it conformed to the delegate's I need in.
EDIT: more detail.
Basically, my app is a flight logbook. You make planes, which you saves, and you can pick it when you make a new session. The planeNum key stores how many planes there are, and the key Plane%liTailNumber has the tail number for that plane.
This is my code:
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {
return (long)[[NSUserDefaults standardUserDefaults]integerForKey:#"planeNum"];
}
NSMutableArray *tailPickerOptions;
- (NSString *)pickerView:(UIPickerView *)thePickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
NSInteger num = [[NSUserDefaults standardUserDefaults]integerForKey:#"planeNum"];
while (num > 0){
--num;
tailPickerOptions = [[NSMutableArray alloc]init];
NSString *dTailNumber = [NSString stringWithFormat:#"%#", [[NSUserDefaults standardUserDefaults]objectForKey:[NSString stringWithFormat:#"Plane%liTailNumber", (long)num]]];
[tailPickerOptions addObject:dTailNumber];
NSLog(#"%#", tailPickerOptions);
}
return tailPickerOptions[row];
}
You initialize a new array for each loop of the while. Your code also doesn't ensure you actually initialize the array - if num = 0, you'll never go in and declare the array. There should be a warning or compiler error for this. In the best case scenario because you keep declaring a new array in your loop, you'll return a max of 1 element ever.
Move your array declaration above the while loop.

Objective c converter app

I am working on a small converter app for my school project, an app that won't be published in App Store, just for school grade. I am wondering if anyone knows how did this developer in this app
made connections for converting values? The simplest way i can imagine is with switch cases but that would make too much unnecessary code:
if (first column is distance) then if(second column is metres)
case0:third column is yards -> do something
case1:third column is kilometers ->do something
case2:third column is metros ->do nothing
etc....
Thanks for answering.
EDIT:
Thanks for fast answer, this is what i made so far, iOS simulator is displaying correctly three column picker in which second two are displayed depending on the row of the first one. Can u tell me is this any good? Maybe some things are uneccesary complicated?
#import "konverterViewController.h"
#interface konverterViewController ()
#end
#implementation konverterViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.fizVelicine = [[NSArray alloc] initWithObjects:#"distance",#"mass" , nil];
self.udaljenostJedinice = [[NSArray alloc] initWithObjects:#"meter", #"kilometer", #"yard", #"inch", nil];
self.masaJedinice = [[NSArray alloc] initWithObjects:#"kilogram",#"dekagram",#"gram",#"tone" , nil];
}
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
UILabel *retval = (id)view;
if (!retval) {
retval = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f,
[pickerView rowSizeForComponent:component].width,
[pickerView rowSizeForComponent:component].height)];
}
retval.opaque = NO;
retval.backgroundColor = [UIColor orangeColor];
retval.adjustsFontSizeToFitWidth = YES;
retval.font = [UIFont systemFontOfSize:12];
if (component == 0) {
retval.textAlignment = NSTextAlignmentCenter;
retval.text = [self.fizVelicine objectAtIndex:row];
}
else if ([self.odabir isEqualToString:#"distance"]){
retval.textAlignment = NSTextAlignmentCenter;
retval.text = [self.udaljenostJedinice objectAtIndex:row];
}
else {
retval.textAlignment = NSTextAlignmentCenter;
retval.text = [self.masaJedinice objectAtIndex:row];
}
return retval;
}
// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 3;
}
// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent: (NSInteger)component
{
if(component== 0)
{
return [self.fizVelicine count];
}
else
{
if([self.odabir isEqualToString:#"distance"]){ return [self.udaljenostJedinice count];}
else {return [self.masaJedinice count];}
}
}
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
if(component == 0)
{
return [self.fizVelicine objectAtIndex:row];
}
else {
if([self.odabir isEqualToString:#"distance]){
return [self.udaljenostJedinice objectAtIndex:row];}
else {
return [self.masaJedinice objectAtIndex:row];
}
}
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
if (component == 0) {
self.odabir=[[NSString alloc] initWithFormat:#"%#" , [self.fizVelicine objectAtIndex:row]];
[pickerView reloadAllComponents];}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
It sounds like you're puzzling over how to initialize the picker sections at the top. I think you'll need a data structure that is an array of arrays:
#[#"distance", #[#"meters", #"inches", #"cubits", #"whatevers"],
#"weight", #[#"grams", // etc
Tell the picker that you have three segments. The first segment can be manufactured (and cached, if you want) as the first elements of each sub-array. The second two segments get their values from the data structure, indexed by the value of the first section.
EDIT; You'll probably want a data structure that helps you compute the conversion. For each kind of measure, imagine an NxN table, where N is the number of units on the wheels. A row let's you look up the left wheel setting and the column lets you look up the right wheel. The table should contain what you need to do the calculation. If all of the measures linearly related, like inches-meters, the table can simply contain floats (wrapped as NSNumber) conversion factors.
// conversion factors for distance, units as the first value, conversion factors in a subarray
// meters = 1*meters, 39.37*inches, 2.19*cubits, etc
NSArray *conversions =
#[#"meters", #[#1.0, #39.37, #2.19, //etc
#"inches", // etc. conversions to meters inches cubits etc.
You might notice that this array contains some waste. Only half the table is needed, since inches->meters is just the reciprocal of meters->inches) but I think the space small enough to not worry about this. You might also notice that the table is good only for simple linear relationships between units. Centigrade to Fahrenheit will require a different treatment. The most general treatment for arbitrary conversions might be an array of blocks that carry out the computation. But I suggest starting more simply.
EDIT AGAIN:
Now, to get a conversion formula, get the current picker selections and look up a conversion factor:
NSInteger fromUnitsIndex = [self.picker selectedRowInComponent:1];
NSArray *fromArray = self.conversions[fromUnitsIndex];
// the second member of this array is an array of conversion factors
NSArray *conversionNumbers = fromArray[1];
NSInteger toUnitsIndex = [self.picker selectedRowInComponent:2];
NSNumber *conversionNumber = conversionNumbers[toUnitsIndex];
It sounds like a fun project. Good luck!

Building a UIPickerView Util class

I'm trying to learn iOS from an entirely Android background. I would like to build a UIPickerView Util class that can be reused over and over again as a separate class throughout my app and I'm receiving the EXC_BAD_ACCESS message and I'm not sure why. So I have two questions:
I've not seen anything about separating this as a different class, is this because this is an improper way to handle this problem?
What's wrong with this basic (mostly generated) code that would be giving me the EXC_BAD ACCESS message? I've read that this is related to memory issues. I'm using ARC so why is this an issue?
Here are the beginnings of the class that I'm trying to build.
Header file
#import <UIKit/UIKit.h>
#interface PickerTools : UIViewController<UIPickerViewDelegate>
#property (strong, nonatomic)UIPickerView* myPickerView;
-(UIPickerView*)showPicker;
#end
Implementation file
#import "PickerTools.h"
#implementation PickerTools
#synthesize myPickerView;
- (UIPickerView*)showPicker {
myPickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 200, 320, 200)];
myPickerView.delegate = self;
myPickerView.showsSelectionIndicator = YES;
return myPickerView;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow: (NSInteger)row inComponent: (NSInteger)component {
// Handle the selection
}
// tell the picker how many rows are available for a given component
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
NSUInteger numRows = 5;
return numRows;
}
// tell the picker how many components it will have
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
// tell the picker the title for a given component
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
NSString *title;
title = [#"" stringByAppendingFormat:#"%d",row];
return title;
}
// tell the picker the width of each row for a given component
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component {
int sectionWidth = 300;
return sectionWidth;
}
#end
Here's how I'm calling it from a method in a UITableViewController class:
PickerTools *picker = [[PickerTools alloc]init];
[[self view]addSubview:[picker showPicker]];
What are you doing with showPicker? showPicker is misleading because it doesn't actually show. It only returns a pickerView with a frame. At some point you need to add it to a view using addSubview or use a UIPopoverController or something.
If you are just creating your view controller class within the scope of a method, then it is getting released as soon as that method is done running. Then all bets are off. The picker is trying to access the delegate (which is the view controller) but the view controller is nowhere to be found because it was released.
You'll have to post some usage code. By itself, this code should work, but it's how you're using it.
Also, you don't have to use a UIViewController just to "control" a simple view. Consider making a custom class and just sublcass NSObject.
EDIT:
After looking at your posted code my suspicions were correct. You need to "retain" your PickerTools instance. Meaning, you need to save the "picker" variable (misleading again) as a strong property on the calling view controller. It gets released right after you're adding the pickerview as a subview. The pickerView is alive because it's being retained by it's superview but the object that holds it (the delegate "picker") is dead. Make sense?

Resources