Hi I am using NSURLSession to fetch data from a server and I am using the following code for that purpose.
[[[NSURLSession sharedSession] dataTaskWithURL:urlForDiseaseTypes completionHandler:^(NSData *data, NSURLResponse *response,NSError *error)
{
if(!error)
{
NSHTTPURLResponse *httpRespc = (NSHTTPURLResponse *)response;
if(httpRespc.statusCode == 200)
{
NSArray *result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
diseaseArray = [result valueForKeyPath:#"Value"];
diseaseIDarray = [result valueForKeyPath:#"ID"];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableViewMain reloadData];
});
}
}
}]resume];
And I am getting value inside both arrays(diseaseArray,diseaseIDarray). diseaseArray values are supposed to get displayed on table view. But when tableview opens no values are getting visible. When checked inside in Table View methods the array count is zero. How can I load my tableview with the values I get from NSURLSession block.
Currently I am calling this function in viewDidLoad.
Related
I am trying to submit user input to a webpage and then retrieve returned data. This webpage takes a person's name and returns his/her information from a database. I tried to make a POST request when user clicks a button then send user's input to that webpage. But when I print out returned data, it's just the html source code of that webpage, only without javaScript. How can I change/add the below function to get the person's information page? I've spent lots of time but still can't figure it out. Please help me! Thank you!
-(void) sendHTTPPost{
NSString* input = nameTextField.text;
//1
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://find.pitt.edu"]];
[req setHTTPMethod:#"POST"];
//2
NSData* postData = [input dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
//3
NSString *postLength = [NSString stringWithFormat:#"%lu",(unsigned long)[postData length]];
[req setValue:postLength forHTTPHeaderField:#"Content-Length"];
[req setValue:#"text/html" forHTTPHeaderField:#"Content-type"];
[req setHTTPBody:postData];
//4
NSURLSession *session = [NSURLSession sharedSession];
//5
NSURLSessionDataTask *task = [session dataTaskWithRequest:req
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// Do something with response data here - convert to JSON, check if error exists, etc....
if(error != nil){
NSLog(#"error: %#", error);
}
else{
NSString* str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#", str);
NSLog(#"response = %#", response);
}
}];
[task resume];
}
It is unlikely that the POST body is supposed to contain only the value. Chances are, it should contain
key=value&key2=value2&key3=value3...
where key is the name of the input, and value is the value of that input, in a URL-encoded format. (See "Encoding URL Data" in URL Session Programming Guide for details on how to URL-encode the values.)
json is:
{
"Title":"Kick", "Year":"2009", "Rated":"N/A", "Released":"08 May 2009",
"Runtime":"N/A", "Genre":"Comedy, Romance, Thriller", "Director":"Reddy Surender",
"Writer":"Abburi Ravi (dialogue), Reddy Surender (screenplay), Vakkantham Vamsi (story)",
"Actors":"Ravi Teja, Ileana, Shaam, Ali",
"Plot":"A guy with an abnormal lifestyle tries to find thrill and pleasure in every work he does and finally becomes a thief.",
"Language":"Telugu", "Country":"India", "Awards":"1 nomination.",
"Poster":"N/A","Metascore":"N/A",
"imdbRating":"7.6",
"imdbVotes":"736",
"imdvid":"tt1579592",
"Type":"movie",
"Response":"True"
}
The Code is:
-(void)parseData:(NSData *)data
{
NSString *responseString = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(#"responseString %#",responseString);
NSError *error;
NSArray *json = [NSJSONSerialization JSONObjectWithData:data
options:(kNilOptions)
error:&error];
NSLog(#"json data == %#", json);
NSMutableArray *response =[[NSMutableArray alloc]init];
for (int i = 0; i < json.count; i++)
{
response = [json valueForKey:#"imdbRating"];
User * userObj = [[User alloc]init];
userObj.movieRating = [json valueForKey:#"imdbRating"];
[response addObject:userObj];
}
[delegate getIMDBMovie_Rating:response];
}
How to save data in bussiness model object for key imdbRating
The Json you specified is not an array. This is an NSDictionary object. Also as this is a NSDictionary you don't need to use for loop.
Second thing you are doing wrong with your response variable.
you did:
response = [json valueForKey:#"imdbRating"];
User * userObj = [[User alloc]init];
userObj.movieRating = [json valueForKey:#"imdbRating"];
[response addObject:userObj];
here response variable is not an array even though you allocated it as NSMutableArray earlier. As you assign new value in response in the line: response = [json valueForKey:#"imdbRating"];
your variable type will be either NSNumber or NSString based on the type of [json valueForKey:#"imdbRating"].
So remove the line response = [json valueForKey:#"imdbRating"]; and it will work.
By doing this you will hv an array of User objects containing imdbRatings.
UPDATE
According to your comment your code has:
-(void)getIMDBMovie_Rating:(NSMutableArray*)retrievedData {
if (retrievedData.count > 0)
{
userObj = [retrievedData objectAtIndex:0];
NSLog(#"%#is the value",retrievedData);
iMDB_MovieRatingLabel.text=userObj.movieRating;
}
}
Problem is in your getIMDBMovie_Rating. as your method is accepting NSMutableArray as parameter. But when you supply value for your method is NSDictionay [delegate getIMDBMovie_Rating:response]; (you can check by NSLog(#"%#", [response class]);).
So in your getIMDBMovie_Rating method you are accessing [retrievedData objectAtIndex:0];. objectAtIndex is not available with NSDictionay that's why your app get crash.
Try like this,
-(void)parseData:(NSData *)data
{
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"responseString %#",responseString);
NSError *error;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:(kNilOptions) error:&error];
NSLog(#"json data == %#", json);
NSMutableArray *response =[[NSMutableArray alloc]init];
NSArray *aArray = [json valueForKey:#"imbdRating"];
for (NSDictionary *dictionary in aArray)
{
/* Create a initWithData method in your User Model class and pass the dictionary object to it like,
- (id) initWithData:(NSDictionary *) jsonDictionary
{
self=[super init];
if(self)
{
self.movieRating =[json valueForKey:#"imdbRating"];
} */
User * userObj = [[User alloc]initWithData:dictionary];
[response addObject:userObj];
}
[delegate getIMDBMovie_Rating:response];
}
I'm attempting to download data from MySQL. However when NSURLSession creates a new thread, the data hasn't completely downloaded and thus the main thread is dealing with null values / crashes. I've used GCD's dispatch_async, however it's a few milliseconds slow.
In my test program, I have two NSLogs, one directly after calling the NSURLSession method and the other in the method itself. The output (below) shows NSURLSession is delayed by 30 milliseconds. Although while the time itself isn't much, it would have an enormous impact in how I'll structure my task. Is there any way to pause the main thread until the data has been downloaded and the method has been finished?
2014-03-30 18:56:06.224 TestProgram[1396:60b] (null)
2014-03-30 18:56:06.258 TestProgram[1396:60b] [{"error":200}]
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
if(error == nil)
{
dispatch_async(dispatch_get_main_queue(), ^{
NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(#"%#",text);
NSError *error;
self.json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
for(int i =0 ; i < self.json.count ; i++)
{
[dataParse setDictionary:_json[i]];
}
});
} else {
NSLog(#"Response:%# %#\n", response, error);
}
}];
[dataTask resume];
Take a look at the documentation for the NSURLSessionDataTask completion routine. It seems to imply that the data is not completely downloaded at that point.
I am new to xcode and I seem to be stuck at trying to create a tableview with sections.
My code below creates the header however I cannot seem to display the rows that belong to the section. I'm sure it has to do with the multidimensional array. I say this because "dobSection" value is "results" when I suppose it should display the dates under "DOB".
I have spent hours trying many different ways to get this to work..... eh! No luck.
The Json is somewhat like this:
{"results":
[{"name":"joe","surname":"blow","DOB":"1990-01-01"},
{"name":"jane","surname":"doe","DOB":"1990-01-01"},
{"name":"john","surname":"doe","DOB":"1995-06-06"}]
}
and the code
NSMutableArray *jsonResults;
- (void)fetchedData:(NSData *)responseData {
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
jsonResults = [json objectForKey:#"results"];
self.dob = json;
self.keys = [jsonResults valueForKey:#"DOB"];
[self.tableView reloadData];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [keys count];
//return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
// NSString *key = [keys objectAtIndex:section];
NSString *key = [keys objectAtIndex:section];
NSArray *dobSection = [dob objectForKey:key];
return [dobSection count];
}
in addition by replacing this:
NSArray *dobSection = [dob objectForKey:key];
with
NSArray *dobSection=[[games objectForKey:#"results"]valueForKey:#"dob"];
I get all rows.
I cannot get them to group by DOB
My code above may be flawed however I would love some input on how to get this right.
Thank you
I have a problem to download a file or manage an error in some cases (JSON)
The download works very fine. The problem is the server can send a 404 or 200 (with JSON) in a few cases when the user requests the download.
How to handle the JSON in this case? When we send the request we don't know if we will receive JSON error (with a 200 status oR 404) or the zipped file...
I don't see how responseObject can help me.
Here is my code:
AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:zipPath append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"Successfully downloaded zip file to %#", zipPath);
// is-it impossible to handle a JSON response here ?
// responseObject can help me ? don't think !
// do what I have to do after the download is complete
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
// 404
// is-it impossible to handle a JSON response here ?
if ([error code] == -1011)
{
}
}];
[operation setDownloadProgressBlock:^(NSInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
float progress = ((float)((int)totalBytesWritten) / (float)((int)totalBytesExpectedToWrite));
self.progressView.progress = progress;
}];
[operation start];
Does I need to make a AFJSOnRequestOperation ? But in this case, how to receive the downloaded file that is not JSON ?
Thanks for helping.
EDIT: as I wroted in my comments, I can get and catch the responseData in success block ONLY if I comment the line:
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:zipPath append:NO];
It's logical, I suppose the response goes into outputStream instead of success block. Is there a solution for that ?
The server should signal the MIME type in the header Content-Type.
If it doesn't you need to detect the data type yourself.
This line ensures to get all responses with statuscode 200-499 in the success block:
[AFHTTPRequestOperation addAcceptableStatusCodes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(300, 200)]];
In the success block you need to identify the type of response:
id jsonObject = AFJSONDecode(operation.responseData, NULL);
if (jsonObject) {
// handle JSON
} else {
// handle zip file
}
You can also inspect operation.response.statusCode and operation.response.MIMEType beforehand.
I've tried with AFJSOnRequestOperation, in .m I simply put the outputStream beneath the init:
AFJSONRequestOperation *requestOperation = [[[self alloc] initWithRequest:urlRequest] autorelease];
requestOperation.outputStream = [NSOutputStream outputStreamToFileAtPath:[FullyLoaded filePathForResourceAtURL:urlRequest.URL.absoluteString] append:NO];
And the same happens, responseData is nil unless commenting the outputStream line, so it's not HTTPRequest or JSOnRequest issue. The way I use to get around is to JSON sequence the object from the responseData and write it to file, rather than directly outputstream the request.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFCompoundResponseSerializer serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"application/octet-stream"];
AFHTTPRequestOperation *operation = [manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (responseObject) {
}
else{
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
[operation start];
// manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"application/octet-stream"]; : can vary based on what you expect