首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >嵌套查询块将数据加载到UITableView中

嵌套查询块将数据加载到UITableView中
EN

Stack Overflow用户
提问于 2015-02-12 05:44:08
回答 1查看 196关注 0票数 0

我有一个以UIViewController作为子视图的tableView。表视图有三个部分,我使用了问题PFQueryTableViewController with 3 Sections的答案来完成这一任务,但是数据并没有被加载到表中。我正在viewWillAppear的后台执行我的查询。我担心这是由于嵌套的查询块造成的。我怎么才能解决这个问题?这是我的代码:

代码语言:javascript
复制
-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];


    PFQuery *gameQuery = [PFQuery queryWithClassName:@"Game"];
    [gameQuery whereKey:@"players" equalTo:[PFUser currentUser]];
    [gameQuery orderByDescending:@"createdAt"];

    [gameQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error){

        self.myTurn = [NSMutableArray array];
        self.theirTurn = [NSMutableArray array];
        self.gameOver = [NSMutableArray array];
        self.allGames = [NSArray array];

        for(PFObject *object in objects)
        {
            if([object objectForKey:@"isOver"] == [NSNumber numberWithBool:YES])
            {
                [self.gameOver addObject:object];
            }

            else
            {

                PFRelation *relation = [object relationForKey:@"whoseTurn"];
                PFQuery *relQuery = [relation query];
                [relQuery findObjectsInBackgroundWithBlock:^(NSArray *userObjects, NSError *error1){


                    NSMutableArray *arr = [NSMutableArray array];
                    for(PFUser *user in userObjects)
                    {
                        [arr addObject:user.objectId];
                    }

                    if([arr containsObject:[PFUser currentUser].objectId])
                    {
                       [self.myTurn addObject:object];
                    }

                    else
                        [self.theirTurn addObject:object];

                }];
            }

        }

        self.allGames = [NSArray arrayWithObjects:self.myTurn, self.theirTurn, self.gameOver, nil];
        [self.tableView reloadData];

    }];

}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return [self.allGames count];
}


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

    return [[self.allGames objectAtIndex:section] count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *MyIdentifier = @"MyIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];

    if (cell == nil)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                       reuseIdentifier:MyIdentifier];
    }

    PFObject *object = self.allGames[indexPath.section][indexPath.row];
    cell.textLabel.text = [object objectForKey:@"numPlayers"];

    return cell;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-02-12 09:46:02

下面是你可以做的事情:

代码语言:javascript
复制
-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    PFQuery *gameQuery = [PFQuery queryWithClassName:@"Game"];
    [gameQuery whereKey:@"players" equalTo:[PFUser currentUser]];
    [gameQuery orderByDescending:@"createdAt"];

    [gameQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error){

        @synchronized(self.allGames) {
            self.allGames = [NSArray arrayWithObjects: [NSMutableArray array], [NSMutableArray array], [NSMutableArray array], nil];
            // These two instance variables contain values used in asynchronous blocks, to know how much responses are still expected
            self.expectedNbGames = [objects count];
            self.fetchedNbGames = 0;
        }

        for(PFObject *object in objects)
        {
            if([object objectForKey:@"isOver"] == [NSNumber numberWithBool:YES])
            {
                @synchronized(self.allGames) {
                    [((NSMutableArray *)self.allGames[2]) addObject:object];
                    self.fetchedNbGames++;
                }
            }

            else
            {
                PFRelation *relation = [object relationForKey:@"whoseTurn"];
                PFQuery *relQuery = [relation query];
                [relQuery findObjectsInBackgroundWithBlock:^(NSArray *userObjects, NSError *error1){

                    NSMutableArray *arr = [NSMutableArray array];
                    for(PFUser *user in userObjects)
                    {
                        [arr addObject:user.objectId];
                    }

                    @synchronized(self.allGames) {
                        if([arr containsObject:[PFUser currentUser].objectId])
                        {
                            [((NSMutableArray *)self.allGames[0]) addObject:object];
                        }

                        else
                            [((NSMutableArray *)self.allGames[1]) addObject:object];
                        }

                        self.fetchedNbGames++;
                        if (self.fetchedNbGames == self.expectedNbGames)
                        {
                            // We have now received the last expected response, it's time to sort everything again in descending order based on the "createdAt" value
                            NSSortDescriptor *dateDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"createdAt" ascending:NO];
                            NSArray *sortDescriptors = [NSArray arrayWithObject:dateDescriptor];
                            // self.allGames[0] is already sorted anyway because it's been left untouched from the initial PFQuery
                            self.allGames[1] = [self.allGames[1] sortedArrayUsingDescriptors:sortDescriptors];
                            self.allGames[2] = [self.allGames[2] sortedArrayUsingDescriptors:sortDescriptors];
                            // And... reload one last time!
                            dispatch_async(dispatch_get_main_queue(), ^{
                                [self.tableView reloadData];
                            });
                        }
                    }

                    dispatch_async(dispatch_get_main_queue(), ^{
                        [self.tableView reloadData];
                    });
                }];
            }

        }

        [self.tableView reloadData];
    }];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    @synchronized(self.allGames) {
        return [self.allGames count];
    }
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    @synchronized(self.allGames) {
        return [[self.allGames objectAtIndex:section] count];
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *MyIdentifier = @"MyIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];

    if (cell == nil)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                       reuseIdentifier:MyIdentifier];
    }

    @synchronized(self.allGames) {
        PFObject *object = self.allGames[indexPath.section][indexPath.row];
        cell.textLabel.text = [object objectForKey:@"numPlayers"];
    }

    return cell;
}

@synchronized()构造用于确保线程安全,因为您将从不同的线程(主线程,但也是来自解析答复的异步块)访问(读写) sell.allGames数组。

请注意,我们要从异步块中多次分派reloadData,因为您的代码目前无法知道所有块何时完成运行。我们需要在主线程上分派这个调用,因为它将触发UI更新,而这些更新总是必须在主线程上完成。

看看这是否有效,也许您可以使用属性来稍微改进它(避免每次使用@synchronized()时编写self.allGames)。

UPDATE:我改进了我的答案,提供了一种在收到所有回复后重新排序的方法。这个过程涉及创建两个新的实例变量(名为fetchedNbGamesexpectedNbGames的整数),它们必须在收到来自Parse的每个响应后进行更新和相互比较。一旦接收到所有响应,结果数组就可以重新排序(由于请求被异步发送和处理,结果数组可能被无序排序),表视图再次刷新。

这是未经测试的,可能有很大的改进空间,但这取决于您调整它以满足您的需要,您得到了基本的想法。

还请参阅this other SO thread,以更直观地解释与线程和异步调用相关的问题。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28470167

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档