如何将来自一个 JSON 请求的数据用于第二个 JSON 请求?

Posted

技术标签:

【中文标题】如何将来自一个 JSON 请求的数据用于第二个 JSON 请求?【英文标题】:How to use data from one JSON request for a second JSON request? 【发布时间】:2013-06-17 21:20:09 【问题描述】:

我已经成功地从 API 解析 JSON 并将其显示在 tableview 中。我收到的数据是他注册的用户的课程,但是我收到的数据只是班级 ID,所以我必须获取每个班级 ID 并发送单独的 API 请求以获取班级名称和教师。我可以在单独的视图控制器上成功执行此操作,因为如果用户单击该行,我可以获得班级 ID,但是,我想在单个表格视图上显示班级名称、教师和 ID。

所以我的问题是,我如何从表格视图中获取数据并为每个单元格发出单独的 api 请求并将数据显示到该单元格上?

我目前的数据:

如果我单击一行,我会得到以下数据:

2013-06-17 17:06:59.232 App[22024:c07] Class: Honors Pre-Calculus
2013-06-17 17:06:59.233 App[22024:c07] Teacher: Joe Shmo

如何在一个屏幕上同时显示两者?

这是我在第一个屏幕上检索类 ID 的代码:

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

if ([searchResults count] == 0) 
    return [tableView dequeueReusableCellWithIdentifier:
            NothingFoundCellIdentifier];



 else 

    ScheduleResultCell *cell = (ScheduleResultCell *)[tableView dequeueReusableCellWithIdentifier:SearchResultCellIdentifier];

    ScheduleResult *searchResult = [searchResults objectAtIndex:indexPath.row];


    NSString *classFormat = @"%@";
    NSString *classfks = searchResult.class_fk;
    NSString *classfk = [NSString stringWithFormat:classFormat, classfks];

    cell.idLabel.text = classfk;

    return cell;



这是我在第二个屏幕上检索课程信息的代码:

-(void)viewDidAppear:(BOOL)animated 
url = [NSString stringWithFormat:@"https://myapiurl.com/v1/classes/%@.json", idValue];

//show loader view
[SVProgressHUD showWithStatus:@"Loading Info"];

//fetch the feed
_feed = [[ClassFeed alloc] initFromURLWithString:url
                                      completion:^(JSONModel *model, JSONModelError *err) 

                                          //hide the loader view
                                          [SVProgressHUD dismiss];

                                          //json fetched
                                          NSLog(@"Class: %@", _feed.course);
                                          NSLog(@"Teacher: %@", _feed.teacher_full_name);
                                          NSLog(@"Meeting Info: %@", _feed.meeting_times);

                                          [self.tableView reloadData];

                                      ];


知道如何在一个屏幕上完成此操作吗?

这是我一直在尝试做的,但它似乎只在一个单元格上显示数据:

int count = [searchResults count];

    NSString *classFormat = @"%@";
    NSString *classfks = searchResult.class_fk;
    NSString *classfk = [NSString stringWithFormat:classFormat, classfks];

    for (int i=0; i < count; i++) 
        ScheduleResult *classInfo = [searchResults objectAtIndex:indexPath.row];
        NSString *classId = classInfo.class_fk;
        NSLog(@"i value: %d", i);
        url2 = [NSString stringWithFormat:@"https://apiurl.com/v1/classes/%@.json", classId];
        NSLog(@"url value: %@", url2);
        [SVProgressHUD showWithStatus:@"Loading Info"];
        _feed = [[ClassFeed alloc] initFromURLWithString:url2
                                              completion:^(JSONModel *model, JSONModelError *err) 

                                                  //hide the loader view
                                                  [SVProgressHUD dismiss];

                                                  //json fetched
                                                  NSLog(@"Class #%d: %@", i, _feed.course);
                                                  NSLog(@"Teacher #%d: %@", i,  _feed.teacher_full_name);
                                                  NSLog(@"Meeting #%d: %@", i,  _feed.meeting_times);
                                                  //name = namefk;
                                                  NSString *nameFormat = @"%@";
                                                  NSString *namefks = _feed.course;
                                                  NSString *namefk = [NSString stringWithFormat:nameFormat, namefks];
                                                  cell.nameLabel.text = namefk;

                                                  //[self.tableView reloadData];

                                              ];



                

我尝试使用不同的方法将数据添加到数组中,但我什至无法正确完成。

NSMutableArray* fullArray;
    fullArray = [[NSMutableArray alloc] init];
    [fullArray addObject:classfk];
    NSLog(@"array: %@", fullArray);

调试输出:

array: ( 10326
) 2013-06-17 23:36:45.488 App[30088:c07] array: ( 10371 ) 
2013-06-17 23:36:45.494 App[30088:c07] array: (
10420 )

如果这个问题没有多大意义,我想问一下如何从这个 JSON 提要(第一个 url)中获取 class_fk:

[
    "class_fk": 10326,
    "currently_enrolled": true,
    "date_withdrawn": null,
    "enrollment_pk": 147745,
    "fee_paid": false,
    "late_date_enrolled": null,
    "level": null,
    "student_fk": 132664,
    "update_date": "2012-08-27"
,

    "class_fk": 10371,
    "currently_enrolled": true,
    "date_withdrawn": null,
    "enrollment_pk": 147168,
    "fee_paid": false,
    "late_date_enrolled": null,
    "level": null,
    "student_fk": 132664,
    "update_date": "2012-08-23"

并使用它插入另一个 url 并从中获取课程和teacher_full_name? (第二个网址):


"class_id": "ADVMTG-40",
"class_pk": 10326,
"course": "Advisor Meeting",
"course_id": 7,
"course_type": "Advisory",
"description": "ADV: Shmo, J.",
"group_fk": 13980,
"primary_grade_level": "None",
"school_level": "Upper School",
"school_year": 2012,
"status": "Active",
"subject": "Administration",
"teacher_fk": 80404,
"teacher_full_name": "Joe Shmo",
"update_date": "2012-10-23T10:06:00-05:00",
"teachers": [
    
        "person_fk": 80404,
        "role": "Primary Teacher",
        "role_id": 1,
        "teacher_name": "Joe Shmo",
        "update_grades": true,
        "view_grades": true
    
],
"meeting_times": [
    
        "block": "Advisor Meetings",
        "block_abbreviation": "ADV",
        "day": "Friday",
        "end_time": null,
        "grading_period": "ALL",
        "room": null,
        "start_time": null
    
]

这是我的问题的解决方案(非常感谢您的帮助!):

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^



    //[searchResults sortUsingSelector:@selector(compareName:)];

    NSString *urlString = @"https://apiurl.com/v1/enrollments.json?student=132664";
    NSURL *Url = [NSURL URLWithString:urlString];
    NSURLRequest *request = [NSURLRequest requestWithURL:Url];
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    NSArray *classes = [NSJSONSerialization JSONObjectWithData:data
                                                       options:NSJSONReadingMutableContainers
                                                         error:nil];
    //NSLog(@"classes array: %@", classes);

    //now we loop through all classes
    for (NSMutableDictionary *class in classes) 

        //we get individual data for each class

        NSString *classID = class[@"class_fk"];
        //NSLog(@"classID: %@", classID);
        NSString *classUrlString = [NSString stringWithFormat:@"https://apiurl.com/v1/classes/%@.json", classID];
        NSURL *classUrl = [NSURL URLWithString:classUrlString];
        NSURLRequest *classRequest = [NSURLRequest requestWithURL:classUrl];


        NSData *classData = [NSURLConnection sendSynchronousRequest:classRequest returningResponse:nil error:nil];
        NSDictionary *classDictionary = [NSJSONSerialization JSONObjectWithData:classData
                                                                        options:NSJSONReadingMutableContainers
                                                                          error:nil];
        //NSLog(@"classes dictionary: %@", classDictionary);
        if (classes == nil) 
            dispatch_async(dispatch_get_main_queue(), ^
                [self showNetworkError];
            );
            return;

         else 
            if (classDictionary == nil) 
                NSLog(@"classes dictionary: %@", classDictionary);
             else 
        //probably should check here if array is empty before accessing first object
        //we shove the data from a classDictionary into class
        //class[@"teacher_full_name"] = classDictionary[@"teacher"][0];

                if (classDictionary[@"teacher_full_name"] == nil) 
                    class[@"teacher_full_name"] = @"Not Provided";
                 else 
                    class[@"teacher_full_name"] = classDictionary[@"teacher_full_name"];
                

                if (classDictionary[@"course"] == nil) 
                    class[@"course"] = @"Not Provided";
                 else 
                    class[@"course"] = classDictionary[@"course"];
                

                if (classDictionary[@"class_pk"] == nil) 
                    class[@"class_pk"] = @"Not Provided";
                 else 
                    class[@"class_pk"] = classDictionary[@"class_pk"];
                

                if (classDictionary[@"teachers"][0][@"person_fk"] == nil) 
                    class[@"person_fk"] = @"Not Provided";
                 else 
                 class[@"person_fk"] = classDictionary[@"teachers"][0][@"person_fk"];   
                

        ScheduleResult *searchResult = [[ScheduleResult alloc] init];
        searchResult.name = class[@"course"];
        searchResult.teacher = class[@"teacher_full_name"];
        searchResult.class_fk = class[@"class_pk"];

        [searchResults addObject:searchResult];


        NSLog(@"searchresult: %@", class[@"person_fk"]);
        //NSLog(@"course: %@ and teacher: %@", class[@"course"], class[@"teacher_full_name"] );
            
        

    



    dispatch_async(dispatch_get_main_queue(), ^
        //NSLog(@"dictionary: %@", classes);
        [self.tableView reloadData];
        [SVProgressHUD dismiss];
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    );

【问题讨论】:

今天的第三个“ios+JSON+UITableView”问题(至少)。 抱歉,我花了几天时间研究其他问题,但找不到与我想要完成的任务相关的问题。 我相信你,相信你。你们都做了。当然。 谢谢,希望我能得到答案,因为这周我已经筋疲力尽地试图解决这个问题。 你试过什么?您可以获取此提要并在检索到它时执行完成块。您认为获取该完成块中每个提要条目的详细信息会是什么样子?你会在哪里存储这些数据?你怎么知道你什么时候完成并准备好关闭你的“加载”视图? 【参考方案1】:

好的,这里有两个选项。

首先是(在后台队列中),获取初始提要。然后解析 JSON。然后遍历 JSON 并对数组中的每个字典进行 api 调用并将其推回字典中。然后告诉你的表重新加载到主队列中。

第二个选项稍微复杂一些。当用户滚动您的表格时,您可以在后台队列中进行调用以获取适当的数据并更新单元格。这与在单元格中异步加载图像的方式非常相似。除了这里,它不是图像,而是 JSON。您应该缓存这些数据,这样就不会发生两次,如果用户滚动太快并且加载数据的单元格不再出现在屏幕上,则取消请求。

我建议你保留第一个,保持简单和容易(虽然可能效率不高,因为你急于提前加载数据,但如果第一个 api 调用返回的记录数很小,那么它应该没问题,但如果它是 100 秒,那么选择第二个选项。

另外,请务必注意,您需要在第一个选项中同步执行所有操作(这就是您知道所有数据已下载的方式)。

好的,这是第一个选项。我用 NSURLConnection 做到了这一点。请注意,我不喜欢这个选项,但它很容易完成工作:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^

        //first we get all classes
        NSString *urlString = @"https://myapiurl.com/v1/classes";
        NSURL *url = [NSURL URLWithString:urlString];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
        NSArray *classes = [NSJSONSerialization JSONObjectWithData:data
                                                           options:NSJSONReadingMutableContainers
                                                             error:nil];

        //now we loop through all classes
        for (NSMutableDictionary *class in classes) 

            //we get individual data for each class

            NSString *classID = class[@"class_fk"];
            NSString *classUrlString = [NSString stringWithFormat:@"https://apiurl.com/v1/classes/%@.json", classID];
            NSURL *classUrl = [NSURL URLWithString:classUrlString];
            NSURLRequest *classRequest = [NSURLRequest requestWithURL:classUrl];


            NSData *classData = [NSURLConnection sendSynchronousRequest:classRequest returningResponse:nil error:nil];
            NSDictionary *classDictionary = [NSJSONSerialization JSONObjectWithData:classData
                                                                            options:NSJSONReadingMutableContainers
                                                                              error:nil];

            //probably should check here if array is empty before accessing first object
            //we shove the data from a classDictionary into class
            class[@"teachers_name"] = classDictionary[@"teachers"][0];
            class[@"course"] = classDictionary[@"course"];

        

        //now you've got an array of dictionaries that have teachers name and course in it.
        //we tell our tableview to reload the data on main queue
        dispatch_async(dispatch_get_main_queue(), ^
            [someTableView reloadData];
        );
    );

【讨论】:

感谢您的回复!尝试您的答案时,我有两个问题。我得到了初始提要并解析了 JSON,但我无法将数据添加到数组中(如果你看上面我发布了我尝试将数据放入数组中)。假设我确实将它添加到数组中,我将如何将它推回字典中? @acenario 检查我更新的答案。我不知道您的 ClassFeed 在内部是如何工作的,所以我无法对此发表评论。 @acenario 在你的代码中,你从哪里得到 'cell' 从行'cell.nameLabel.text = namefk;' ? 我完全想通了!非常感谢。最后一个问题,假设我想要 person_pk 脱离教师和 block_abbreviation,我将如何使用你的代码来完成? 我认为你的意思是 person_fk。就像我对 teacher_name 所做的那样,它是一样的,只是不同的键。

以上是关于如何将来自一个 JSON 请求的数据用于第二个 JSON 请求?的主要内容,如果未能解决你的问题,请参考以下文章

UITableView 中的第二个视图不会显示来自 JSON 的解析数据

如何根据 sencha 中 json 响应的第一个组合值填充第二个组合

如何在curl php中发送第二个请求时保留会话?

如何正确格式化来自背包.tf API 请求的 JSON 数据?

PHP + Mysql:来自第一个查询的动态表名,用于执行第二个查询

同一个活动Android Studio中的两个JSON解析方法