ios - 将 JSON 解析为 TableView 时出现 NSNull 长度错误

标签 ios json xcode uitableview

我正在尝试将 JSON 文件解析为我的 iOS 应用程序 TableView 。 当我启动应用程序时,我看到它解析数据,但是当我开始滚动时,应用程序立即崩溃并给我这个错误:Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull length] : 无法识别的选择器发送到实例 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 之前,我没有遇到这个错误。有人可以帮助我吗?

谢谢。

最佳答案

在解析 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 并执行类检查,您可以轻松修改它以适应其他数据类型。

--编辑-- 如果这是您将使用 JSON 的唯一地方,则更改

NSDictionary *tweet = [self.tweets objectAtIndex:indexPath.row]; 

NSDictionary *temp = [self.tweets objectAtIndex:indexPath.row];
NSDictionary *tweet = [NSDictionary nullFreeDictionaryWithDictionary:temp];

请注意,我将 nullFreeDictionaryWithDictionary 作为 NSDictionary 类的 Objective-C 类别。如果您不打算在其他任何地方使用此方法,则可以将其添加到 View Controller 的实现文件中。

关于ios - 将 JSON 解析为 TableView 时出现 NSNull 长度错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19643731/

相关文章:

java - Json Java : retrieve attributes with particular value

ios - Xcode 7 beta 在自动完成时崩溃 - NSRangeException

c# - 如何使用 Xamarin IOS 在 UITableView 中显示多列?

ios - 3d touch swift 3 不打开viewcontroller

javascript - 将对象作为参数传递给 Handlebars 模板中的 onclick 方法

javascript - 带有句法着色的 Json Pretty Print

ios - Apple 推荐的 Swift 日志记录方法

xcode - Xcode 10.0中缺少工具选项板

iphone - 在启动 iPhone 应用程序时禁用所有 UITabBarItems

ios - 如何配置 iOS 应用程序以在特定设备上运行?