使用NSUserdefaults填充UITableView

3

我一直试图让tableview正常工作。每天都有一点进展,但是我无法通过测试应用程序来看到任何反馈,因此我不确定自己是否正确操作。

我在谷歌上搜索了一段时间,查看了苹果文档,但我仍然不明白如何正确填充UITableView。

第一个问题。我从哪里获取该单元格?我需要制作自定义单元格来显示数据。解决方案似乎是使用nib文件,但我如何将其加载到另一个视图控制器上呢?

第二个问题。这个单元格显然应该具有动态内容。这些内容将从用户首选项中获取(我可以做到),但我不知道如何访问nib文件中的标签来实现这一点。

第三个问题。我想要有不同的部分(每个部分都有一种不同的单元格来显示),并带有不同的标题/页脚。像往常一样,这里我觉得文档不够详细。如何实现这一点?

第四个,也是最重要的问题。我不知道如何加载单元格。显然,它是通过cellForRowAtIndexPath完成的,但我不确定它是如何完成的。

最后,这是代码(以及堆栈跟踪)。希望你能帮助我。请不要将此关闭为重复。首先,它不应该是,其次,如果重复问题是在3年前由于库的更新情况而提出的,那么它就不是一个重复的问题。

#import "profileViewController.h"
#import "../Objs/CCProfileObject.h"

@interface profileViewController ()
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (strong, nonatomic) IBOutlet UITableViewCell *proxySampleCell;
@property (strong, nonatomic) IBOutlet UITableViewCell *ccSampleCell;
@end

@implementation profileViewController
@synthesize tableView;

- (void)viewDidLoad{
    // Dark mode, you can skip all of this
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(changeColor:)
                                                 name:@"darkToggle" object:nil];

    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    if([userDefaults boolForKey:@"darkMode"] == YES){
        [self changeColor:nil];
    }

}

- (void)viewDidAppear:(BOOL)animated{

    // Display profiles
    NSData *arrayData = [[NSUserDefaults standardUserDefaults] objectForKey:@"profileArray"];
    NSArray *profiles = [NSKeyedUnarchiver unarchiveObjectWithData:arrayData];

    for(NSObject *profile in profiles){
        if([profile class] == [CCProfileObject class])
        {
            CCProfileObject *ccProfile = (CCProfileObject*) profile;
            printf("%s\n", [ccProfile.getName UTF8String]);
            // Retrieve info from the object
            // Duplicate cell
            // Change appropriate labels
            // Add cell to a specific section
        }
        // Different types of cells will be added later
        // Concept is the same, what changes is the specific section and cell to duplicate

    }
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    if(indexPath.section == 1){
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"reusableShippingCell"];
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"reusableShippingCell"];
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
        }

        cell.textLabel.text = @"aldo";

        return cell;
    }



    return nil;
}
// This should be the only part that actually works (I use the same class twice because proxy and shipping are not yet done)
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    // Display profiles
    NSData *arrayData = [[NSUserDefaults standardUserDefaults] objectForKey:@"profileArray"];
    NSArray *profiles = [NSKeyedUnarchiver unarchiveObjectWithData:arrayData];
    NSMutableArray *sectionData = [[NSMutableArray alloc]init];

    for(NSObject *profile in profiles){
        // Credit
        if([profile class] == [CCProfileObject class])
        {
            [sectionData insertObject:@1 atIndex:0];
        }
        // Shipping
        else if([profile class] == [UIImage class])
        {
            [sectionData insertObject:@1 atIndex:1];
        }
        // Proxy
        else if([profile class] == [UIImage class])
        {
            [sectionData insertObject:@1 atIndex:2];
        }
    }

    int toReturn = 0;
    for(int i = 0; i < [sectionData count]; i++){
        toReturn += [[sectionData objectAtIndex:i] integerValue];
    }
    return toReturn;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    // Credit card section
    if(section == 0){
        return 1;
    } else if (section == 1){
        return 2;
    } else {
        return 3;
    }
}

`Assertion failure in -[UITableView _configureCellForDisplay:forIndexPath:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3698.52.10/UITableView.m:9453
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView (<UITableView: 0x16106d000; frame = (0 0; 375 812); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x1d0243bd0>; layer = <CALayer: 0x1d0030f60>; contentOffset: {0, -88}; contentSize: {375, 117}; adjustedContentInset: {88, 0, 83, 0}>) failed to obtain a cell from its dataSource (<profileViewController: 0x15ff14c70>)
First throw call stack:
(0x1837f6d8c 0x1829b05ec 0x1837f6bf8 0x1841e6fa0 0x18d4975b0 0x18d4941e8 0x18d493e00 0x18d492b1c 0x18d48e668 0x18d3cb770 0x18796d25c 0x1879713ec 0x1878ddaa0 0x1879055d0 0x18d7b56b4 0x18379f2bc 0x18379ea7c 0x18379c7b0 0x1836bcda8 0x18569f020 0x18d69d78c 0x1048a4f90 0x18314dfc0)
libc++abi.dylib: terminating with uncaught exception of type NSException

你不需要一步到位地解决我全部问题,即使只是修复一个问题或说明我需要做些什么也足够了,因为这样可以让我至少有所进展。


2
在Objective-C中使用表视图的例子不计其数。三年前的答案今天仍然有效。多年来,表视图的填充方式没有任何变化。从苹果自己的文档开始:iOS表视图编程指南 - rmaddy
请查看苹果提供的众多示例应用之一:iOS UITableView基础知识 - rmaddy
@rmaddy 似乎已经过时了。例如,我在 cellForRowAtIndexPath 中找不到 [self configureCell: forIndexPath: - G. Ramistella
什么是过时的?我给了你两个链接,有很多页面。而configureCell这个东西将会是添加到视图控制器的自定义代码。 - rmaddy
好的。抱歉。我正在浏览代码,希望能找到我需要的东西。谢谢。 - G. Ramistella
请阅读我写的教程。https://xcodenoobies.blogspot.com/2017/11/how-to-create-reusable-views-with.html - GeneCode
2个回答

0

首先,除非您有一个非常复杂的单元格,否则您不需要为UITableViewCell创建自定义nib。相反,您可以直接使用UITableViewAttributes inspector中的Prototype Cells设计单元格布局。只需为Prototype Cells指定一个数字,并在UITableView视图内设计适当的单元格布局即可。不要忘记为每个单元格设置identifier,这将帮助您在cellForRowAtIndexPath中加载正确的布局。

对于简单的单元格布局,您可以为单元格的每个元素提供一个tag号码。这将帮助您在需要时访问它们,如下所示:

UILabel *label = [cell viewWithTag:100];

每个UITableView都需要一个DataSource,您将实现UITableViewDataSource来提供以下内容:
  1. 表格的部分数量
  2. 每个部分的项目数量
  3. 单个单元格的内容

您已经在提供的源代码中完成了这一点,除了一件事: cellForRowAtIndexPath需要返回一个UITableViewCell,而不是nil。如果您返回nil,则会抛出异常。

因此,一个有效的cellForRowAtIndexPath可能如下所示:

@implementation ViewController {
    NSArray *data;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    // You load your data from NSUserDefault here
    data = [self loadDataFromNSUserDefault];
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *cellIdentifier = @"defaultCell";
    if (indexPath.section == 0) {
        cellIdentifier = @"customCell1";
    } else if (indexPath.section == 1) {
        cellIdentifier = @"customCell2";
    }

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    // Access your view's children using their `tag`
    UILabel *title = [cell viewWithTag:100];
    UIImageView *icon = [cell viewWithTag:101];

    // Set content
    title.text = [[data objectAtIndex:indexPath.row] objectForKey:@"title"];
    icon.image = [UIImage imageNamed:[[data objectAtIndex:indexPath.row] objectForKey:@"icon"]];

    return cell;
}

0

你的核心问题在于这一行代码 - if (indexPath.section == 1) - section 的编号从 0 开始。因此,你会为第一个 section(编号为 0)和第二个 section(编号为 1)之后的任何 section 返回 nil,这会导致崩溃。你应该永远不要cellForRow 中返回 nil

话虽如此 - 我仍然建议你阅读评论中提供的链接,你可能会学到一些有价值和/或有趣的东西。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接