使用节标题和节行解析 JSON

Posted

技术标签:

【中文标题】使用节标题和节行解析 JSON【英文标题】:Parsing JSON with section headers and section rows 【发布时间】:2013-11-26 18:06:43 【问题描述】:

我正在努力解决看起来应该很简单的事情。将以下 JSON 解析为 tableview,将类别名称作为部分标题以及搜索这些部分的详细信息。这是我的 JSON。如您所见,我有多个类别(例如婴儿和其他婴儿用品等),在这些类别下是我想要在每个类别下的详细信息。


"items": 
    "post": 
        "categories": [
            [
                "Baby",
                
                    "title": "trying with category id again",
                    "price": "3344.55",
                    "category_key": "3"
                
            ],
            [
                "Cars & Trucks",
                
                    "title": "putting in title",
                    "price": "3000.99",
                    "category_key": "7",
                
            ],
            [
                "Cars & Trucks",
                
                    "title": "adding another listing",
                    "price": "400000.99",
                    "category_key": "7"
                
            ],

这是我的代码。总的来说,我有 14 个类别。我下面的代码似乎解析了 JSON,它知道有 14 个类别,但值显示为 0、1、2、3 等(键),而不是 category_name 的实际值。

- (void)fetchedData:(NSData *)responseData 

//parse out the json data

NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];


_tableData = [json objectForKey:@"items"][@"post"][@"category_name"];

_filteredItemArray = [_tableData valueForKey:@"category_name"];


dispatch_async(dispatch_get_main_queue(), ^
    [m_tableView reloadData];

);
//_buyCategory =  json[@"items"][@"post"];
NSLog(@"Items in Dictionary: %@", _filteredItemArray); /// I CAN SEE ALL MY DATA
NSLog(@"Array Count: %u", [_filteredItemArray count]); ///THE COUNT SHOWS 14


这是我的表格数据:

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section


    return [[_filteredItemArray objectAtIndex:section] objectForKey:@"category_name"]; ///APP CRASHES HERE...BUT THIS SEEMS RIGHT TO ME



- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

// Return the number of rows in the section.

return [[[[_tableData objectAtIndex:section] objectAtIndex:1] allKeys] count];


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

static NSString *CellIdentifier = @"Cell";
CustomBuyMainCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

NSDictionary* tempResults = [_tableData objectAtIndex:indexPath.row];

_buyTitle = [tempResults objectForKey:@"title"];
_buyPrice = [tempResults objectForKey:@"price"];

cell.buyMainTitle.text = _buyTitle;
cell.buyMainPrice.text = _buyPrice;
//NSLog(@"TempResults: %@", _buyTitle);

return cell;


#pragma mark - Segue
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
if ([[segue identifier] isEqualToString:@"showDetail"]) 
    BuyDetail *buyDetail = [segue destinationViewController];

    // In order to manipulate the destination view controller, another check on which table (search or normal) is displayed is needed
    if(sender == self.searchDisplayController.searchResultsTableView) 

        //buyDetail.itemDetailArray = [self.tableData objectAtIndex:[m_tableView indexPathForSelectedRow].row];
    
    else 

        //buyDetail.itemDetailArray = [self.tableData objectAtIndex:[m_tableView indexPathForSelectedRow].row];
    



我的 php

 $channel ['json']['categories'][$category_name][]['items'][] = array(
    'ID' => $ID,
    'title' => $title,
    'price' => $price,
    'date_time' => $date_time,
    'description' => $description,

   );
   
$channels = array($channel);
$json = json_encode($channel);
header('Content-type: application/json');
echo $json;

我认为我严重遗漏了一些东西,因此非常感谢任何帮助。

【问题讨论】:

您想将“Baby”和“Other Baby Stuff”作为部分标题的标题吗? 是的,但我现在有 14 个类别,这些类别将会增长。所以我不想在我的代码中指定类别名称。我只想解析出类别名称。这有意义吗? 检查我修改后的答案。希望这就足够了 在您的 JSON 中,您是否碰巧在 "items": "post": "category_name": 下列出了一个名为 "category_name" 的类别?如果不是,我无法理解您的代码中的_filteredItemArray 不是nil 谢谢!对不起,什么是“结果”?和 tempDictionary ......你的意思是“temp”吗?它在这两个地方给了我错误。 【参考方案1】:

经过扩展讨论,您的 JSON 似乎已标准化,我们可以继续使用以下代码:

- (void)fetchedData:(NSData *)responseData

    NSError *error;

    //declare "NSDictionary *jsonDictionary;" in the .h of this class
    //no need to make an array, simply use the response dictionary
    jsonDictionary = [NSJSONSerialization JSONObjectWithData:responseData 
                                                     options:kNilOptions
                                                       error:&error];
   //get all keys (since there may be "holes" in the numbering)
   //declare "NSArray *arrAllKeys;" in the .h of this class
   arrAllKeys = [[jsonDictionary objectForKey:@"items"] allKeys];

    [m_tableView reloadData];

    //NOTE: No need for _tableData or _filteredItemArray objects


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

    return [[jsonDictionary objectForKey:@"items"] count];


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 

    return [[[[jsonDictionary objectForKey:@"items"]
                              objectForKey:[arrAllKeys objectAtIndex:section]]
                              objectForKey:@"details"] count];


- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section

    return [[[jsonDictionary objectForKey:@"items"]
                             objectForKey:[arrAllKeys objectAtIndex:section]]
                             objectForKey:@"categories"];


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

    static NSString *CellIdentifier = @"Cell";
    CustomBuyMainCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) 
        cell = [[[NSBundle mainBundle] loadNibNamed:@"CustomBuyMainCell"
                                              owner:self
                                            options:nil]
                                      objectAtIndex:0];
    

    NSString *categoryItemName = [[[[[jsonDictionary objectForKey:@"items"]
                                                     objectForKey:[arrAllKeys objectAtIndex:indexPath.section]]
                                                     objectForKey:@"details"]
                                                    objectAtIndex:indexPath.row]
                                                     objectForKey:@"title"];

    NSString *categoryItemPrice = [[[[[jsonDictionary objectForKey:@"items"]
                                                     objectForKey:[arrAllKeys objectAtIndex:indexPath.section]]
                                                     objectForKey:@"details"]
                                                    objectAtIndex:indexPath.row]
                                                     objectForKey:@"price"];

    [cell.buyMainTitle setText:categoryItemName];
    [cell.buyMainPrice setText:categoryItemPrice];

    return cell;

    //NOTE: No need for tempResults or _buyTitle or _buyPrice objects anymore
    //(unless you are using _buyTitle & _buyPrice elsewhere as well)


-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

    if ([[segue identifier] isEqualToString:@"showDetail"]) 
        BuyDetail *buyDetail = [segue destinationViewController];

        //declare and synthesize in the BuyDetail.h
        //"@property (nonatomic, strong) NSDictionary *selectedCategoryItem;"

        int mySelectedSection = [m_tableView indexPathForSelectedRow].section;
        int mySelectedRowInSection = [m_tableView indexPathForSelectedRow].row;

        buyDetail.selectedCategoryItem = [[[[jsonDictionary objectForKey:@"items"]
                                                            objectAtIndex:[arrAllKeys objectAtIndex:mySelectedSection]]
                                                            objectForKey:@"details"]
                                                           objectAtIndex:mySelectedRowInSection];

        //NOTE: selectedCategoryItem is a dictionary object in your BuyDetail
        //handle it like as you would handle any other dictionary
    


distance 的值是整数,所以我们需要这样获取它:

int distanceInMiles = [[[[[[[jsonDictionary objectForKey:@"items"]
                                            objectForKey:[arrAllKeys objectAtIndex:indexPath.section]]
                                            objectForKey:@"details"]
                                           objectAtIndex:indexPath.row]
                                            objectForKey:@"distance"]
                                            objectForKey:@"miles"] intValue];

//assuming categoryItemDistance is NSString object
categoryItemDistance = [NSString stringWithFormat:@"%d",distanceInMiles];

【讨论】:

哦,如此接近!我只是在这里遇到错误:在@interface 上看不到 NSArray: if (cell == nil) cell = [[[NSBundle mainBundle] loadNibNamed:@"CustomBuyMainCell" owner:self options:nil] objectAtIndexPath:0]; @mreynol : 哦,又是屎...应该是cell = [[[NSBundle mainBundle] loadNibNamed:@"CustomBuyMainCell" owner:self options:nil] objectAtIndex:0]; ...不是objectAtIndexPath:0,应该是objectAtIndex:0。原因:NSArray 没有提供任何名为-objectAtIndexPath: 的实例方法。它提供objectAtIndex:。这只是我的几个错字之一:/。我的错,我会更新我的答案...... 好的,清除了错误!但是当我现在运行时它崩溃了:( -[__NSCFDictionary objectAtIndex:]:无法识别的选择器发送到实例 0x14597b60 2013-11-29 09:40:42.999 OnTradar[20438:60b] *** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:'-[__NSCFDictionary objectAtIndex:]:无法识别的选择器发送到实例 0x14597b60' @mreynol : ohhhhhhh... 在items 中,您有“1”作为键的名称,然后它的值就是其余部分。同样,您有一个名为“2”的键,它是各自的值,依此类推。嗯......它看起来就像一个数组......但......不是。没有问题。让我们看看

以上是关于使用节标题和节行解析 JSON的主要内容,如果未能解决你的问题,请参考以下文章

视频第2,3节 Spring Boot完美使用FastJson解析JSON数据

[Python3]JSON解析

在 Swift 问题中为 iOS 应用程序解析 JSON

JSONObject 和 GSON 解析 JSON 数据详解(转)

Json丨使用 JsonUtility 创建并解析 Json

Json丨使用 JsonUtility 创建并解析 Json