繁体   English   中英

变量不在块外更新

[英]Variable not updating outside of block

所以我的代码在下面。 我正在尝试按分数排序可变数组。 我已经在字典中为每个酒吧的标题分配了分数。 但是,当我调用keyssortedbyvalue时,可以对它们进行很好的排序。 如Logs(下图)所示,但由于某种原因,此更改未反映在块外部的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 :( TestPub,“ Waxy O'Connors”,“ Ark”,“ Counting House”,广播)

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

因此,我们可以看到,当块完成时,并且当发生这种情况时我正在注销sortedPubArray,但仍未反映在块外部的sortedPubArray中。 任何帮助将不胜感激

首先,没有理由对__block使用pubArray 您不会在块中更改任何变量(在变量所引用的对象上调用方法不会更改变量的value )。 对于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 ,但是后台执行直到约200ms之后才完成16:35:27.925

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

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

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


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

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

而且,您需要确保没有任何事情可以复制pubsArraypubsArray原始值。 使pubsForUser:更好pubsForUser: return (void)并潜在地将一个块作为参数,当一切都说完之后就执行。

暂无
暂无

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

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