初学xcode,具体要实现的功能为用picker建一个省  / 市   /   邮编,三级联动picker,参照了网络上省市区三级联动自己写了代码,一直未能实现功能,
h文件
#import <UIKit/UIKit.h>
#define PickerOne 0
#define PickerTwo 1
#define PickerThree 2
@interface den : UIViewController<UIPickerViewDataSource,UIPickerViewDelegate>@property (strong, nonatomic) IBOutlet UIPickerView *pickView;
@property(strong,nonatomic)NSDictionary *zidian;
@property(strong,nonatomic)NSArray *sheng;
@property(strong,nonatomic)NSArray *city;
@property(strong,nonatomic)NSArray *number;
@property(nonatomic,retain)NSArray* selectArray;- (IBAction)choose:(id)sender;
@endM文件
#import "den.h"@interface den ()@end@implementation den
@synthesize pickView;
@synthesize zidian;
@synthesize sheng;
@synthesize city;
@synthesize number;
@synthesize selectArray;- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}- (void)viewDidLoad
{NSBundle *bundle = [NSBundle mainBundle];
    //获取code.plist的路径
    NSString *listPath = [bundle pathForResource:@"code2" ofType:@"plist"];
    //用获取到的路径创建一个字典文件
    NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:listPath];
    //分配给zidian
    self.zidian = dictionary;
    [dictionary release];
    
    //获取字典里所有的数组
    NSArray *components = [self.zidian allKeys];
    //按照字母顺序排序
    NSArray *sorted = [components sortedArrayUsingSelector:@selector(compare:)];
    self.sheng = sorted;
    NSString *selectedSheng = [self.sheng objectAtIndex:0];
    NSArray *array = [zidian objectForKey:selectedSheng];
    //将它分配给zips
    self.city = array;
    NSArray *components1 = [self.zidian allKeys];
    NSArray *sorted1=[components1 sortedArrayUsingSelector:@selector(compare:)];
    self.city=sorted1;
    NSString *selectedCity=[self.city objectAtIndex:0];
    NSArray *array1=[zidian objectForKey:selectedCity];
    self.number=array1;
    [zidian release];
    
    [super viewDidLoad];
    self.pickView.dataSource=self;
    self.pickView.delegate=self;
// Do any additional setup after loading the view.
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}- (IBAction)choose:(id)sender {
    NSInteger shengRow = [pickView selectedRowInComponent:PickerOne];
    NSInteger cityRow  = [pickView selectedRowInComponent:PickerTwo];
    NSInteger zipsRow  = [pickView selectedRowInComponent:PickerThree];
    //返回选中行的值
    NSString *shengName= [self.sheng objectAtIndex:shengRow];
    NSString *cityName = [self.city objectAtIndex:cityRow];
    NSString *zipsName = [self.number objectAtIndex:zipsRow];
    //把选中的值分配给字符串
    NSString *title = [[NSString alloc] initWithFormat:@"你选择的邮编是%@",zipsName];
    NSString *msg = [[NSString alloc] initWithFormat:@"%@是%@的%@的邮编",
                     zipsName,shengName,cityName];
    
    UIAlertView *alert=[[UIAlertView alloc]initWithTitle:title message:msg delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    [alert show];
    [alert release];
    [title release];
    [msg release];
}- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    return 3;
}
//返回给定的组件有多少行数据,我们有2个组件,所以用if操作。后期tableview也是类似的操作方法
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
//    switch (component){
//            case PickerOne:return [self.sheng count];break;
//            case PickerTwo:return [self.city count];break;
//            case PickerThree:return [self.number count];break;}
    
    
    if (component==PickerOne) {
        return [self.sheng count];
    }
    if (component==PickerTwo) {
        return [self.city count];
    }
    if (component==PickerThree) {
        return [self.number count];
    }
    return 0;
}#pragma  -
#pragma  picker 委托方法//官方的意思是,指定组件中的指定数据,我理解的就是目前选中的是哪一行。
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{    if (component==PickerOne) {
        return [self.sheng objectAtIndex:row];
    }
    if (component==PickerTwo) {
        return [self.city objectAtIndex:row];
    }
    if (component==PickerThree) {
//        return [self.number objectAtIndex:row];
    }
    return nil;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row
       inComponent:(NSInteger)component
{
    NSLog(@"row is %d,Component is %d",row,component);
if (component==0) {
        self.selectArray=[zidian objectForKey:[self.sheng objectAtIndex:row]];
        if ([self.selectArray count]>0) {
            self.city= [[self.selectArray objectAtIndex:0] allKeys];
        }else{
            self.city=nil;
        }
        if ([self.city count]>0) {
            self.number=[[self.selectArray objectAtIndex:0] objectForKey:[self.city objectAtIndex:0]];
        }else{
            self.number=nil;
        }
        [pickerView selectedRowInComponent:1];
        [pickerView reloadComponent:1];
        [pickerView selectedRowInComponent:2];
        
        
    }
    if (component==1) {
        if ([selectArray count]>0&&[city count]>0) {
            self.number=[[self.selectArray objectAtIndex:0] objectForKey:[self.city objectAtIndex:row]];
        }else{
            self.number=nil;
        }
        [pickerView selectRow:0 inComponent:2 animated:YES];
        
    }
    [pickerView reloadComponent:2];
    
}
    @end

解决方案 »

  1.   

    不需要把问题想得很复杂,可简单认为,picker有三个柜子,每个柜子里有可变数量的抽屉。
    这些抽屉里显示什么内容完全是你自己指定的。
    1. 首先加载所有‘省份’列表,此时,‘市’和‘邮编‘可以是空的。告诉picker进行reload
    2. 指定picker默认选中省份中的某一个(例如第一个)
    3. picker的delegate会告诉你‘省份’component被选中,
    4. 如果‘省份’被选中,则加载对应的‘市’列表,告诉picker reload自己,此时‘邮编’列表是空的。告诉picker进行reload
    5. picker的delegate会告诉你‘市’component被选中
    6. ‘市’被选中,加载对应的‘邮编’列表,告诉picker进行reload其实你要做的事情只是替换不同component需要使用的列表内容而已。也就是说,用户选中某个component的某个row时,只要不是邮编component,就改变下一级的component的数据列表源,重新reload,然后用代码选中默认row(例如第一行)
      

  2.   

    给你一个比较简单的例子吧:
    //
    //  ViewController.m
    //  PickerDemo
    //
    //  Created by Charles on 14-7-2.
    //  Copyright (c) 2014年 Syncbox. All rights reserved.
    //#import "ViewController.h"@interface ViewController ()
    @endtypedef NS_ENUM(NSInteger, ComponentType) {
        ComponentProvince,
        ComponentCity,
        ComponentMailCode,
    };@implementation ViewController {
        __weak IBOutlet UIPickerView* thePickerView;
        
        NSDictionary* data;
        
        NSArray* provinces;
        NSArray* citys;
        NSArray* mailCodes;
        
        NSString* selectedProvice;
        NSString* selectedCity;
    }- (void)viewDidLoad
    {
        [super viewDidLoad];
        
        data = @{
                 @"广东": @{
                         @"广州": @[@"510000", @"510001", @"510003"],
                         @"化州": @[@"123456", @"123457", @"123458"],
                         },
                 @"湖南": @{
                         @"郴州": @[@"444444", @"444441", @"444445"],
                         @"长沙": @[@"222222", @"222223", @"222224"],
                         }
                 };
        
        provinces = [data allKeys];
        [thePickerView reloadAllComponents];    [self manuallySelectRow:0 inComponent:ComponentProvince];
    }- (void)manuallySelectRow:(NSInteger)row inComponent:(NSInteger)component {
        [thePickerView selectRow:0 inComponent:component animated:YES];
        [self pickerView:thePickerView didSelectRow:0 inComponent:component];
    }- (void)pickerView:(UIPickerView *)pickerView
          didSelectRow:(NSInteger)row
           inComponent:(NSInteger)component
    {
        switch (component) {
            case ComponentProvince:
                selectedProvice = provinces[row];
                citys = [data[selectedProvice] allKeys];
                break;
                
            case ComponentCity:
                selectedCity = citys[row];
                mailCodes = data[selectedProvice][selectedCity];
                break;
            
            case ComponentMailCode:
                // 选中邮编时,不需要联动
            default:
                break;
        }    if (component==ComponentProvince || component==ComponentCity) {
            NSInteger nextComponent = component+1;
            [pickerView reloadComponent:nextComponent];
            [self manuallySelectRow:0 inComponent:nextComponent];
        }
    }- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
        return 3;
    }- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
        switch (component) {
            case ComponentProvince:
                return provinces.count;
                
            case ComponentCity:
                return citys.count;
                
            case ComponentMailCode:
                return mailCodes.count;
        }
        
        return 0;
    }- (NSString *)pickerView:(UIPickerView *)pickerView
                 titleForRow:(NSInteger)row
                forComponent:(NSInteger)component
    {
        switch (component) {
            case ComponentProvince:
                return provinces[row];
                
            case ComponentCity:
                return citys[row];
                
            case ComponentMailCode:
                return mailCodes[row];
        }
        
        return nil;
    }@end
      

  3.   

    关键是第59行那个方法的实现,如果选中了前两个component,则需要加载下一个component的内容,并手动选中其第一个row,手动选中必须使用第54行的做法,因为只是调用-[UIPickerView selectRow:inComponent:animated:] 只是进行了选中,并不会触发59行didSelect的执行。上面这种做法是比较简单的,通过代码来产生‘联动’和用户在设备上选中某个component时产生的联动所使用的逻辑是统一的