Waiting or not exiting the code block in getting json - objective-c

I am using GET method on Json. The GET method is inside a for loop, and the issue is it is not finishing the task or not getting the result. Instead the loop increments. I've placed a breakpoint inside the block where I am setting the result data to a NSDictionary but it never goes there.
Is it possible for the GET method to be directly called. I mean the code will be read line by line. And it will not skip or wait for the json to finish processing?
Here's what I've done:
- (void)downloadJsonFeed
{
for(int i = 1;i < self.numberOfEpisodes;i++)
{
NSString *endPoint = [[[[baseJsonUrl stringByAppendingString:getEpisodes]stringByAppendingString:self.title]stringByAppendingString:#"&episodeNumber="]stringByAppendingString:[NSString stringWithFormat:#"%i",i]];
NSLog(#"End point %#",endPoint);
[JsonDownload getJson:token andEndpointString:endPoint WithHandler:^(__weak id result)
{
NSArray *episodeArray =result;
//will do some task here
}];
}
}
- (void)getJson:(NSString *)authData andEndpointString:(NSString *)urlString WithHandler:(void(^)(__weak id result))handler
{
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
NSURL * url = [NSURL URLWithString:urlString];
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
//NSString *auth = [NSString stringWithFormat:#"Bearer {%#}", authData];
[urlRequest setValue:#"application/json" forHTTPHeaderField:#"Content-type"];
[urlRequest setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[urlRequest setValue:authData forHTTPHeaderField:#"Cookie"];
[urlRequest setHTTPMethod:#"GET"];
NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(error == nil)
{
id returnedObject = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableLeaves error:nil];
handler(returnedObject);
}
else{
NSLog(#"error %#",error);
}
}];
[dataTask resume];
}
I've placed a break point in this line NSArray *episodeArray =result; and it never goes there. But when I put the break point on [JsonDownload getJson:token andEndpointString:endPoint WithHandler:^(__weak id result) line it is responding
And on the commented line //will do some task here I need to a task there before getting another json again. But I can't cause it never go inside the code block

Fixed the issue by replacing white space characters in my endPoint by %20

Related

NSURLSessionConfiguration and NSData always returning nil

I am new to Mac application development and i am working on fixing the deprecation issues present in the application. I am using XCode 11.3 in Mojave MacOS 10.14 and Our application contains the following line of code
[NSURLConnection sendSynchronousRequest:request returningResonse:response error:Error]
A warning message getting displayed as sendSynchronousRequest is deprecated and it is suggesting to use [NSURLSession dataTaskWithRequest:completionHandler:] .
so i have implemented the following code
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
NSURL * url = [NSURL URLWithString:#"MyURLHere"];
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"Response:%# %#\n", response, error);
if(error == nil)
{
NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
}
}];
[dataTask resume];
i found that data is being returned as nil always. When i debugged the code, i found that even [NSURLSessionConfiguration defaultSessionConfiguration] is being returned as nil. Can you please suggest what needs to be done in order to fix these issues?

I am trying to sent a record to my web server but the web server never gets hit

I have this little project
I have some recipes that I want to share with my iPhone.
the database has this fields
string id
string name
string recipe_text
byte[] image
so when I change it on the iPhone I call this function
+(void) sendRecipe:(BFRecipe *) recipe
{
NSString * imageStringData = #"";
if(recipe.recipeImage != nil)
imageStringData = [UIImagePNGRepresentation(recipe.recipeImage) base64Encoding];
NSDictionary * jsonRecord = [NSDictionary dictionaryWithObjectsAndKeys:recipe.recipeId,#"RecipeId",recipe.name,#"Name" ,recipe.recipeText,#"RecipeText",imageStringData,#"Item" , nil];
NSString *urlString = [NSString stringWithFormat:#"%#/%#",[[NSUserDefaults standardUserDefaults ] objectForKey:#"Host"],#"UpdateRecipeItem"];
NSMutableURLRequest *request = [NSMutableURLRequest new];
request.HTTPMethod = #"POST";
NSData *jsonBodyData = [NSJSONSerialization dataWithJSONObject:jsonRecord options:kNilOptions error:nil];
[request setURL:[NSURL URLWithString:urlString]];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setHTTPBody:jsonBodyData];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config
delegate:nil
delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:^(NSData * _Nullable data,
NSURLResponse * _Nullable response,
NSError * _Nullable error) {
NSHTTPURLResponse *asHTTPResponse = (NSHTTPURLResponse *) response;
// set a breakpoint on the last NSLog and investigate the response in the debugger
// if you get data, you can inspect that, too. If it's JSON, do one of these:
}];
[task resume];
}
My MVC server has a function like this but it never gets called Why ?
public void UpdateRecipeImage(string id)
{
recipe_item item = Model.recipe_item.FirstOrDefault(ri => ri.recipe_id == new Guid(id));
....
.....
....
}
I see problem with your calling part in objective-c code
NSString *urlString = [NSString stringWithFormat:#"%#/%#",[[NSUserDefaults standardUserDefaults ] objectForKey:#"Host"],#"UpdateRecipeItem"];
Here you calling #"UpdateRecipeItem" but on mvc api you have UpdateRecipeImage(string id)
so problem is with your naming. Try to call proper api name that is UpdateRecipeImage(string id)
-OR-
If calling #"UpdateRecipeItem" is your attention, then post your mvc api code here with parameters. I am sure you're missing something for you api endpoint.
UPDATE: Based on your code shared in comment, try adding [FromBody] in you api method. Look at code below:
[HttpPost]
public void UpdateRecipeItem([FromBody] UpdateRecipeItem recipeItem)
{
try
{
recipe_item item = Model.recipe_item.FirstOrDefault(ri => ri.recipe_id == new Guid(recipeItem.RecipeId));
Hope you understand. Happy Coding!

Soundcloud OAuth request returns always invalid client

Here is my objective-c code to obtain access token from SoundCloud:
- (void) authoriseSoundcloud {
NSString *apiUrl = #"https://api.soundcloud.com/oauth2/token";
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:[ NSURL URLWithString:apiUrl]];
NSString * params = [NSString stringWithFormat:#"client_id=%#&client_secret=%#grant_type=password&username=%#&password=%#",client,secretKey,fldUsername.text,fldPassword.text ];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
NSURLSession *defaultSession = [NSURLSession sharedSession];
NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"Response:%# %#\n", response, error);
if(error == nil)
{
NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(#"Data = %#",text);
}
}];
[dataTask resume];
}
However, I always get the result 401- {"error":"invalid_client"}.
However, that client ID works perfectly with those requests, that does not need authorization and I have checked multiple times, that my client ID and secret are correct.
As there is not much samples for iOS to use those parameters in HTTP post body, I assume that maybe my parameters list is incorrect. Any ideas from Soundcloud engineers?
Just a typo mistake, simply add "&" between "client_secret=%#" and "grant_type", like this :
NSString * params = [NSString stringWithFormat:#"client_id=%#&client_secret=%#&grant_type=password&username=%#&password=%#",client,secretKey,fldUsername.text,fldPassword.text ];
Work like a charm :)

Objective C Block within Block generates Leak. How can I solve it?

Why does this code generates a leak? How could it be solved?
This is the original call:
NSString * url = #"https://theserverurl/user/login" ;
NSDictionary *parameters = #{#"login":#"the-email#mail.com", #"password":#"encrypted-password"} ;
[[BackEndAPI sharedManager] NSURLSessionOperation: #"POST" url: url parameters: parameters success:^(NSURLRequest *request, NSHTTPURLResponse * response, id responseObject) {
// Success
} failure:^(IDLEngineError *engineError) {
// Failure
}] ;
This is the singleton which handles the NSURL request:
- (NSMutableURLRequest *) NSURLSessionOperation:(NSString *) restOperation
url:(NSString *)url
parameters:(id)parameters
success:(void (^)(NSMutableURLRequest *request, NSHTTPURLResponse * response, id responseObject))success
failure:(void (^)(IDLEngineError *))failure {
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
__weak id weakSelf = self ;
// POST
if ([restOperation isEqualToString:#"POST"]) {
NSError *error;
NSURLSession *session = [NSURLSession sessionWithConfiguration: sessionConfig ];
// Create the request
__block NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: url ] ];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"] ;
request.HTTPMethod = #"POST";
NSData *postData = [NSJSONSerialization dataWithJSONObject: parameters options: 0 error:&error];
[request setHTTPBody:postData];
// Perform operation
NSURLSessionDataTask * task = [session dataTaskWithRequest: request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// This generates a leak!!!!
success(request, nil, nil) ;
}] ;
[task resume] ;
}
return nil ;
}
Please take a look to the leaked app on GitHub:
https://github.com/arkyxperience/myleakedapp
Find also here the report (screenshot) coming from Instruments:
It turns out the leak is with NSURLSessionDataTask. If you isolate the following piece of code, the leak will remain:
NSString * url = #"https://theserverurl/user/login" ;
NSDictionary *parameters = #{#"login":#"the-email#mail.com", #"password":#"encrypted-password"} ;
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
NSError *error;
NSURLSession *session = [NSURLSession sessionWithConfiguration: sessionConfig ];
// Create the request
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: url ] ];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"] ;
request.HTTPMethod = #"POST";
NSData *postData = [NSJSONSerialization dataWithJSONObject: parameters options: 0 error:&error];
[request setHTTPBody:postData];
// Perform operation
NSURLSessionDataTask * task = [session dataTaskWithRequest: request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
}] ;
[task resume] ;
Am I doing anything wrong?
OK, i tried your github code, looks like there is no leak. What object is leaking after all? To test this code please add restoration id to your controller. In this code dealloc is being triggered even tho i don't use weak to call controller. So controller is not leaking, complete block does not have a retain loop. Don't see anything that can leak in NSURLSessionOperation:. So what exactly is leaking?
- (void)viewDidLoad {
[super viewDidLoad];
NSString * url = #"https://google.com" ;
NSDictionary *parameters = #{#"login":#"the-email#mail.com", #"password":#"encrypted-password"} ;
[[BackEndAPI sharedManager] NSURLSessionOperation: #"POST" url: url parameters: parameters success:^(NSURLRequest *request, NSHTTPURLResponse * response, id responseObject) {
NSLog(#"finish");
dispatch_async(dispatch_get_main_queue(), ^{
self.view.window.rootViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
});
} failure:^(NSError * error) {
NSLog(#"fail");
}];
}
- (void)dealloc {
NSLog(#"Did dealloc");
}

Simple objective-c GET request

Most of the information here refers to the abandoned ASIHTTPREQUEST project so forgive me for asking again.
Effectively, I need to swipe a magnetic strip and send the track 2 data to a webservice that returns "enrolled" or "notenrolled" (depending on the status of the card...)
So my data comes in simply as
NSData *data = [notification object];
And then I need to pass this to a url to the order of
http://example.com/CardSwipe.cfc?method=isenrolled&track2=data
And then just receive a response string...
I've searched a ton and there seems to be some conflicting answers as to whether this should be accomplished simply with AFNetworking, RESTkit, or with the native NSURL/NSMutableURLRequest protocols.
The options for performing HTTP requests in Objective-C can be a little intimidating. One solution that has worked well for me is to use NSMutableURLRequest. An example (using ARC, so YMMV) is:
- (NSString *) getDataFrom:(NSString *)url{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:#"GET"];
[request setURL:[NSURL URLWithString:url]];
NSError *error = nil;
NSHTTPURLResponse *responseCode = nil;
NSData *oResponseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&responseCode error:&error];
if([responseCode statusCode] != 200){
NSLog(#"Error getting %#, HTTP status code %i", url, [responseCode statusCode]);
return nil;
}
return [[NSString alloc] initWithData:oResponseData encoding:NSUTF8StringEncoding];
}
Update:
Your question's title, and tagging say POST, but your example URL would indicate a GET request. In the case of a GET request, the above example is sufficient. For a POST, you'd change it up as follows:
- (NSString *) getDataFrom:(NSString *)url withBody:(NSData *)body{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:body];
[request setValue:[NSString stringWithFormat:#"%d", [body length]] forHTTPHeaderField:#"Content-Length"];
[request setURL:[NSURL URLWithString:url]];
/* the same as above from here out */
}
Update for iOS 9:
So, [NSURLConnection sendSynchronousRequest] is deprecated starting from iOS 9. Here's how to do a GET request using NSURLSession starting from iOS 9
GET Request
// making a GET request to /init
NSString *targetUrl = [NSString stringWithFormat:#"%#/init", baseUrl];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:#"GET"];
[request setURL:[NSURL URLWithString:targetUrl]];
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:
^(NSData * _Nullable data,
NSURLResponse * _Nullable response,
NSError * _Nullable error) {
NSString *myString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Data received: %#", myString);
}] resume];
POST Request
// making a POST request to /init
NSString *targetUrl = [NSString stringWithFormat:#"%#/init", baseUrl];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
//Make an NSDictionary that would be converted to an NSData object sent over as JSON with the request body
NSDictionary *tmp = [[NSDictionary alloc] initWithObjectsAndKeys:
#"basic_attribution", #"scenario_type",
nil];
NSError *error;
NSData *postData = [NSJSONSerialization dataWithJSONObject:tmp options:0 error:&error];
[request setHTTPBody:postData];
[request setHTTPMethod:#"POST"];
[request setURL:[NSURL URLWithString:targetUrl]];
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:
^(NSData * _Nullable data,
NSURLResponse * _Nullable response,
NSError * _Nullable error) {
NSString *responseStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Data received: %#", responseStr);
}] resume];
Tested 100% working
Only for Objective C
-(void)fetchData
{
NSURLSessionConfiguration *defaultSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultSessionConfiguration];
// Setup the request with URL
NSURL *url = [NSURL URLWithString:#"https://test.orgorg.net/ios/getStory.php?"];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
// Convert POST string parameters to data using UTF8 Encoding
NSString *postParams = #"";
NSData *postData = [postParams dataUsingEncoding:NSUTF8StringEncoding];
// Convert POST string parameters to data using UTF8 Encoding
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:postData];
// Create dataTask
NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *results = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
//JSON Parsing....
NSString *message = results[#"Message"];
BOOL status = results[#"Status"];
if (status){
// Here you go for data....
}else{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"App"
message:message
preferredStyle:UIAlertControllerStyleAlert]; // 1
UIAlertAction *firstAction = [UIAlertAction actionWithTitle:#"Ok"
style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
NSLog(#"You pressed button one");
}]; // 2
[alert addAction:firstAction]; // 4
[self presentViewController:alert animated:YES completion:nil];
}
}];
// Fire the request
[dataTask resume];
}
For Objective c :
-(void)loadData:(NSString*)url{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"https://jsonplaceholder.typicode.com/posts"]];
[request setHTTPMethod:#"GET"];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSMutableArray *jsonArray = (NSMutableArray *)[NSJSONSerialization JSONObjectWithData:data options:NSASCIIStringEncoding error:&error];
if([self.delegate respondsToSelector:#selector(loadingData:)]){
[self.delegate loadingData:jsonArray];
}
}] resume];
}
Swift 5.5:
// MARK: - Posts
func getPosts(endPath : String, completion: #escaping ([Post]) -> ()) {
let urlPath = Constants.Network.BASE_URL + endPath
guard let url = URL(string: urlPath) else {
print("Invalid URL")
return
}
var request = URLRequest(url: url)
request.httpMethod = Constants.Network.HTTPS_METHOD
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
if let decodedResponse = try? JSONDecoder().decode([Post].self, from: data) {
DispatchQueue.main.async {
completion(decodedResponse)
}
return
}
}
print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
}.resume()
}
**Simply Call and get your JSON Data.**
-(void)getJSONData
{
NSURL *url = [NSURL URLWithString:#"http://itunes.apple.com/us/rss/topaudiobooks/limit=10/json"];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *data = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSError *erro = nil;
if (data!=nil) {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&erro ];
if (json.count > 0) {
for(int i = 0; i<10 ; i++){
[arr addObject:[[[json[#"feed"][#"entry"] objectAtIndex:i]valueForKeyPath:#"im:image"] objectAtIndex:0][#"label"]];
}
}
}
dispatch_sync(dispatch_get_main_queue(),^{
[table reloadData];
});
}];
[data resume];
}