我正在尝试将JSON文件解析为我的iOS应用程序表视图。
当我启动应用程序时,我发现它会解析数据,但是当我开始滚动应用程序时,会立即崩溃并给我这个错误:Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull length]: unrecognized selector sent to instance 0x38094a60'
我的代码:
#import "FirstViewController.h"
#import "YoutubePost.h"
@interface FirstViewController ()
{
NSInteger refreshIndex;
NSArray *title;
NSArray *about;
NSArray *views;
NSArray *rating;
NSArray *votes;
NSArray *content;
}
@end
@implementation FirstViewController
@synthesize tweets;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(@"Videos", @"Videos");
self.tabBarItem.image = [UIImage imageNamed:@"newtab1"];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.myTableView.separatorColor = [UIColor clearColor];
[self issueLoadRequest];
[self setNeedsStatusBarAppearanceUpdate];
}
-(UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;
}
#pragma mark - Table view data source
- (void)issueLoadRequest
{
// Dispatch this block asynchronosly. The block gets JSON data from the specified URL and performs the proper selector when done.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"my-site.php/file.json"]];
[self performSelectorOnMainThread:@selector(receiveData:) withObject:data waitUntilDone:YES];
});
}
- (void)receiveData:(NSData *)data {
// When we have the data, we serialize it into native cocoa objects. (The outermost element from twitter is
// going to be an array. I JUST KNOW THIS. Reload the tableview once we have the data.
self.tweets = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
[self.myTableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.tweets.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = @"YoutubePost";
YoutubePost *cell = (YoutubePost *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"YoutubePost" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
// The element in the array is going to be a dictionary. I JUST KNOW THIS. The key for the tweet is "text".
NSDictionary *temp = [self.tweets objectAtIndex:indexPath.row];
NSDictionary *tweet = [self nullFreeDictionaryWithDictionary:temp];
cell.title.text = [tweet objectForKey:@"title"];
cell.views.text = [tweet objectForKey:@"views"];
return cell;
}
- (NSDictionary *)nullFreeDictionaryWithDictionary:(NSDictionary *)dictionary
{
NSMutableDictionary *replaced = [NSMutableDictionary dictionaryWithDictionary:dictionary];
// Iterate through each key-object pair.
[dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *stop) {
// If object is a dictionary, recursively remove NSNull from dictionary.
if ([object isKindOfClass:[NSDictionary class]]) {
NSDictionary *innerDict = object;
replaced[key] = [NSDictionary nullFreeDictionaryWithDictionary:innerDict];
}
// If object is an array, enumerate through array.
else if ([object isKindOfClass:[NSArray class]]) {
NSMutableArray *nullFreeRecords = [NSMutableArray array];
for (id record in object) {
// If object is a dictionary, recursively remove NSNull from dictionary.
if ([record isKindOfClass:[NSDictionary class]]) {
NSDictionary *nullFreeRecord = [NSDictionary nullFreeDictionaryWithDictionary:record];
[nullFreeRecords addObject:nullFreeRecord];
}
else {
if (object == [NSNull null]) {
[nullFreeRecords addObject:@""];
}
else {
[nullFreeRecords addObject:record];
}
}
}
replaced[key] = nullFreeRecords;
}
else {
// Replace [NSNull null] with nil string "" to avoid having to perform null comparisons while parsing.
if (object == [NSNull null]) {
replaced[key] = @"";
}
}
}];
return [NSDictionary dictionaryWithDictionary:replaced];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 397;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int storyIndex = [indexPath indexAtPosition: [indexPath length] - 1];
NSString * storyLink = [[tweets objectAtIndex: storyIndex] objectForKey:@"link"];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:storyLink]];
// Spit out some pretty JSON for the tweet that was tapped. Neato.
NSString *formattedJSON = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:[self.tweets objectAtIndex:indexPath.row] options:NSJSONWritingPrettyPrinted error:nil] encoding:NSUTF8StringEncoding];
NSLog(@"tweet:\n%@", formattedJSON);
}
@end
在我安装新的Xcode 5之前,我没有收到此错误。有人能帮助我吗?
感谢。
答案 0 :(得分:8)
在解析JSON结果时,我一直在做的是避免这种情况,使用以下方法将NSNull
的每个实例替换为空字符串(@""
):
+ (NSDictionary *)nullFreeDictionaryWithDictionary:(NSDictionary *)dictionary
{
NSMutableDictionary *replaced = [NSMutableDictionary dictionaryWithDictionary:dictionary];
// Iterate through each key-object pair.
[dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *stop) {
// If object is a dictionary, recursively remove NSNull from dictionary.
if ([object isKindOfClass:[NSDictionary class]]) {
NSDictionary *innerDict = object;
replaced[key] = [NSDictionary nullFreeDictionaryWithDictionary:innerDict];
}
// If object is an array, enumerate through array.
else if ([object isKindOfClass:[NSArray class]]) {
NSMutableArray *nullFreeRecords = [NSMutableArray array];
for (id record in object) {
// If object is a dictionary, recursively remove NSNull from dictionary.
if ([record isKindOfClass:[NSDictionary class]]) {
NSDictionary *nullFreeRecord = [NSDictionary nullFreeDictionaryWithDictionary:record];
[nullFreeRecords addObject:nullFreeRecord];
}
else {
if (object == [NSNull null]) {
[nullFreeRecords addObject:@""];
}
else {
[nullFreeRecords addObject:record];
}
}
}
replaced[key] = nullFreeRecords;
}
else {
// Replace [NSNull null] with nil string "" to avoid having to perform null comparisons while parsing.
if (object == [NSNull null]) {
replaced[key] = @"";
}
}
}];
return [NSDictionary dictionaryWithDictionary:replaced];
}
当然,这依赖于JSON返回格式是字典,但如果用id
替换所有参数类型并执行类检查,则可以轻松修改它以适应其他数据类型。
- Edit-- 如果这是您将使用JSON的唯一地方,那么请更改
NSDictionary *tweet = [self.tweets objectAtIndex:indexPath.row];
到
NSDictionary *temp = [self.tweets objectAtIndex:indexPath.row];
NSDictionary *tweet = [NSDictionary nullFreeDictionaryWithDictionary:temp];
请注意,我有nullFreeDictionaryWithDictionary
作为NSDictionary类的Objective-C类别。如果您不打算在其他任何地方使用此方法,您可以将其添加到视图控制器的实现文件中。