【问题标题】:How do I drill down through a plist using UITableViews?如何使用 UITableViews 向下钻取 plist?
【发布时间】:2013-08-19 19:19:25
【问题描述】:

我想使用 uitableviews 深入了解 plist 以获取特定学校。向下钻取是州->区->学校。我创建了一个 plist,但不能 100% 确定该结构是最好的。此外,我可以在第一个 tableview 上获得第一组活动信息,但不知道如何从那里开始。我是否需要为每个向下钻取(stateview、districtview、schoolview)创建一个表视图,或者我可以重用一个通用的表视图,因为它们只是列表?以下是我到目前为止所拥有的。感谢您的帮助。

PLIST
<plist version="1.0">
<array>
<dict>
    <key>districts</key>
    <dict>
        <key>District 1</key>
        <array>
            <string>School 2</string>
            <string>School 1</string>
        </array>
        <key>District 2</key>
        <array>
            <string>School 3</string>
            <string>School 4</string>
        </array>
    </dict>
    <key>state</key>
    <string>South Dakota</string>
</dict>
<dict>
    <key>districts</key>
    <array>
        <string>District 1</string>
        <string>District 2</string>
    </array>
    <key>state</key>
    <string>Arkansas</string>
</dict>
<dict>
    <key>districts</key>
    <array>
        <string>District 3</string>
        <string>District 4</string>
    </array>
    <key>state</key>
    <string>New York</string>
</dict>
</array>
</plist>

这是我的视图控制器

#import "plistViewController.h"

@interface plistViewController ()

@end

@implementation plistViewController

- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {

}
return self;
}

@synthesize content = _content;

-(NSArray *)content
{
if (!_content) {
    _content = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Data" ofType:@"plist"]];
}
return _content;
}

- (void)viewDidLoad
{
[super viewDidLoad];

}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];

}

#pragma mark - Table view data source

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

return [self.content count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

cell.textLabel.text = [[self.content objectAtIndex:indexPath.row] valueForKey:@"state"];
return cell;
 }


#pragma mark - Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
}

@end

【问题讨论】:

  • 我注意到你的类缺少它的 numberOfSections 方法。这确实是复制粘贴还是您错过了?
  • 不,我还没有将它内置到类中。
  • 如果您不将该方法添加到类中,该表将不知道该怎么做。这是一个required 方法。其他方法,例如可以显示节标题的方法,或者使单元格的高度,是optional
  • 感谢您的提醒。我一定会补充的。

标签: ios objective-c xcode uitableview plist


【解决方案1】:

UITableView 最好的一点是它不关心它显示什么数据。它只是问它的delegate 几个不同的问题:

  1. 我应该有多少个部分?
  2. 每个部分有多少行?
  3. 我可以为这个 _ 索引路径提供一个 UITableViewCell 吗?

因此,您必须专注于让您的委托响应提供正确的数据。

所以,首先将您的 plist 拆分为可管理的块。 UITableView prima-donna 数据源是一个 NSArray。由于索引逻辑,整齐地映射到 tableViews。

也就是说,您的第一个 tableViewController plistViewController 具有显示信息的良好逻辑。具体来说,您正在查询数组位置 x 的 NSDictionary 并要求它返回其 state 对象。 3 个字典对象,返回 3 个字符串。不错。

那么你如何进入下一个级别?您的 tableView 将在这里为您提供帮助。它询问了它的delegate 的一个具体问题:

  1. 当用户触摸第 Y 行 X 行时我该怎么办?

您将需要设置另一个名为DistrictViewController 的 UITableViewController 子类。在标题.h 文件中,您需要为NSDictionary 对象创建strong 属性。像这样:

//DistrictViewController.h
@interface DistrictViewController : UITableViewController
@property (nonatomic, strong) NSDictionary *districtDictionary;
@end

//DistrictViewController.m
@implementation DistrictViewController
@synthesize districtDictionary;

我们有它。此类现在设置为跟踪 1 个 NSDictionary 对象。现在你只需要配置你的表委托方法来显示你想要的数据。

第一个示例,NSArray 的第一行(索引:0)中的内容,您有一个包含 2 个键的字典:District 1District 2。但这是一个问题。 NSDictionary 并不那么容易映射到 TableViews,因为 NSDictionary 对象不使用索引来工作。别担心。 NSDictionary 有一个名为allKeys 的方法,它将为您提供字典中每个键的数组。当您从某个地方收到一个 NSDictionary 但事先不知道它包含哪些键时,这很有用。

那么,你的 tableView 提出的问题,让我们来回答吧:

//How many sections will be in me: Let's just say 1 for now.
//How many rows will be in this section:

//Ask the NSDictionary how many keys it has:
NSArray *keyArray = [self.districtDictionary allKeys];
return [keyArray count];

//Give me a tableCell for index path X,Y


//First, get your array of keys back:
NSArray *keyArray = [self.districtDictionary allKeys];
//Next, find the key for the given table index:
NSString *myKey = [keyArray objectAtIndex:indexPath.row];
//Finally, display this string in your cell:
cell.textLabel.text = myKey;

在此之后,您将对最终视图执行相同的操作。为学校设置一个 viewController 并将其命名为SchoolViewController 并将其设置为负责一个 NSArray。和以前一样:

@interface SchoolViewController : UITableViewController
@property (nonatomic, strong) NSArray *schoolArray;
@end

@implementation SchoolViewController
@synthesize schoolArray;

在这个视图中,它会很像第一个。您只需让这个 viewController 像以前一样回答表格的问题:

  1. 有多少个部分?我们需要 1
  2. 多少行?我们需要数组中的数量return [schoolArray count];
  3. 给我一个手机:cell.textLabel.text = [schoolArray objectAtIndex:indexPath.row];

将这一切放在一起的最后一部分是表格提出的最后一个问题。

  1. 当用户触摸一行时我该怎么办?

在每个视图中,查看这个方法签名:

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

这是您添加逻辑以连接事物的地方。在第一个视图plistViewController 中,执行以下操作:

NSDictionary *topLevelDictionary = [self.content objectAtIndex:indexPath.row];
NSDictionary *allDistricts = [topLevelDictionary objectForKey:@"districts"];
DistrictViewController *dView = [[DistrictViewController alloc] initWithStyle:UITableViewStylePlain];
dView.districtDictionary = allDistricts;
[self.navigationController pushViewController:dView animated:YES];

在第二个视图中,DistrictViewController 这样做:

NSArray *keyArray = [self.districtDictionary allKeys];
NSString *myKey = [keyArray objectAtIndex:indexPath.row];
NSArray *schoolArray = [self.districtDictionary objectForKey:myKey];
SchoolViewController *sView = [[SchoolViewController alloc]initWithStyle:UITableViewStylePlain];
sView.schoolArray = schoolArray;
[self.navigationController pushViewController:sView animated:YES];

我希望这对你有帮助。我在纯文本编辑器中输入了这一切。希望没有拼写错误。您需要在每个视图控制器中#import 关联的视图控制器!祝你好运。

【讨论】:

  • 我不得不编辑这个。我在发布后看到 plist 的结构为 NSArray->NSDictionary->NSDictionary.
  • 非常感谢。这里有很多信息可以让我再次朝着正确的方向前进。根据我试图浏览的信息,您认为我的 plist 结构最适合,还是您推荐其他东西?如果知道有帮助,最终结果是将与所选学校关联的 id 传递给将返回有关所选学校的数据的 api。
  • 希望这会有所帮助。专业提示:如果确实有帮助,您应该用小箭头投票。复选标记将答案标记为“已接受”。至于您的问题,您可能并不总是知道任何 plist 中的数据将包含什么。如果您事先知道,您可以创建视图来处理特定的字典键等。但是,更符合地区的第二种观点,您不知道密钥将是什么。如果您可以继续学习如何动态提取键和对象,那么您将一切就绪。
  • 太棒了。我会在几个小时后进入 XCode,看看现在烟雾是什么颜色的。到时候你身上会出现复选标记。像您这样进行彻底的解释总是有帮助的,而不是简单地剪切和粘贴代码答案,尽管我已经被一个好的 ole cut-n-pasted 保存了几次;)
  • 代码看起来很好,我没有错误或警告,但我无法转换到 DistrictViewController。我在 didSelect.. 方法中设置了一个断点,并且正在设置信息(districtDictionary 有信息)。它只是不推动新的表格视图。有什么想法吗?
【解决方案2】:

创建向下钻取表:

你可以这样做:

- (void)viewDidLoad
{
[super viewDidLoad];


NSArray *districts = [NSArray arrayWithObjects:@"district1", @"district2", @"district3", nil];
NSArray *states = [NSArray arrayWithObjects:@"NY", @"NJ", @"NO", @"StateOther1", @"StateOther2", nil];
NSArray *schools = [NSArray arrayWithObjects:@"", @"school1", @"school2", @"school3", @"school4", nil];

NSMutableDictionary *schoolSection = [NSMutableDictionary dictionary];
[schoolSection schools forKey:@"items"];
[schoolSection setObject:@"Shools" forKey:@"title"];

NSMutableDictionary *districtSection = [NSMutableDictionary dictionary];
[districtSection setObject:districts forKey:@"items"];
[districtSection setObject:@"Section" forKey:@"title"];

NSMutableDictionary *stateSection = [NSMutableDictionary dictionary];
[districtSection setObject:states forKey:@"items"];
[districtSection setObject:@"State" forKey:@"title"];

self.adresses = @[schoolSection, districtSection,stateSection];
}

下一步:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.adresses.count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSDictionary *currentSection = [self.adresses objectAtIndex:section];
if ([[currentSection objectForKey:@"isOpen"] boolValue]) {
    NSArray *items = [currentSection objectForKey:@"items"];
    return items.count;
}
return 0;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                  reuseIdentifier:CellIdentifier];
}

NSDictionary *currentSection = [self.adresses objectAtIndex:indexPath.section];
NSArray *items = [currentSection objectForKey:@"items"];
NSString *currentItem = [items objectAtIndex:indexPath.row];
cell.textLabel.text = currentItem;

return cell;
}

下一步:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
NSDictionary *currentSection = [self.adresses objectAtIndex:section];
NSString *sectionTitle = [currentSection objectForKey:@"title"];
BOOL isOpen = [[currentSection objectForKey:@"isOpen"] boolValue];
NSString *arrowNmae = isOpen? @"arrowUp":@"arrowDown";

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0.0f, 0.0f, 320.0f, 50.0f);
button.tag = section;
button.backgroundColor = [UIColor brownColor];
[button setTitle:sectionTitle forState:UIControlStateNormal];
[button addTarget:self action:@selector(didSelectSection:)
 forControlEvents:UIControlEventTouchUpInside];
[button setImage:[UIImage imageNamed:arrowNmae] forState:UIControlStateNormal];
return button;
}

下一步:

- (void)didSelectSection:(UIButton*)sender {
//get current section
NSMutableDictionary *currentSection = [self.adresses objectAtIndex:sender.tag];

//get elements of section
NSArray *items = [currentSection objectForKey:@"items"];

//create array of indexes
NSMutableArray *indexPaths = [NSMutableArray array];
for (int i=0; i<items.count; i++) {
    [indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:sender.tag]];
}

//get current state  of section is opened
BOOL isOpen = [[currentSection objectForKey:@"isOpen"] boolValue];

//set new state
[currentSection setObject:[NSNumber numberWithBool:!isOpen] forKey:@"isOpen"];

//animate of adding and deleting of cells
if (isOpen) {
    [self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationTop];
} else {
    [self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationTop];
}

//reload button image
NSString *arrowNmae = isOpen? @"arrowDown.png":@"arrowUp.png";
[sender setImage:[UIImage imageNamed:arrowNmae] forState:UIControlStateNormal];
}

您可以根据需要自定义此表。 可以下载的向下钻表示例here(点击“Скачать”按钮)

【讨论】:

  • 这很复杂,我会小心从俄罗斯网站下载东西:-)
  • 抱歉俄语。用英文注册会很长)有帮助吗?
  • 虽然此信息适用于向下钻取菜单,但我需要专门向下钻取 plist,因此 id 对我的情况没有多大帮助。
【解决方案3】:

您应该将区域数组传递给可以显示它们的新视图控制器。新的视图控制器应该有一个名为 Districts 的属性,我还建议创建一个初始化程序,该初始化程序接受一个设置此属性的区域数组。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSArray *districts = [[self.content objectAtIndex:indexPath.row] valueForKey:@"districts"];
    DistrictsViewController *districtsvc =  
     [[DistrictsViewController alloc] initWithNibName:nil 
                                               bundle:nil 
                                            districts:districts];
    [self.navigationController pushViewController:districtsvc];
}

从您的示例中,我不确定学校信息的来源,因此如果很难说您是否能够轻松创建单个通用视图控制器以从州深入到学校。

【讨论】:

    猜你喜欢
    • 2012-09-04
    • 1970-01-01
    • 1970-01-01
    • 2017-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-29
    • 1970-01-01
    相关资源
    最近更新 更多