0

I have another very beginner's question related to xCode. I am completely new to iOS development so I appreciate you guys to reply me.

I have written the following class to access the Restful API. The code in the method "makePostRequest" works fine if I write it directly in the calling method. But, I want to make it asynchronous and I don't know exactly how can I make this work asynchronous. Can somebody help me please to write this as asynchronos call?

#import <Foundation/Foundation.h>
#import "ServerRequest.h"
#import "NetworkHelper.h"

@implementation ServerRequest

@synthesize authorizationRequest=_authorizationRequest;
@synthesize responseContent=_responseContent;
@synthesize errorContent=_errorContent;
@synthesize url=_url;
@synthesize urlPart=_urlPart;
@synthesize token=_token;

- (void)makePostRequest : (NSString *) params   {
    NSString *urlString = [NSString stringWithFormat:@"%@%@", [self getUrl], [self getUrlPart]];

    NSURL *url = [NSURL URLWithString:urlString];
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];

    NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:[NSOperationQueue mainQueue]];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];

    if([self isAuthorizationRequest])    {
        [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
        [request setValue:@"Basic" forHTTPHeaderField:@"Authorization"];
    }
    else    {
        NSString *authorizationValue = [NSString stringWithFormat:@"Bearer %@", [self getToken]];
        [request setValue:authorizationValue forHTTPHeaderField:@"Authorization"];
    }

    if(params.length > 0)
        [request setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];

    @try {
        NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                                    completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)  {
                                                        if(error)   {
                                                            NSLog(@"Error: %@", error);
                                                        }
                                                        if([response isKindOfClass:[NSHTTPURLResponse class]])  {
                                                            NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
                                                            if(statusCode == [NetworkHelper HTTP_STATUS_CODE])  {
self.responseContent = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves
error:nil];
                                                            }
                                                            else    {
self.errorContent = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves
error:nil];
                                                            }
                                                        }
                                                    }];
        [dataTask resume];
    }

    @catch (NSException *exception) {
        NSLog(@"Exception while making request: %@", exception);
    } @finally {
        NSLog(@"finally block here");
    }
}

- (void)setAuthorization : (bool)value  {
    self.authorizationRequest = &value;
}

- (bool)isAuthorizationRequest  {
    return self.authorizationRequest;
}

- (NSDictionary *)getResponseContent    {
    return self.responseContent;
}

- (NSDictionary *)getErrorContent   {
    return self.errorContent;
}

- (void)setToken:(NSString *)token  {
    self.token = token;
}

- (NSString *)getToken  {
    return self.token;
}

- (void)setUrl:(NSString *)value  {
    //self.url = value;
    _url = value;
}

- (NSString *)getUrl    {
    return self.url;
}

- (void)setUrlPart:(NSString *)value  {
    self.urlPart = value;
}

- (NSString *)getUrlPart    {
    if(self.urlPart.length == 0)
        return @"";

    return self.urlPart;
}

@end
Abizern
  • 146,289
  • 39
  • 203
  • 257
user2908751
  • 195
  • 1
  • 2
  • 8
  • But the response in completionHandler is already asynchronous. – Retterdesdialogs Aug 11 '17 at 13:25
  • add completion handler to your method. - (void)makePostRequest : (NSString *) params withCompleteBlock:(void (^)(id response, NSInteger responseCode, BOOL isSuccess, NSError *error))complete; then , when you are getting response, return this, hope this will help. – Ratnesh Shukla Aug 11 '17 at 13:29
  • Welcome to stackoverflow and Objective C. Here you need to know before post a question, Check before it's already asked or not. [Check this apple doc](https://developer.apple.com/documentation/foundation/nsurlsession/1407613-datataskwithrequest). [This one of the good webservice](https://github.com/AFNetworking/AFNetworking) – Mathi Arasan Aug 11 '17 at 13:30
  • @Retterdesdialogs Yes, but the problem is that I don't know how should I move this code to the calling method which is also setting parameters for this class. Currently, when I make a call from another class by instantiating the this class and setting its parameters, that call doesn't wait for the result from "completionHandler" and moves on. Resulting me to get nothing as a response. – user2908751 Aug 11 '17 at 13:32
  • @RatneshShukla I already have completion handler in this method. Should I also add completion handler to the calling method? – user2908751 Aug 11 '17 at 13:35
  • Use the delegate pattern for that. You need to implement a protocol in ServerRequest Class. Other classes can then subscribe to that protocol and can implement the methods from that protocol. You need to learn that anyway and you will use it in most of your projects. – Retterdesdialogs Aug 11 '17 at 13:36
  • @Retterdesdialogs Thanks. Can you provide any working example of delegate pattern? – user2908751 Aug 11 '17 at 13:48
  • I coded 6 Years Objective-C but now I am totally out of it. I could provide you an example in Swift if you want or look here https://stackoverflow.com/a/12660523/442121 – Retterdesdialogs Aug 11 '17 at 14:01

1 Answers1

0

I'm giving you an example how you can make your method serve you data when available. It's block based. So you don't have to consider asynchronous task here.

First define your completion block in your ServerRequest.h:

typedef void(^myCompletion)(NSDictionary*, NSError*);

And change your method's signature to this:

- (void) makePostRequest:(NSString *)params completion: (myCompletion)completionBlock;

Now change your method's implementation to something like this (I'm only posting your @try block, so just change your try block. Others remain same)

@try {
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                                completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)  {
                                                    if(error) {
                                                        NSLog(@"Error: %@", error);
                                                        if (completionBlock) {
                                                            completionBlock(nil, error);
                                                        }
                                                    }
                                                    if([response isKindOfClass:[NSHTTPURLResponse class]]) {
                                                        NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
                                                        if(statusCode == [NetworkHelper HTTP_STATUS_CODE]) {
                                                            NSError *error;
                                                            self.responseContent = [NSJSONSerialization JSONObjectWithData:data
                                                                                                                   options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves
                                                                                                                     error:&error];
                                                            if (completionBlock) {
                                                                if (error == nil) {
                                                                    completionBlock(self.responseContent, nil);
                                                                } else {
                                                                    completionBlock(nil, error);
                                                                }
                                                            }
                                                        } else {
                                                            NSError *error;
                                                            self.errorContent = [NSJSONSerialization JSONObjectWithData:data
                                                                                                                options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves
                                                                                                                  error:&error];
                                                            if (completionBlock) {
                                                                if (error == nil) {
                                                                    completionBlock(self.errorContent, nil);
                                                                } else {
                                                                    completionBlock(nil, error);
                                                                }
                                                            }
                                                        }
                                                    }
                                                }];
    [dataTask resume];
}

Finally, when you call this method from somewhere else, use this as:

[serverRequestObject makePostRequest:@"your string" completion:^(NSDictionary *dictionary, NSError *error) {
    // when your data is available after NSURLSessionDataTask's job, you will get your data here
    if (error != nil) {
        // Handle your error
    } else {
        // Use your dictionary here
    }
}];
nayem
  • 7,285
  • 1
  • 33
  • 51