I am trying to create a NSString function to return a string that has the NSURLSessionDataTask
- (NSString *) retrieveData
{
self.session = [NSURLSession sharedSession];
self.dataTask = [self.session dataTaskWithURL:[NSURL URLWithString:URL] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
if(data)
{
self.json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
NSLog(#"%#", self.json);
for(NSDictionary *stateArray in self.json)
{
NSString *sName = stateArray[#"State"];
if(self.state == sName)
{
NSString *sFlag = stateArray[#"State_Flag_Path"];
return sFlag;
}
}
}
else
{
NSLog(#"Failed to fetch URL: %#", error);
}
}];
[self.dataTask resume];
}
Then, I get an error message for incompatible block pointer types issue.
Can anyone please help?
Thank you in advance.
I found a way...
return the string after
[self.dataTask resume];
Related
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
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
}
}];
I have a singleton class where i have implemented a method to parse json data through URL. The code is as below
-(id)parseJsonDataWIthURL:(NSString *)url :(NSString*)datumm
{
NSMutableDictionary *arrrrr=[[NSMutableDictionary alloc]init];
NSMutableURLRequest *reqqq=[[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:url]];
NSData *dataaa=[datumm dataUsingEncoding:NSUTF8StringEncoding];
[reqqq setHTTPMethod:#"POST"];
[reqqq setHTTPBody:dataaa];
NSURLSessionConfiguration *configg=[NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession*sessionn=[NSURLSession sessionWithConfiguration:configg delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDataTask *taskk=[sessionn dataTaskWithRequest:reqqq completionHandler:^(NSData *data,NSURLResponse *responce,NSError *error){
if(error)
{
NSLog(#"%#", [error localizedDescription]);
}else{
NSMutableDictionary *d = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments|NSJSONReadingMutableContainers error:&error];
NSLog(#"data %#",d);
[arrrrr setDictionary:d];
}
}];
[taskk resume];
return arrrrr;
}
The method returns no values, it is because the blocks takes time to execute within that method returns the result. So is there any way to wait until block completes and return the value.
ragul ml,
Simplest solution I can suggest is to use blocks :)
Here is how you can achieve it :) modify -(id)parseJsonDataWIthURL:(NSString *)url :(NSString*)datumm to,
-(void)parseJsonDataWIthURL:(NSString *)url :(NSString*)datumm withCompletionBlock:(void(^)(NSMutableArray *))completionBlock
{
NSMutableDictionary *arrrrr=[[NSMutableDictionary alloc]init];
NSMutableURLRequest *reqqq=[[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:url]];
NSData *dataaa=[datumm dataUsingEncoding:NSUTF8StringEncoding];
[reqqq setHTTPMethod:#"POST"];
[reqqq setHTTPBody:dataaa];
NSURLSessionConfiguration *configg=[NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession*sessionn=[NSURLSession sessionWithConfiguration:configg delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDataTask *taskk=[sessionn dataTaskWithRequest:reqqq completionHandler:^(NSData *data,NSURLResponse *responce,NSError *error){
if(error)
{
NSLog(#"%#", [error localizedDescription]);
completionBlock(nil)
}else{
NSMutableDictionary *d = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments|NSJSONReadingMutableContainers error:&error];
NSLog(#"data %#",d);
[arrrrr setDictionary:d];
if (completionBlock) {
completionBlock(arrrrr);
}
}
}];
[taskk resume];
}
finally modify your call as,
[[YourSingletonClass sharedInstance] parseJsonDataWIthURL:your_url :datumm withCompletionBlock:^(NSMutableArray *array) {
if (array){
//web service is successful
}
}];
I am creating an app that uses Google Place. Before I used to use Yahoo's api and had to use a url that was responsible for local search that was provided by yahoo. The url was following:
http://local.yahooapis.com/LocalSearchService/V3/localSearch?appid=SF0DVEvV34G4GnXEDU4SXniaDebJ_UvC1G1IuikVz3vpOJrBpyD.VqCJCVJHMh99He3iFz1Rzoqxb0b7Z.0-
Now since yahoo's api is discontinued I have decided to switch over to Google Place. But I cannot find an Url to use. I just dowlod the framework and use the api key. Where can I find such url for Google Place.
Register for the Google Places API by following the linke provided below:
https://code.google.com/apis/console
Refer Code Link for places Auto Search
https://github.com/AdamBCo/ABCGooglePlacesAutocomplete
NSString *const apiKey = #"*****23xAHRvnOf2BVG8o";
NSString * searchWord = #"search some place "
NSString *urlString = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/autocomplete/json?input=%#&types=establishment|geocode&radius=500&language=en&key=%#",searchWord,apiKey];
pragma mark - Network Methods
-(void)retrieveGooglePlaceInformation:(NSString *)searchWord withCompletion:(void (^)(BOOL isSuccess, NSError *error))completion {
if (!searchWord) {
return;
}
searchWord = searchWord.lowercaseString;
self.searchResults = [NSMutableArray array];
if ([self.searchResultsCache objectForKey:searchWord]) {
NSArray * pastResults = [self.searchResultsCache objectForKey:searchWord];
self.searchResults = [NSMutableArray arrayWithArray:pastResults];
completion(YES, nil);
} else {
NSString *urlString = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/autocomplete/json?input=%#&types=establishment|geocode&radius=500&language=en&key=%#",searchWord,apiKey];
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *jSONresult = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
if (error || [jSONresult[#"status"] isEqualToString:#"NOT_FOUND"] || [jSONresult[#"status"] isEqualToString:#"REQUEST_DENIED"]){
if (!error){
NSDictionary *userInfo = #{#"error":jSONresult[#"status"]};
NSError *newError = [NSError errorWithDomain:#"API Error" code:666 userInfo:userInfo];
completion(NO, newError);
return;
}
completion(NO, error);
return;
} else {
NSArray *results = [jSONresult valueForKey:#"predictions"];
for (NSDictionary *jsonDictionary in results) {
}
//[self.searchResultsCache setObject:self.searchResults forKey:searchWord];
completion(YES, nil);
}
}];
[task resume];
}
}
I always used this solution when I needed to parse a feed JSON.
https://stackoverflow.com/a/20077594/2829111
But sendAsynchronousRequest is now deprecated and I'm stuck with this code
__block NSDictionary *json;
[[session dataTaskWithURL:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// handle response
json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"Async JSON: %#", json);
[collectionView reloadData];
}] resume];
And with this the reloadData argument takes a long time to execute. I've alredy tried forcing back to the main queue with:
__block NSDictionary *json;
[[session dataTaskWithURL:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// handle response
json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"Async JSON: %#", json);
dispatch_sync(dispatch_queue_create("com.foo.samplequeue", NULL), ^{[collectionView reloadData});
}] resume];
The problem is that the completion handler does not run on the main queue. But all UI updates must happen on the main queue. So dispatch that to the main queue:
[[session dataTaskWithURL:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// handle response
NSError *parseError;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
// do something with `json`
dispatch_async(dispatch_get_main_queue()), ^{[collectionView reloadData]});
}] resume];
Why don't you try JSONModel library....... it is so simple to use
-(void)getEmployeePerformance:(EmpPerformanceRequest*)request
withSuccesBlock:(succesEmployeePerformanceResponseBlock) successBlock
andFailBlock:(FailResponseBlock) failBlock
{
NSString* weatherUrl = [[ABWebServiceUtil sharedInstance]getEmployeePerformanceURL];
[HTTPClientUtil postDataToWS:weatherUrl parameters:[request toDictionary] WithHeaderDict:nil withBlock:^(AFHTTPRequestOperation *responseObj, NSError *error)
{
if(responseObj.response.statusCode == HTTP_RESPONSE_SUCESS)
{
EmpPerformanceArrayModel *empPerfArrModel;
if(responseObj.responseString)
{
empPerfArrModel = [[EmpPerformanceArrayModel alloc]initWithString:result error:nil];
empPerfArrModel.employeesArray = [empPerformanceModel arrayOfModelsFromDictionaries:empPerfArrModel.employeesArray];
}
if(successBlock)
{
successBlock(responseObj.response.statusCode, empPerfArrModel);
}
}else if (failBlock)
{
failBlock(responseObj.response.statusCode);
}
}];
}
for more detail follow this link...... it will brief you well
https://github.com/icanzilb/JSONModel
Try parsing JSON in connectionDidFinishLoading so you will get response as NSDictionary.
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
Class NSJSONSerializationclass = NSClassFromString(#"NSJSONSerialization");
NSDictionary *result;
NSError *error;
if (NSJSONSerializationclass)
{
result = [NSJSONSerialization JSONObjectWithData: responseData options: NSJSONReadingMutableContainers error: &error];
}
// If the webservice response having values we have to call the completionBlockā¦
if (result)
{
if (self.completionBlock != nil)
{
self.completionBlock(result);
}
}
}
I have an iOS method that is now deprecated --NSURLConnection sendSynchronousRequest. This method worked and was fast.
I must be doing something wrong with the new method, as it is unacceptably slow.
The new method code I'm showing the whole routine is:
- (void)getData {
NSLog(#"%s", __FUNCTION__);
pathString = #"https://api.wm.com/json/jRoutes/.......";
NSURL *url = [NSURL URLWithString:pathString......];
NSURLSessionDataTask *downloadTask = [[NSURLSession sharedSession]
dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if ([response respondsToSelector:#selector(statusCode)]) {
if ([(NSHTTPURLResponse *) response statusCode] == 404) {
dispatch_async(dispatch_get_main_queue(), ^{
// alert
NSLog(#" NO DATA");
return;
});
}
}
// 4: Handle response here
[self processResponseUsingData:data];
}];
[downloadTask resume];
}
- (void)processResponseUsingData:(NSData*)data {
NSLog(#"%s", __FUNCTION__);
NSError *error = nil;
NSMutableDictionary* json = nil;
if(nil != data)
{
json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
}
if (error || !json)
{
NSLog(#"Could not parse loaded json with error:%#", error);
} else {
dispatch_async(dispatch_get_main_queue(), ^{
allRoutesArray = [json valueForKey:#"Routes"];
NSLog(#"allRoutesArray count: %lu", (unsigned long)allRoutesArray.count);
[self.tableView reloadData];
});
}
}