0

I'm using blocks to get header fields from response in one class and I have to get that in another class.

I implemented code like this

In first class:

- (void)viewDidLoad {
    [super viewDidLoad];
    UserAuthentication *auth = [[UserAuthentication alloc]init];
    NSDictionary *dict = [auth getUserConfiguration];
    NSLog(@"%@",dict);
}

In userAuthentication class:

-(NSDictionary *)getUserConfiguration;
{
    __block NSDictionary *resultDictionary;
    NSURLSession *session = [NSURLSession sharedSession];
    [[session dataTaskWithURL:[NSURL URLWithString:@"http://72.52.65.142:8083/auth"]
            completionHandler:^(NSData *data,
                                NSURLResponse *response,
                                NSError *error) {
                NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
                if ([response respondsToSelector:@selector(allHeaderFields)]) {
                     resultDictionary = [httpResponse allHeaderFields];
                    NSLog(@"%@",resultDictionary);
                }
            }] resume];
    NSLog(@"%@",resultDictionary);
    return resultDictionary;
}

Here my problem is in first class I'm getting dict as null.

Even in userAuthentication class also I'm getting null.

But after some time call back method is calling and then I can see the response correctly in completionHandler.

So how I can get response in firstClass?

Ronak Chaniyara
  • 5,335
  • 3
  • 24
  • 51
Himanth
  • 2,381
  • 3
  • 28
  • 41

5 Answers5

2

You are misunderstanding the basic principle of async operation that runs in background thread and when the operation is completed it gives you data in completion block.

To get response in viewDidLoad Method of second class you need to use blocks. like below

-(void)getUserConfigurationOnCompletion:(void (^)(NSDictionary *))completion
{
    __block NSDictionary *resultDictionary;
    NSURLSession *session = [NSURLSession sharedSession];
    [[session dataTaskWithURL:[NSURL URLWithString:@"http://72.52.65.142:8083/auth"]
            completionHandler:^(NSData *data,
                                NSURLResponse *response,
                                NSError *error) {
                NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
                if ([response respondsToSelector:@selector(allHeaderFields)]) {
                     resultDictionary = [httpResponse allHeaderFields];
                   // Call completion with parameter
                    completion(resultDictionary);
                }
            }] resume];
}

and use it like this in viewDidLoad

- (void)viewDidLoad {
    [super viewDidLoad];
    UserAuthentication *auth = [[UserAuthentication alloc]init];
    [auth getUserConfigurationOnCompletion:^(NSDictionary *dict){
    // do necessary work with response dictionary here
    NSLog(@"%@",dict);

   }];
}
Irfan Gul
  • 1,579
  • 13
  • 23
2

That's something you'll have to get used to: Anything that is related to internet access (and some things not related to it) cannot be returned immediately - unless you are willing to wait for it, block your user interface, and make your users very, very unhappy.

You have to write your application in such a way that it can be in four states: Never asked for the user configuration, asking for the user configuration, having asked for and received the user configuration, or having asked for the user configuration and failed. In this case your view must handle all four possibilities and must handle when the situation changes.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
1

You are using NSURLSession! It performs tasks on a background thread! Completion block is called only when you get the response from the server. Naturally it will take time to complete the request. You should use blocks to complete the request and return the result on completion.

-(void)getUserConfigurationAndOnCompletion:(void(ˆ)(NSDictionary *dict, NSError *error))completion;
{
    __block NSDictionary *resultDictionary;
    NSURLSession *session = [NSURLSession sharedSession];
    [[session dataTaskWithURL:[NSURL URLWithString:@"http://72.52.65.142:8083/auth"]
            completionHandler:^(NSData *data,
                                NSURLResponse *response,
                                NSError *error) {
                NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
                if ([response respondsToSelector:@selector(allHeaderFields)]) {
                     resultDictionary = [httpResponse allHeaderFields];
                    NSLog(@"%@",resultDictionary);

                 //This will call the block in the first class with the result dictionary

              dispatch_async(dispatch_get_main_queue(), ^{
                   if(!error){
                       completion(resultDictionary,nil);
                   }else{
                       completion(nil,error);
                   }
              });

        }] resume];
}

When you call the above code from your first class, it will create a block there and you will get the required dictionary over there in the block parameter!

Rikh
  • 4,078
  • 3
  • 15
  • 35
  • How to call this method in first class – Himanth Oct 18 '16 at 09:52
  • When you try to call the function, autofill show the function name and then autoComplete will write the whole function. But you should have a look at Lion's answer to get an idea about it. – Rikh Oct 18 '16 at 10:11
1

Your method should be like,

  -(void)getUserConfigurationwithCompletionHandler : (void (^)(NSDictionary* resultDictionary))completionHandler
{
__block NSDictionary *resultDictionary;
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:@"http://72.52.65.142:8083/auth"]
        completionHandler:^(NSData *data,
                            NSURLResponse *response,
                            NSError *error) {
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
            if ([response respondsToSelector:@selector(allHeaderFields)]) {
                resultDictionary = [httpResponse allHeaderFields];
                NSLog(@"%@",resultDictionary);

                completionHandler(resultDictionary);

            }
        }] resume];
  NSLog(@"%@",resultDictionary);

}

and you can access it like,

  - (void)viewDidLoad {
       [super viewDidLoad];

       [self getUserConfigurationwithCompletionHandler:^(NSDictionary *resultDictionary) {

    // you can acess result dictionary here

    NSLog(@"%@",resultDictionary);

    }];

 }

because you will getting data in response of webservice(from server) so it takes some time to complete so you have to return data from completion handler of webservice call and you can't return data from completion handler so you have to create own completion handler and call as i have mentioned above. you can access resultDictionary in completionHandler and you can show new VC from this completionHandler.

Ketan Parmar
  • 27,092
  • 9
  • 50
  • 75
0

You have to call a method in your first class in your completionHandler.

  1. Create a property of type YOURFIRSTCLASS *myfirstclass in your UserAuthentication Class.

  2. Pass your firstclass with "self" to the UserAuthentication object.

  3. create visible method in your firstclass "-(void)responseCaller:(NSDictionary)dict"

  4. call the method in your response method

YOURFIRSTCLASS .h:

-(void)responseCaller:(NSDictionary)dict;

YOURFIRSTCLASS .m

-(void)responseCaller:(NSDictionary)dict
{NSLog(@"%@",dict);}

- (void)viewDidLoad {
    [super viewDidLoad];
    UserAuthentication *auth = [[UserAuthentication alloc]init];
    auth.myfirstclass = self;
    NSDictionary *dict = [auth getUserConfiguration];
    NSLog(@"%@",dict);
}

UserAuthentication .h

#import "YOURFIRSTCLASS.h"
@property (nonatomic) *myfirstclass;

UserAuthentication .m

-(NSDictionary *)getUserConfiguration;
{
    __block NSDictionary *resultDictionary;
    NSURLSession *session = [NSURLSession sharedSession];
    __weak myfirstclassSave = myfirstclass;
    [[session dataTaskWithURL:[NSURL URLWithString:@"http://72.52.65.142:8083/auth"]
            completionHandler:^(NSData *data,
                                NSURLResponse *response,
                                NSError *error) {
                NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
                if ([response respondsToSelector:@selector(allHeaderFields)]) {
                     resultDictionary = [httpResponse allHeaderFields];
                     [myfirstclassSave responseCaller:resultDictionary ];

                }
            }] resume];

    return resultDictionary;
}

Something like that

Maurice Raguse
  • 4,437
  • 2
  • 29
  • 46