findObjectsInBackgroundWithBlock: gets data from Parse, but data only exists inside the block
The last NSLog(@"The dictionary is %@", self.scoreDictionary)
statement does not actually execute after the block completes. It executes after the findObjectsInBackgroundWithBlock
method returns. findObjectsInBackgroundWithBlock
presumably runs something in a separate thread, and your block may not actually execute at all until some length of time after that last NSLog statement. Graphically, something like this is probably happening:
Thread 1
--------
retriveDataFromParse called
invoke findObjectsInBackgroundWithBlock
findObjectsInBackgroundWithBlock queues up work on another thread
findObjectsInBackgroundWithBlock returns immediately |
NSLog statement - self.scoreDictionary not yet updated |
retriveDataFromParse returns |
. V
. Thread 2, starting X milliseconds later
. --------
. findObjectsInBackgroundWithBlock does some work
. your block is called
. for-loop in your block
. Now self.scoreDictionary has some data
. NSLog statement inside your block
You probably want to think about, what do you want to do with your scoreDictionary data after you have retrieved it? For example, do you want to update the UI, call some other method, etc.? You will want to do this inside your block, at which point you know the data has been successfully retrieved. For example, if you had a table view you wanted to reload, you could do this:
for (PFObject *object in objects){
....
}
dispatch_async(dispatch_get_main_queue(), ^{
[self updateMyUserInterfaceOrSomething];
});
Note the dispatch_async
- if the work you need to do after updating your data involves changing the UI, you'll want that to run on the main thread.
How can I access a __block variable, after the block has completed?
You can use them outside block just like any other variable.
In your current code this log will print nil, because code inside the block gets executed asynchronously, in this case - when the search results return.
If you want meaningful value from myObject
, you should really put your log inside the block, after myObject
assignment.
See the order of execution in comments:
__block PFObject *myObject = nil; //1
PFQuery *query = [PFQuery queryWithClassName:@"ClassName"]; //2
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) { //3
if (objects.count) //5
myObject = [objects lastObject]; //6
}]; //7
NSLog(@"%@",myObject); //4
Return a value within findObjectsInBackgroundWithBlock
It seems you want a list of User
objects that the current user is following. You already have that after your first query, since you used includeKey
on toUser
.
- (PFQuery *)queryForTable {
PFQuery *isFollowingQuery = [PFQuery queryWithClassName:kPAPActivityClassKey];
[isFollowingQuery whereKey:@"fromUser" equalTo:self.User];
[isFollowingQuery whereKey:@"activity" equalTo:@"follow"];
[isFollowingQuery includeKey:@"toUser"]; //toUser is a user pointer
return isFollowingQuery;
}
Now, this is the correct query to return from queryForTable.
Then, in the cellForRowAtIndexPath
method, you get the User object you want to display:
PFUser *user = [object objectForKey:@"toUser"];
Remember that in the special cellForRowAtIndexPath
in the PFQueryTableViewController
you also get the object for the current row.
Then you can get the value(s) you want from the user object. All inn cellForRowAtIndexPath
Setting block value in Objective-C using Parse
Your block is working in the background, thus, your method is returning the value NO before your block completes the work.
Use property outside block: findObjectsInBackgroundWithBlock:
Doing exerciciosArray = objects;
doesn't do what you think. You're assigning to a copy of exercisiosArray, not the original variable or property. That copy only exists inside the. You can use __block
in the ivar declaration. That will tell the runtime to use the original variable in the block, and not create a copy.
[EDIT] The above paragraph is incorrect. Ivars that are used inside the block are never copied, instead they're implicitly referenced through self
, which is retained in the block. Adding the __block
modifier to an ivar doesn't make any difference. Assigning to an ivar inside a block is OK. This is a somewhat subtle point of Objective-C that is not well documented.
So you have two options:
Add
__block
to the declaration (ifexerciciosArray
is an iVar). [EDIT] This is unnecessary. See the edit above.If
exerciciosArray
is a property, makeexerciciosArray
anNSMutableArray
. Then, you can elements to it by doing[exerciciosArray addObjectsFromArray:objects];
Don't forget to do [[exerciciosArray alloc] init]
where appropriate.
Getting data out of a closure in swift
Declare otherUsersCoord
as a var outside the closure expression, rather than inside it. When it is assigned to within the closure, that change will be reflected in the variable outside the closure. This is known as “capturing” otherUsersCoord
. Capturing external context is what makes closures more than just functions.
Beware though, you still need to wait for the closure to actually run before the variable will have the value you decide. It won’t be instantly synchronously available. Also, capturing external variables keeps them alive and can occasionally result in cyclic references and similar problems (this is why sometimes when you refer to a member variable or function you get a warning about “capturing self”).
Read multiple data in block method IOS
You could use the bolts library for this, which parse already includes. Would make the code a lot simpler, the example below could be easily extended for more than 2 images or other files.
// do your query
PFObject *object = [objects firstObject];
PFFile *file1 = object[@"image1"];
PFFile *file2 = object[@"image2"];
BFTask* task1 = [file1 getDataInBackground];
BFTask* task2 = [file2 getDataInBackground];
[BFTask taskForCompletionOfAllTasks:@[task1, task2]] continueWithBlock:^id(BFTask *task) {
if(!task.error){
UIImage* image1 = [UIImage imageWithData:task1.result];
UIImage* image2 = [UIImage imageWithData:task2.result];
// do your thing with the images
}
return nil;
}];
Related Topics
An App Id with Identifier '' Is Not Available. Please Enter a Different String
Xcode 6 iPhone Simulator Application Support Location
Uilabel with Text of Two Different Colors
Get Device Token for Push Notification
How to Create IPA in Xcode 6 Without Apple Developer Account
How to Edit Empty Spaces of Left, Right Uibarbuttonitem in Uinavigationbar [iOS 7]
Facebook Sdk 3.1 - Error Validating Access Token
Why Do We Use Use_Frameworks! in Cocoapods
Drop-Down List in Uitableview in iOS
Sorting Nsarray of Dictionaries by Value of a Key in the Dictionaries
Uploading Image with Afnetworking 2.0
iPhone Upload Multipart File Using Afnetworking
Ios: Keep an App Running Like a Service
Framework Not Found Googletoolboxformac
Swift 3.0 Error: Escaping Closures Can Only Capture Inout Parameters Explicitly by Value