【问题标题】:Variable not updating outside of block变量不在块外更新
【发布时间】:2013-11-09 16:38:22
【问题描述】:

所以我的代码如下。我正在尝试根据分数对可变数组进行排序。我已经在字典中为每个酒吧的标题分配了分数。但是当我调用keyssortedbyvalue 时,它​​对它们进行了很好的排序。正如日志(下图)所见,但由于某种原因,此更改并未反映在块外的变量 sortedPubArray 中。任何想法为什么?

注意:我为 sortedPubArray 创建了一个单独的变量,因此更容易看到它没有反映在块外的变量中。

//Method to get us the pubs for a specific user
+(NSMutableArray *)PubsForUser:(PFUser *)passedUser
{
//First things first let's create our array to represent the array of pubs which should be returned when our query finally executes (down there somewhere)
__block NSMutableArray *pubArray = [[NSMutableArray alloc] init];
//And the sorted version, which we will ultimately return
__block NSMutableArray *sortedPubArray = [[NSMutableArray alloc] init];

//Get the user passed in so we can get there preferences
PFUser *currentUser = passedUser;
//Get all the keys into a local array so we can traverse through and find out what user likes
NSMutableArray *allTypes = [NSMutableArray arrayWithArray:[currentUser allKeys]];
//first we have to remove the username and email keys from the array
[allTypes removeObject:@"username"];
[allTypes removeObject:@"email"];

NSMutableArray *userTypes = [[NSMutableArray alloc] init];

//Now traverse through array and if the type is set to true add it to our local userTypes array
//For each category in the user
for (NSString *typeKey in allTypes) {
    //If the user has selected this category as one of their choices
    if ([currentUser[typeKey]  isEqual: @YES]) {
        //Then add the category name (ie the key) to our local property representing the users choosen style of pubs
        [userTypes addObject:typeKey];
    }
}

//Create our array of queries
NSMutableArray *queryArray = [[NSMutableArray alloc] init];

//Traverse through our array of user categories and create a query for each one.
for (NSString *style in userTypes) {

    //Set up Parse query
    PFQuery *pubQuery = [PFQuery queryWithClassName:@"Pub"];
    [pubQuery whereKey:style equalTo:@YES];

    //Add query to array of queries
    [queryArray addObject:pubQuery];

}



//Now create final query which will contain each of our subqueries
PFQuery *totalQuery = [PFQuery orQueryWithSubqueries:queryArray];
[totalQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
    //Do error checking
    if (error) {
        //Log out error message to user
        UIAlertView *queryErrorAlert = [[UIAlertView alloc] initWithTitle:@"Whoops!" message:@"Houston there's a problem! Try again in 5 minutes or drop us an email if this keep's happening at gordon@outerapp.com" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [queryErrorAlert show];
    } //It worked!
    else {
        //So now we have an array of PFObjects ie Pubs!
        [pubArray addObjectsFromArray:objects];

        //Now sort the array by number of hits, ie number of categories the same. So that the pub/club most tailored to the users tastes is top of the array

        //First create array to contain all pub categories so we're not comparing user's restaurant categories with the pub (this could crash the app as you can see below, we'd be trying toaccessing properties of the pub which don't exist
        NSMutableArray *pubTypes = [NSMutableArray arrayWithArray:[[objects objectAtIndex:0] allKeys]];
        //And set up a dictionary to keep the score of each pub (score is how many of the same types it has as user
        NSMutableDictionary *pubScores = [[NSMutableDictionary alloc] init];


        //This requires us to iterate through the array assinging a value to the variable representing the "likeness" of the pub to the user. So the higher the score, the more hits
        for (PFObject *pub in pubArray) {

            int pubScore = 0;

            //So now we should calculate the total score, by iterating through and adding 1 each time it's true
            for (NSString *category in pubTypes) {

                //Test if the pub and the user's category choice is the same. ie this will iterate through student, theme, gastropub etc and everytime they are the same we add 1, and different -1
                if (pub[category] == currentUser[category]){

                    //They're the same so add to the score
                    pubScore++;

                } //If they're not the same
                else {

                    //Subtract one
                    pubScore--;

                }
            }

            //Now store the score of the pub in our dictionary
            [pubScores setValue:[NSNumber numberWithInt:pubScore] forKey:[pub objectForKey:@"PubName"]];
        }



        //And now finally simply sort the array by score (the first with the highest score), so that the pub with the best rating is at the top of the feed
        //To do this, we can use an inbuilt NSMutableDictionary method to output our keys in descending order of magnitude
        sortedPubArray = [NSMutableArray arrayWithArray:[pubScores keysSortedByValueUsingComparator:^NSComparisonResult(id obj1, id obj2) {

            //If it's greater, put it above
            if ([obj1 integerValue] > [obj2 integerValue])
                return (NSComparisonResult)NSOrderedAscending;
            //If lower, then below
            if ([obj1 integerValue] < [obj2 integerValue])
                return (NSComparisonResult)NSOrderedDescending;

            return (NSComparisonResult)NSOrderedSame;

        }]];

        NSLog(@"FinishedBlockLog: %@", sortedPubArray);
    }
}];

NSLog(@"FinishedMethodLog: %@", sortedPubArray);
return pubArray;
}

日志:

2013-11-09 16:35:27.722 外部 [5037:70b] FinishedMethodLog: ( )

2013-11-09 16:35:27.723 外部 [5037:70b] 分配给方法返回的变量:( )

2013-11-09 16:35:27.925 外部 [5037:70b] FinishedBlockLog: ( 测试版, “蜡像奥康纳斯”, “方舟”, 《计数楼》, 收音机 )

2013-11-09 16:35:32.590 外部 [5037:70b] 按钮我创建用于注销变量,该变量返回分配给它的方法:( )

所以我们可以看到,当块完成时,我正在注销 sortedPubArray,但它仍然没有反映在块外的 sortedPubArray 中。任何帮助将不胜感激

【问题讨论】:

  • 你必须掌握异步操作的概念:-)
  • 不,我知道它不会立即完成,但它根本不会更新它。不管我等多久
  • PubsForUser的返回值怎么用? - 在任何情况下,您都应该在完成块中更新 UI。
  • 我将使用它从每个酒吧获取数据。但当然,直到它真正完成。所以现在,它没有执行任何代码。每次点击按钮时都会调用最后一个日志,它的输出只是分配给此方法返回值的变量。我认为变量应该在块完成时更新,因为它只是指向数组的指针?感谢您的帮助,马丁。是的,我不更新 UI 的原因是它不在 viewController 中。它只是一个模型类,我的 VC 从中获取信息。

标签: ios objective-c nsmutablearray objective-c-blocks parse-platform


【解决方案1】:

首先,没有理由将__block 用于pubArray。您不会更改块中的任何一个变量(在变量引用的对象上调用方法不会更改变量值)。对于sortedPubArray,没有理由为该变量分配一个空的可变数组,因为无论如何您只是稍后在代码中重新分配给所述变量。

顺便说一句:PubsForUser: 应该是 pubsForUser:。方法总是以小写字母开头。

不过,问题的真正根源在于您的并发模型。您正在后台执行某些操作,但期望结果立即在前台可用。考虑您的日志语句:

2013-11-09 16:35:27.722 Outer[5037:70b] FinishedMethodLog: ( )

2013-11-09 16:35:27.723 Outer[5037:70b] Variable assigned to the return of the method: ( )

2013-11-09 16:35:27.925 Outer[5037:70b] FinishedBlockLog: ( TestPub, "Waxy O'Connors", "The Ark", "The Counting House", Radio )

注意时间戳;你的 pubsForUserMethod: 正在 16:35:27.722 完成,但后台执行直到 16:35:27.925 才完成,大约 200 毫秒后。

您需要同步执行此操作,或者在后台块的末尾放置一个回调,告诉您的主线程东西已经准备好(很可能)。

dispatch_async(dispatch_get_main_queue(), ^{ [myUIThingy youManYourStuffIsReady: sortedPubArray]; });

请注意,简单地将东西扔到后台执行并不是一个很好的并发模型。您需要非常仔细地考虑您的数据、同步点和线程之间的一致性。


现在,如果您真的在使用返回的 pubsArray(这引出了为什么 sortedPubsArray 存在的问题)并且仍然想知道为什么您的 UI 状态没有更新...

...您的 UI 状态不会自行更新。您仍然需要在该后台任务中进行回调,让 UI 知道它应该重新加载显示所述数组内容的表格视图。

并且您需要确保没有任何内容复制pubsArray 并折腾原始值。让pubsForUser: 返回(void) 并有可能将块作为参数,当一切都说完后执行。

【讨论】:

  • 是的,你是对的,我实际上并没有返回 pubArray。那只是测试留下的,当我将它复制+粘贴到stackoverflow时,我一定没有更新它。无论如何,我现在不想更新 UI,我最终会但我不明白为什么,即使在块完成后,数组也不会在它之外更新。所以你可以用我的 FinishedBlockLog 看到,即使在块完成后,下一个日志(5 秒后)打印出分配给我们方法的返回值的变量(即 sortedPubArray,它应该在我的代码中)仍然是空数组。
  • @Gordon 确保您实际上正在查看同一个数组; NSLog(@"Array %p %@", array, array);.
  • 是的,这是我的任务self.pubArray = [PubFinder pubsForUser:[PFUser currentUser]];,这是名为NSLog(@"Button I've created to log out variable which has the return of the method assigned to it: %@", self.pubArray);的日志
  • 好的,所以我设法通过将代码实际移动到我的 VC 中的方法中并在块完成时将 sortedPubArray 直接分配给 self.pubArray 来使其工作。我不明白为什么它以前不起作用,我认为 self.pubArray 只是指向实际数组的指针?也许不是,无论如何谢谢你的时间bbum,非常感谢。
  • @property (strong, nonatomic) NSMutableArray *pubArray;
猜你喜欢
  • 2020-08-25
  • 2021-10-05
  • 1970-01-01
  • 1970-01-01
  • 2020-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-10
相关资源
最近更新 更多