简体   繁体   English

PFQueryTableView麻烦填充表视图

[英]PFQueryTableView trouble populating table view

I'm currently working on a PFQueryTableView and trying to get it to populate with data from an array that's pulled from ViewDidLoad. 我目前正在处理PFQueryTableView,并尝试使用从ViewDidLoad提取的数组中的数据填充它。 UPDATE: I've moved the function to an NSObject and implemented a singleton to be used across multiple classes in an effort to silo the operation away from the view controller. 更新:我已经将该函数移至NSObject并实现了一个单例,以便在多个类中使用,以使操作脱离视图控制器。 Below is the updated code: 下面是更新的代码:

  + (NSArray *)savedTankArray
{
    PFUser *userName = [PFUser currentUser];
    NSString *userNameString = [userName objectForKey:@"username"];


    PFQuery *query = [[PFQuery alloc] initWithClassName:@"SavedTanks"];
    [query whereKey:@"userName" equalTo:userNameString];
    [query setValue:@"SavedTanks" forKeyPath:@"parseClassName"];

    [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
     {
         if (!error)
         {
             // The find succeeded.
             NSLog(@"Successfully retrieved %lu Tanks.", objects.count);
             // Do something with the found objects
             for (PFObject *object in objects)
             {
                 NSString *tankNameString = [[NSString alloc] init];
                 NSString *tankCapacityString = [[NSString alloc] init];

                 tankNameString = [object valueForKey:@"tankName"];
                 tankCapacityString = [object valueForKey:@"tankCapacity"];

                 NSLog(@"%@", tankNameString);
                 NSLog(@"%@", tankCapacityString);

                 _savedTankArray = [objects objectAtIndex:0];

             }
         }
         else
         {
             // Log details of the failure
             NSLog(@"Error: %@ %@", error, [error userInfo]);
         }
     }];
NSLog(@"TANK NAME ARRAY: %@", _savedTankArray);
return [_savedTankArray savedTankObjects];

} }

While the NSLogs inside of the function work just fine, my problem is a bit expanded now, and I feel as though I'm missing something really simple here. 虽然该函数内部的NSLogs可以正常工作,但我的问题现在有所扩展,感觉好像在这里缺少了一些非常简单的东西。

By the time I get to @"TANK NAME ARRAY: %@"... obviously it's returning null because its outside of the portion that handles the query. 到我到达@“ TANK NAME ARRAY:%@” ...时,很明显它返回null,因为它在处理查询的部分之外。 This doesn't help me much if I'm trying to bring the data in through another class. 如果我试图通过另一个类将数据引入,这对我没有多大帮助。

I've tried so much over the past few days and I can't imagine I'm missing something terribly complex. 在过去的几天里,我已经做了很多尝试,但我无法想象我错过了一件非常复杂的事情。 I'm sorry for re-opening this but I can't wrap my head around it at this time. 抱歉,我重新打开了它,但目前无法绕开它。

Any ideas on how I could handle this? 关于如何处理这个问题有什么想法吗? I appreciate the help as always. 我一如既往地感谢您的帮助。

There may be other trouble, but for sure this line: 可能还有其他麻烦,但是请确保此行:

tableData = [NSArray arrayWithObjects:objects, nil];

is a mistake. 是一个错误。 This will create a single-element array whose first element is the array of results. 这将创建一个单元素数组,其第一个元素是结果数组。 I think you can fix and simplify as: 我认为您可以将其修复和简化为:

tableData = objects;

For your question on how to proceed, I think you can carry on in this class the way one would in any table view controller. 关于您如何进行的问题,我认为您可以像在任何表视图控制器中一样进行此类学习。 Answer the table datasource methods by referring to tableData (ie it's count for numberOfRowsInSection :, and tableData[indexPath.row] to configure a cellForRowAtIndexPath :, and so on). 通过引用tableData[indexPath.row]来回答表数据源方法(即,它是numberOfRowsInSection :的count ,而tableData[indexPath.row]用于配置cellForRowAtIndexPath :的依此类推)。

New answer for the edited new question: 编辑后的新问题的新答案:

It appears that the mixup is with calling the asynch service. 看来混淆是与调用异步服务。 I'll give two kinds of advice here. 我将在此处提供两种建议。 First, the simplest possible table-containing view controller that gets its data from an asynch service, and second, a little class that wraps the parse asynch service. 首先,是最简单的包含表的视图控制器,它从异步服务获取数据;其次,是包装解析后的异步服务的小类。 First the VC: 首先是VC:

// in a vc with a table view .m
@interface MyViewController ()
@property(weak,nonatomic) IBOutlet UITableView *tableView;
@property(strong,nonatomic) NSArray *array;  // this class keeps the array
@end

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [ClassThatHandlesMyQuery doQuery:^(NSArray *results) {
        self.array = results;
        [self.tableView reloadData];
    }];
}

See how the query class method in the other class takes a block parameter? 看看其他类中的查询类方法如何采用块参数? This is required because the query happens asynchronously. 这是必需的,因为查询是异步发生的。

// do the normal table view stuff
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.array.count;
}

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

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    PFObject *pfObject = self.array[indexPath.row];
    cell.textLabel.text = [pfObject valueForKey:@"someStringProperty"];
    return cell;
}

That should be pretty much all you need in the vc. 那应该是vc中所需的几乎所有东西。 Now let's look at your query method. 现在,让我们看看您的查询方法。 It makes three mistakes: (a) No block parameter to let the caller get the asynch result, (b) it mishandles the array in the query completion block, (c) at the end of the method, it wrongly supposes that a variable _savedTankArray is initialized, in the block. 它犯了三个错误:(a)没有块参数让调用者获得异步结果;(b)对查询完成块中的数组进行了错误处理;(c)在方法末尾,它错误地认为变量_savedTankArray在块中被初始化。 That code appears below the block, but it actually runs before the block runs.\\ 该代码显示在块下方,但实际上在块运行之前运行。\\

Let's fix all three problems. 让我们解决所有三个问题。 First declare a public method: 首先声明一个公共方法:

// ClassThatHandlesMyQuery.h
+ (void) doQuery:(void (^)(NSArray *))completion;

See how it takes a block as param? 看看如何将块作为参数? Now implement: 现在实施:

// ClassThatHandlesMyQuery.m
+ (void) doQuery:(void (^)(NSArray *))completion {

    // your query code.  let's assume this is fine
    PFUser *userName = [PFUser currentUser];
    NSString *userNameString = [userName objectForKey:@"username"];


    PFQuery *query = [[PFQuery alloc] initWithClassName:@"SavedTanks"];
    [query whereKey:@"userName" equalTo:userNameString];
    [query setValue:@"SavedTanks" forKeyPath:@"parseClassName"];

    [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
        if (!error) {
           // the job is MUCH simpler here than your code supposed.
           // log the result for fun
           NSLog(@"did we get objects? %@", objects);

           // hand it back to the caller
           // notice there's no array kept in this class.  it's not needed
           // and it would be awkward to do it at the class (not instance) level
           completion(objects);
        } else {
            NSLog(@"bad news from parse: %@", error);
            completion(nil);
        }
    }
    // this is important
    NSLog(@"hi mom!");
    // watch your log output.  'hi mom' will appear before either message
    // from the block.  why is that?  because that block runs later
    // after the network request completes.  but the hi mom NSLog runs
    // just before the network request starts.  this is why it's wrong to expect
    // any variable set in the block to be initialized here
}

Believe it or not, that's it. 信不信由你,就是这样。 You should be able to write exactly the mini view controller class and the mini query classes as described here, and see data from parse in a UITableView. 您应该能够完全按照此处所述编写小型视图控制器类和小型查询类,并在UITableView中查看解析数据。 I suggest you build something just like this (exactly like this) first just to get going 我建议您先构建像这样(完全像这样)的东西,然后开始

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM