0

After searching for this type of error:

Variable is not assignable (missing __block type specifier)

I found the following solution Assign a variable inside a Block to a variable outside a Block and after I read about the __block I could not benefit from the accepted answer and my code is different scenario.

Here is the code that I am using:

NSDictionary *strongUser = [[NSDictionary alloc]init];
__block  NSDictionary *user = strongUser;

NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
[parameters setValue:@"id, name, email" forKey:@"fields"]; 
[[[FBSDKGraphRequest alloc] initWithGraphPath:@"me" parameters:parameters]
    startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
        user = result;
}];

NSLog(@"%@",user);

NSLog print nothing

What I want is to given the result value to extern variable outside the block.

enter image description here

Community
  • 1
  • 1
Zakaria Darwish
  • 358
  • 5
  • 22

4 Answers4

0

I would suggest using __block NSDictionary *strongUser. I'm concerned that the pointer user still exists inside the block, but the underlying variable to which it is pointing may no longer be accessible. For example:

__block NSDictionary *strongUser = [[NSDictionary alloc]init];

NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
[parameters setValue:@"id, name, email" forKey:@"fields"]; 
[[[FBSDKGraphRequest alloc] initWithGraphPath:@"me" parameters:parameters]
 startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error)
 {
     strongUser = result;
 }];
user212514
  • 3,110
  • 1
  • 15
  • 11
0

Add the following inside your block:

NSLog(@"Doing assignment inside the block");

Then run your code.

The answer to your question will be obvious.

HTH

CRD
  • 52,522
  • 5
  • 70
  • 86
  • i could not understand what you are trying to say – Zakaria Darwish Apr 24 '16 at 20:14
  • In what order do the two log statements print when you run your code? – CRD Apr 24 '16 at 20:16
  • the log outside the block run before the inside the block i know that but i want a solution – Zakaria Darwish Apr 24 '16 at 20:17
  • Solution - use property, not local variable. Or wait async block to be finished. – Evgeny Karkan Apr 24 '16 at 20:18
  • That is the nature of asynchronous programming. There are various ways to handle the issue. You can call a completion/continuation block from within you block, passing on the result; you can use semaphores to wait for completion; etc., etc. You need to read up on asynchronous design and pick a solution which suits your scenario. HTH – CRD Apr 24 '16 at 20:20
  • @EvgenyKarkan - a property won't directly help with the problem, which is trying to access the result before it is assigned. – CRD Apr 24 '16 at 20:22
  • @CRD - yep, good point, but at least 'strongUser' data will be visible from the class scope. Maybe it will be enouth for topic starter. – Evgeny Karkan Apr 24 '16 at 20:26
0

You run your code async, and your log evaluates before completion handler.
Add your log directly inside completion handler's scope.

NSDictionary *strongUser = [[NSDictionary alloc]init];
__block  NSDictionary *user = strongUser;

NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
[parameters setValue:@"id, name, email" forKey:@"fields"]; 
[[[FBSDKGraphRequest alloc] initWithGraphPath:@"me" parameters:parameters]
 startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error)
 {
     user = result;

     NSLog(@"%@",user);
 }];
Evgeny Karkan
  • 8,782
  • 2
  • 32
  • 38
  • yes already read about this on https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW6 but how i can solve my problem – Zakaria Darwish Apr 24 '16 at 20:01
  • See my updated code snippet. – Evgeny Karkan Apr 24 '16 at 20:02
  • the log inside the block give me the result but what i want to access those value outside the block – Zakaria Darwish Apr 24 '16 at 20:11
  • You can access to it only after completion handler did finished, because 'startWithCompletionHandler' runs asynchronously. Try to create 'strongUser' not as local variable but as property - so it will be visible in your class scope. – Evgeny Karkan Apr 24 '16 at 20:16
0

You have a local variable strongUser, it means that when this scope(function) will be finished, your local variable strongUser will be deallocated - so when your block works __block variavle user is alive but it points to unexist object.

The easy wasy to implement it right is to create a property with lazy setter:

@property (nonatomic, strong) NSDictionary *strongUser;

- (NSDictionary *)strongUser {
    if (!_strongUser) {
        _strongUser = [[NSDictionary alloc] init];
    }
    return _strongUser;
}

And call it with selfinside block:

    NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
    [parameters setValue:@"id, name, email" forKey:@"fields"];

    [[[FBSDKGraphRequest alloc] initWithGraphPath:@"me"parameters:parameters]
 startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
     self.strongUser = result;  
     NSLog(@"%@",self.strongUser);  
     }];

Hope it helps!

Alex Kosyakov
  • 2,095
  • 1
  • 17
  • 25