使用 NSUserdefaults 填充 UITableView
Posted
技术标签:
【中文标题】使用 NSUserdefaults 填充 UITableView【英文标题】:Filling UITableView using NSUserdefaults 【发布时间】:2018-09-30 17:11:54 【问题描述】:我已经尝试了一段时间来让 tableview 正常工作。每天我都在取得一些进步,但我无法通过测试应用程序看到任何反馈,所以我不确定我做的事情是否正确。
我在谷歌上搜索了一段时间,查看了苹果文档,但我仍然不明白如何正确填充 UITableView。
第一个问题。我在哪里得到细胞?我需要制作一个自定义单元格来显示数据。解决方案似乎是使用 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
你不需要用一个答案来解决我的所有问题。即使解决问题/解释我需要做的事情就足够了,因为这至少可以让我向前迈进一点。
【问题讨论】:
在 Objective-C 中使用表格视图的例子不胜枚举。 3 年前的答案在今天和当时一样有效。多年来,表格视图的填充方式没有任何变化。从 Apple 自己的文档开始:Table View Programming Guide for ios。 查看 Apple 提供的众多示例应用之一:UITableView Fundamentals for iOS @rmaddy 似乎已经过时了。例如,我在“cellForRowAtIndexPath”中找不到[self configureCell: forIndexPath:
。
什么是过时的?我给了你两个有很多页面的链接。称为configureCell
的东西将是添加到视图控制器的自定义代码。
好的。对不起。目前正在筛选代码,希望我能找到我需要的东西。谢谢。
【参考方案1】:
首先,您不需要为UITableViewCell
定制笔尖,除非您有一个非常复杂的单元格。相反,您可以使用UITableView
的Attributes inspector
中的Prototype Cells
直接设计单元格布局。只需给Prototype Cells
一个数字并在UITableView
视图中设计适当的单元格布局。不要忘记为它们中的每一个设置identifier
,这将帮助您在cellForRowAtIndexPath
中加载正确的布局。
对于简单的单元格布局,您可以为单元格的每个元素提供一个tag
编号。这将帮助您在需要时访问它们,如下所示:
UILabel *label = [cell viewWithTag:100];
每个UITableView
都需要一个DataSource
,你将实现UITableViewDataSource
来提供:
-
表格的部分数
每个部分的项目数
单个单元格的内容
您只是在提供的源代码中执行了此操作,除了一件事: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;
【讨论】:
【参考方案2】:您的核心问题在于这一行 - if (indexPath.section == 1)
- 部分编号从 0
开始。因此,您返回nil
以获取第一部分(编号为 0)中的单元格,以及第二部分(编号为 1)之外的任何部分,这会导致崩溃。你应该永远不要从cellForRow
返回nil
。
话虽如此 - 我仍然建议您阅读 cmets 中提供的链接,您仍然可以学到一些有价值和/或有趣的东西。
【讨论】:
以上是关于使用 NSUserdefaults 填充 UITableView的主要内容,如果未能解决你的问题,请参考以下文章
使用 NSUserDefaults 保存 NSMutableArray 不起作用
(Swift) 将数组存储和检索到 NSUserDefaults