读取 plist 文件以填充表格时出错

Posted

技术标签:

【中文标题】读取 plist 文件以填充表格时出错【英文标题】:Error reading plist file for fill a table 【发布时间】:2010-06-06 13:44:33 【问题描述】:

我正在为 iPhone 开发一个应用程序,但我遇到了问题... 我有一些 textField 的视图,其中写入的信息保存在 plist 文件中。通过@class 和#import 声明,我将此视图控制器导入另一个管理表视图的控制器中。 我刚刚编写的代码似乎是正确的,但我的表已填满了 3 个相同的行... 我不知道为什么行是 3...

谁能帮帮我?

这是添加信息的代码:

@implementation AddWishController

@synthesize titleField, linkField, descField;

-(NSString *)dataFilePath 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    return [documentsDirectory stringByAppendingPathComponent:plistPath];


-(IBAction)done 
    NSMutableArray *array = [[NSMutableArray alloc] init];
    [array addObject:titleField.text];
    [array addObject:linkField.text];
    [array addObject:descField.text];
    [array writeToFile:[self dataFilePath] atomically:YES];

    [array release];

    [self dismissModalViewControllerAnimated:YES];

这个控制表:

#import "WishlistController.h"
#import "AddWishController.h"

@implementation WishlistController

@synthesize lista;

-(IBAction)newWish 
    AddWishController *add = [[AddWishController alloc] initWithNibName:@"AddWish" bundle:nil];
    [self.navigationController presentModalViewController:add animated:YES];
    [add release];


-(NSString *)dataFilePath 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    return [documentsDirectory stringByAppendingPathComponent:plistPath];


#pragma mark -
#pragma mark View lifecycle

- (void)viewDidLoad 
    [super viewDidLoad];


#pragma mark -
#pragma mark Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
    return 1;



- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
    NSArray *data = [[NSArray alloc] initWithContentsOfFile:[self dataFilePath]];
    return [data count];
    [data release];



- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) 
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
    

    NSString *filePath = [self dataFilePath];
    if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) 
        NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
        cell.textLabel.text = [array objectAtIndex:0];
        cell.detailTextLabel.text = [array objectAtIndex:2];

        NSLog(@"%@", array);
    

    return cell;

【问题讨论】:

【参考方案1】:

您的第一个问题是 NSArray writeToFile: 没有附加到现有文件。它只是将数组的完整内容写入文件。如果已存在同名文件,则该函数将覆盖它。

这意味着在您目前的代码中,您只能保存一个包含三个元素的数组。无论用户在 AddWishController 的视图中保存多少次,只有最后三个捕获的信息会保存在磁盘上。

其次,您的 WishlistController 配置错误。

这个:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
    NSArray *data = [[NSArray alloc] initWithContentsOfFile:[self dataFilePath]];
    return [data count];
    [data release];

将始终返回三个计数,因为文件中的数组始终具有三个元素。但是,即使这样也是错误的,因为您不想在单独的单元格中显示每个元素。您的cellForRowAtIndexPath: 非常清楚地将数组的第一个和最后一个元素放入每个单元格中。

至少在这里,您需要一个二维数组。更好的是,您需要一系列字典。每个字典将在-[AddWishController done] 中保存一个“完成”操作的结果。将每个字典添加到数组中。然后在您的 tableview 控制器中,返回表中行数的数组计数。然后在cellForRowAtIndexPath: 中,您应该在 indexpath.row 的数组元素中获取字典。然后从字典中的每个条目中获取单元格 UI 元素的文本。

通常,在应用退出之前,您也不会保存到文件。相反,将数组放在应用程序委托的属性中。在 AddWishController 创建一个属性来引用应用程序代表属性。在 tableview 控制器中执行相同的操作。现在您可以在第一个控制器中填充数组并从第二个控制器中读取它。

基本上,您需要从头开始。

【讨论】:

好的,感谢您的帮助...因此我必须创建两个 NSDictionaries 然后我必须将它们添加到 NSArray 中。对吗? 每次用户在调用done 方法的AddWishController 视图中输入条目时,您都会创建一个字典。关键是将每个愿望记录为字典,以便数组成为愿望列表。在表格中,每个单元格将显示一个愿望,因此表格是愿望列表。这里的基本思想是让数据模型反映表,让表反映数据模型。这样,一切都会自然而然地到位。【参考方案2】:

在WishController# load 中,你将三个不同的项目放入Array,所以当然,如果在WishlistController# tableView: numberOfRowsInSection: 你返回[data count] 作为行数,你得到三行。 另一方面,你在 WishlistController# tableView: cellForRowAtIndexPath: 你不看,应该呈现哪个条目,所以它总是只显示一个也是唯一的单元格。

如果您只想在表格中显示一个单元格,请将您的 WishlistController# tableView: numberOfRowsInSection: 替换为

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
    return 1;

如果你想显示多个愿望,你最好制作一个真实的对象,或者至少使用 NSDictionary,其中字典中的一个条目代表一个具有多个属性(标题、链接、描述)的对象 (=Wish)。



如果你在 Cocoa/Objective-C 的第一步你真的不想查看 NSDictionary,你也可以

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
    return floor([data count]/3);

然后在#tableView: cellForRowAtIndexPath:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
...
    if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) 
        int row = indexPath.row * 3;

        NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
        cell.textLabel.text = [array objectAtIndex:row];
        cell.detailTextLabel.text = [array objectAtIndex:row+2];

        NSLog(@"%@", array);
    

    return cell;

但这绝对仅适用于原型设计以获取展示的东西。你很快就会想研究 NSDictionary,在发布任何东西之前,你最好学习为你的数据模型使用适当的对象,例如使用 Core Data。真的。

还有两件事: - 在 WishlistController#tableView:numberOfRowsInSection: 行

[data release]; 

在 return 之后永远不会被调用。你可能想要

[data autorelease];

返回语句之前。 - 您不想读取文件 // 每次显示表格中的一行时都查找您的对象。创建一个数组作为控制器的实例变量并将其用作数据源。

【讨论】:

techzen 当然是对的:writeToFile 替换了文件的内容,所以你的文件中永远不会有多个愿望。所以,将数组分割成 3 个子项的事情不仅丑陋,而且完全没用。让自己熟悉保存数据的适当机制(再次重申:Core Data 是你的朋友)

以上是关于读取 plist 文件以填充表格时出错的主要内容,如果未能解决你的问题,请参考以下文章

从预填充的数据库中读取数据时出错

在 PhotoScroller 示例中填充 ImageData.plist

在 SWIFT 的表视图中填充自定义单元格时出错

Obj-C,根据plist值设置UILabel的颜色?

加载plist时数组下标不是整数

从 plist 字符串中读取 url 图像