I get the following _downloadedData:
<!-- pageok -->
<!-- managed by puppet -->
<html>
<pre>pageok</pre>
</html>
When using the code listed below:
- (void)downloadItems
{
//Download the json file
NSURL *jsonFileUrl = [NSURL URLWithString:#"http://www.scratchclass.com:80/videos/"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:jsonFileUrl];
[request setHTTPMethod:#"GET"];
[request setValue:#"text/html" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"gzip" forHTTPHeaderField:#"Content-Encoding"];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
if(!connection){
NSLog(#"Connection Failed");
}
}
#pragma mark NSURLConnectionDataProtocol Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"didReceiveResponse: %#",response);
// Initialize the data object
_downloadedData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the newly downloaded data
[_downloadedData appendData:data];
NSString* newStr = [[NSString alloc] initWithData:_downloadedData encoding:NSUTF8StringEncoding ];
NSLog(#"didReceiveData: %#",newStr);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Create an array to store the videos
NSMutableArray *_videos = [[NSMutableArray alloc] init];
// Parse the JSON that came in
NSError *error;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:_downloadedData options:NSJSONReadingMutableContainers error:&error];
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
// Loop through Json objects, create question objects and add them to our questions array
for (int i = 0; i < jsonArray.count; i++)
{
NSDictionary *jsonElement = jsonArray[i];
// Create a new video object and set its props to JsonElement properties
GetVideos1 *testVideo = [[GetVideos1 alloc] init];
testVideo.IDVideo = jsonElement[#"IDVideo"];
testVideo.title = jsonElement[#"title"];
// Add this question to the locations array
[_videos addObject:testVideo];
}
// Ready to notify delegate that data is ready and pass back items
if (self.delegate)
{
[self.delegate itemsDownloaded:_videos];
}
}
json is actually:
[{"IDVideo":"6Joup252fR0","title":"Top 30 Baseball
Plays"},{"IDVideo":"aAy3Sh_RXjc","title":"MLB top
plays"},{"IDVideo":"bkiaAGOoLjc","title":"Top 50 most unforgettable
ejections"}]
But I cannot get to the data as it is part of the #text node name. How can I fetch the data?
Here is the php code that was used:
<?php
// Check connection
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
// Constructor - open DB connection
function __construct() {
$this->db = new mysqli('idirectorySQL.db.9960960.hostedresource.com', 'idirectorySQL', 'iDirectory70!', 'idirectorySQL');
$this->db->autocommit(FALSE);
}
$con=mysqli_connect('idirectorySQL.db.9960960.hostedresource.com', 'idirectorySQL', 'iDirectory70!', 'idirectorySQL');
// This SQL statement selects ALL from the table 'videos'
$sql = "SELECT IDVideo,title FROM videos";
// Check if there are results
if ($result = mysqli_query($con, $sql)) {
// If so, then create a results array and a temporary one
// to hold the data
$resultArray = array();
$tempArray = array();
// Loop through each row in the result set
while($row = $result->fetch_object()) {
// Add each row into our results array
$tempArray = $row;
array_push($resultArray, $tempArray);
}
// Close connections
mysqli_close($con);
// Finally, encode the array to JSON and output the results
header('Content-type: application/json');
// echo json_encode($resultArray, JSON_PRETTY_PRINT);
echo json_encode($resultArray);
}
?>
I used
header('Content-type:application/x-www-form-urlencoded')
but I still received the same message. Also, this is what reads from the request headers:
Accept text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Don't set any custom parameters in the NSURLRequest, GET is the default anyway.
As NSURLConnection is deprecated, this is a solution with the recommended NSURLSession API
NSURL *url = [NSURL URLWithString:#"http://www.scratchclass.com:80/videos/"];
NSURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * data, NSURLResponse * response, NSError * error) {
if (error) {
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
} else {
NSError *jsonError;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&jsonError];
if (jsonError) {
NSLog(#"NSJSONSerialization failed! Error - %# %#",
[jsonError localizedDescription],
[[jsonError userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
} else {
NSMutableArray *videos = [[NSMutableArray alloc] init];
for (NSDictionary *item in jsonArray) {
GetVideos1 *testVideo = [[GetVideos1 alloc] init];
testVideo.IDVideo = item[#"IDVideo"];
testVideo.title = item[#"title"];
// Add this question to the locations array
[videos addObject:item];
}
if (self.delegate) {
[self.delegate itemsDownloaded:videos];
}
}
}
}] resume];
Related
I want to download some items from my host,
but now I get a warning:
'connectionWithRequest:delegate:'is deprecated in iOS9.0 - Use NSURLSession'
I've searched everywhere, but unfortunately I couldn't find any solution.
Can you help me?
My code looks like this:
- (void)downloadItems
{
// Download the json file
NSURL *jsonFileUrl = [NSURL URLWithString:#"http://myhost.com/test.php"];
// Create the request
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:jsonFileUrl];
// Create the NSURLConnection
[NSURLConnection connectionWithRequest:urlRequest delegate:self];
}
#pragma mark NSURLConnectionDataProtocol Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// Initialize the data object
_downloadedData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the newly downloaded data
[_downloadedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Create an array to store the locations
NSMutableArray *_locations = [[NSMutableArray alloc] init];
// Parse the JSON that came in
NSError *error;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:_downloadedData options:NSJSONReadingAllowFragments error:&error];
// Loop through Json objects, create question objects and add them to our questions array
for (int i = 0; i < jsonArray.count; i++)
{
NSDictionary *jsonElement = jsonArray[i];
// Create a new location object and set its props to JsonElement properties
Location *newLocation = [[Location alloc] init];
newLocation.idS = jsonElement[#"idStatistic"];
newLocation.temp = jsonElement[#"temp"];
newLocation.hum = jsonElement[#"hum"];
newLocation.date_time = jsonElement[#"date_time"];
// Add this question to the locations array
[_locations addObject:newLocation];
}
// Ready to notify delegate that data is ready and pass back items
if (self.delegate)
{
[self.delegate itemsDownloaded:_locations];
}
}
Replacing NSURLConnection line with:
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:jsonFileUrl
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
// handle response
}] resume];
I'm currently using Oauth2SampleTouch by Google, so people can log-in with their google accounts into my app. However whenever I call a method from The SampleRootViewController it doesn't go through the authorizeRequest method (only if I call it from another class.).
Here's the method in SampleRootViewController that I'm calling form another class.(the user is already logged in by this time)
-(NSString *)hasLikedVideo:(NSString *)videoID {
liked = #"NULL";
NSString *clientID = #"myClientID";
NSString *clientSecret = #"myClientSecret";
self.auth = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName
clientID:clientID
clientSecret:clientSecret];
NSString *urlStr = [NSString stringWithFormat:#"https://www.googleapis.com/youtube/v3/videos/getRating?id=%#&key=AIzaSyB437bMtpbJh-OrkieCDRtYLe6L1Ijb3Ww", videoID];
NSLog(#"URL FOR LIKE : %# auth:(%#)", urlStr, self.auth);
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSLog(#"stage 1");
[self.auth authorizeRequest:request
completionHandler:^(NSError *error) {
if (error == nil) {
// the request has been authorized
NSLog(#"ERROR LOADING AUTH 1 : %#", [error description]);
} else {
NSLog(#"ERROR LOADING AUTH 2 : %#", [error description]);
}
NSLog(#"stage 2");
NSString *output = nil;
if (error) {
output = [error description];
NSLog(#"ERROR FROM LOADING LIKE INFO : %#", output);
} else {
NSLog(#"stage 3");
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
[self displayAlertWithMessage:output];
if (data) {
// API fetch succeeded
NSLog(#"stage 32");
output = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
// NSLog(#"%#", data);
[self displayAlertWithMessage:output];
} else {
NSLog(#"stage 34");
// fetch failed
output = [error description];
[self displayAlertWithMessage:output];
}
}
NSData* json = [output dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *allCourses = [NSJSONSerialization
JSONObjectWithData:json
options:kNilOptions
error:&error];
NSArray *monday = allCourses[#"items"];
for ( NSDictionary *theCourse in monday )
{
liked = theCourse[#"rating"];
NSLog(#"LIKE INSIDE ARRAY : %#", theCourse[#"rating"]);
}
if( error )
{
NSLog(#"%#", [error localizedDescription]);
}
}];
NSLog(#"stage 4");
return liked;
}
The method runs because I can see it log the string, however it doesn't go through the authorizeRequest, it doesn't even print out the error messages. HOWEVER if my viewController is SampleRootViewController and I call the method from itself it works.
So basically
TestViewcontroller calls a method in SampleRootViewController -> doesn't go through authorizeRequest.
SampleRootViewController calls a method in SampleRootViewController (from itself) -> goes through authorizeRequest and works.
EDIT:
I found out what I was doing "wrong"
I was calling the method like this in background
[self performSelectorInBackground:#selector(getAuthDetails) withObject:nil];
instead of
[self getAuthDetails];
I am using a button action to update the value of a MySQL table field. The update is perform in the web server, but I need to update a UILabel text in my view Controller.
This is the code I have implemented:
- (IBAction)votarAction:(id)sender {
//URL definition where php file is hosted
dispatch_queue_t backgroundQueue = dispatch_queue_create("com.mycompany.myqueue", 0);
dispatch_async(backgroundQueue, ^{
int categoriaID = [[detalleDescription objectForKey:#"idEmpresa"] intValue];
NSString *string = [NSString stringWithFormat:#"%d", categoriaID];
NSLog(#"ID EMPRESA %#",string);
NSMutableString *ms = [[NSMutableString alloc] initWithString:#"http://mujercanariasigloxxi.appgestion.eu/app_php_files/cambiarvaloracionempresa.php?id="];
[ms appendString:string];
// URL request
NSLog(#"URL = %#",ms);
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:ms]];
//URL connection to the internet
NSURLConnection *connection=[[NSURLConnection alloc]initWithRequest:request delegate:self];
dispatch_async(dispatch_get_main_queue(), ^{
//update your label
});
});
}
#pragma NSURLConnection Delegate Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
//buffer is the object Of NSMutableData and it is global,so declare it in .h file
buffer = [NSMutableData data];
NSLog(#"ESTOY EN didReceiveResponse*********");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"ESTOY EN didReceiveDATA*********");
[buffer appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//Here You will get the whole data
NSLog(#"ESTOY EN didFINISHLOADING*********");
NSError *jsonParsingError = nil;
NSArray *array = [NSJSONSerialization JSONObjectWithData:buffer options:0 error:&jsonParsingError];
//And you can used this array
NSLog(#"ARRAY = %#",array);
//HERE LABEL.TEXT UPDATE CODE
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"ERROR de PARSING");
NSLog(#"ESTOY EN didFAILWITHERROR*********");
}
As I told you, the field value at the MySQL table is updated every time the button is tapped, but the problem is that the NSURLConnection delegate methods are never called.
Any help is welcome
In your view controller's header file add: <NSURLConnectionDelegate>
Also, there's no need to throw the NSURLConnection into a seperate background process, maybe that's why the delegates aren't called. NSURLConnection is already asynchronous
Perhaps try something like this:
- (IBAction)votarAction:(id)sender
{
int categoriaID = [[detalleDescription objectForKey:#"idEmpresa"] intValue];
NSString *originalString = [NSString stringWithFormat:#"%d", categoriaID];
NSMutableString *mutablesString = [[NSMutableString alloc] initWithString:#"http://mujercanariasigloxxi.appgestion.eu/app_php_files/cambiarvaloracionempresa.php?id="];
[mutableString appendString:originalString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:mutableString]];
request.cachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
request.timeoutInterval = 5.0;
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:
^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
if (data)
{
NSArray *array = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
dispatch_async(dispatch_get_main_queue(), ^
{
// Update your label
self.label.text = [array objectAtIndex:someIndex];
});
}
else
{
// Tell user there's no internet or data failed
}
}];
}
I have set up a simple Objective-C class in my iOS app which has one simple task, to download a JSON file, parse it and then pass back a NSString which contains a variable parsed from the downloaded JSON file.
The problem I have is that I am calling this class from another class and this all works great however I need to pass back the NSString to the class from which I am calling it from.
The problem is that the method passes back the empty NSString BEFORE connectionDidFinishLoading happens.... And so the NSString never gets assigned a string......
I have setup a while loop in my method but it doesn't really work.....
here is my code:
-(NSString *)get_user_icon:(NSString *)YT_ID {
// Set BOOL to 0 for initial setup.
icon_check = 0;
NSString *url_YT = [NSString stringWithFormat:YOUT_profile_part_2, YT_ID];
dispatch_queue_t downloadQueue = dispatch_queue_create("Icon downloader YouTube", NULL);
dispatch_async(downloadQueue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSURLRequest *theRequest_YT = [NSURLRequest requestWithURL:[NSURL URLWithString:url_YT]];
NSURLConnection *theConnection_YT = [[NSURLConnection alloc] initWithRequest:theRequest_YT delegate:self];
if (theConnection_YT) {
YT_JSON_FEED = [[NSMutableData alloc] init];
NSLog(#"Respoce happening...");
}
else {
NSLog(#"failed");
}
});
});
while (icon_check == 0) {
NSLog(#"Wait");
}
return icon_url;
}
/// Data loading ///
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[YT_JSON_FEED setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[YT_JSON_FEED appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSString *msg = [NSString stringWithFormat:#"Failed: %#", [error description]];
NSLog(#"%#",msg);
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSError *myError = nil;
NSDictionary *feed = [NSJSONSerialization JSONObjectWithData:YT_JSON_FEED options:NSJSONReadingMutableLeaves error:&myError];
icon_url = [[[[[feed objectForKey:#"items"] valueForKey:#"snippet"] valueForKey:#"thumbnails"] valueForKey:#"default"] valueForKey:#"url"];
icon_check = 1;
}
For a synchronous request (blocking until there is something to return), use NSURLConnection's sendSynchronousRequest:returningResponse:error: instead. Like so:
-(NSString *)get_user_icon:(NSString *)YT_ID {
NSString *url_YT = [NSString stringWithFormat:YOUT_profile_part_2, YT_ID];
NSURLRequest *theRequest_YT = [NSURLRequest requestWithURL:[NSURL URLWithString:url_YT]];
NSURLResponse* response = nil;
NSError* error = nil;
NSData* data = [NSURLConnection sendSynchronousRequest:theRequest_YT returningResponse:&response error:&error];
//Check response and error for possible errors here.
//If no errors.
NSDictionary *feed = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&myError];
icon_url = [[[[[feed objectForKey:#"items"] valueForKey:#"snippet"] valueForKey:#"thumbnails"] valueForKey:#"default"] valueForKey:#"url"];
return icon_url;
}
However this is not recommended. You need to change your API to be asynchronous. Either delegate-based, but more preferably, using block-based API.
In my iOS app I've to parse a JSON file. From this JSON I need the following stuff: name, image width and image height. To get image name I'ven't any problem, to get image with and height I use the following code:
- (void) loadImageFromWeb:(NSString *)urlImg forName:(NSString*)name {
NSURL* url = [NSURL URLWithString:urlImg];
//NSURLRequest* request = [NSURLRequest requestWithURL:url];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
NSString *authCredentials =#"reply:reply";
NSString *authValue = [NSString stringWithFormat:#"Basic %#",[authCredentials base64EncodedStringWithWrapWidth:0]];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
if (!error){
UIImage* image = [[UIImage alloc] initWithData:data];
imageWidth = image.size.width;
imageHeight = image.size.height;
imgWidth = [NSString stringWithFormat:#"%f", imageWidth];
imgHeight = [NSString stringWithFormat:#"%f", imageHeight];
self.dictWithDataForPSCollectionView = #{#"title": name,
#"width": imgWidth,
#"height": imgHeight};
[self.arrayWithData addObject:self.dictWithDataForPSCollectionView];
NSLog(#"DATA ARRAY: %#", self.arrayWithData);
} else {
NSLog(#"ERRORE: %#", error);
}
}];
}
You can see that I save the name, image width and image height in a NSDictionary then I put this in an NSMutableArray. When it execute the NSLog, I see this:
DATA ARRAY: (
{
height = "512.000000";
title = "Eau de Toilet";
width = "320.000000";
},
{
height = "1049.000000";
title = "Eau de Toilet";
width = "1405.000000";
}
)
My question is how to get this information back in the class who call my json parser, I tried to access to the variable in this way:
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
recivedData = [[NSMutableData alloc]init];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[recivedData appendData:data];
NSString *string = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"JSON: %#", string);
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSDictionary *json;
NSError *err;
json = [NSJSONSerialization JSONObjectWithData:recivedData options:NSJSONReadingMutableLeaves error:&err];
JsonCategoryReader *reader = [[JsonCategoryReader alloc]init];
[reader parseJson:json];
}
But when I run the code it shows me an empty array. How I can have the information in this class?
UPDATE:
The JSON I've to parse is the following:
{
"1":{
"entity_id":"1",
"type_id":"simple",
"sku":"EAU_DE_TOILET_1",
"description":"A passionate scent with the zest of exclusive Zegna Bergamot, sparked by Violettyne Captive, and the warmth of Vetiver and Cedarwood",
"short_description":"EAU DE TOILETTE NATURAL SPRAY",
"meta_keyword":null,
"name":"Eau de Toilet",
"meta_title":null,
"meta_description":null,
"regular_price_with_tax":60,
"regular_price_without_tax":60,
"final_price_with_tax":60,
"final_price_without_tax":60,
"is_saleable":true,
"image_url":"http:\/\/54.204.6.246\/magento8\/media\/catalog\/product\/cache\/0\/image\/9df78eab33525d08d6e5fb8d27136e95\/p\/r\/product_100ml.png"
},
"2":{
"entity_id":"2",
"type_id":"simple",
"sku":"EAU_DE_TOILET_2",
"description":"A passionate scent with the zest of exclusive Zegna Bergamot, sparked by Violettyne Captive, and the warmth of Vetiver and Cedarwood",
"short_description":"EAU DE TOILETTE NATURAL SPRAY",
"meta_keyword":null,
"name":"Eau de Toilet",
"meta_title":null,
"meta_description":null,
"regular_price_with_tax":60,
"regular_price_without_tax":60,
"final_price_with_tax":60,
"final_price_without_tax":60,
"is_saleable":true,
"image_url":"http:\/\/54.204.6.246\/magento8\/media\/catalog\/product\/cache\/0\/image\/9df78eab33525d08d6e5fb8d27136e95\/s\/c\/scheda_non_shop.jpg"
}
}
My method parseJson do the following:
- (void)parseJson:(NSDictionary *)jsonDict {
// Controllo che il json sia stato ricevuto
if (jsonDict) {
self.nameArray = [[NSMutableArray alloc]init];
self.imgUrlArray = [[NSMutableArray alloc]init];
self.dictWithDataForPSCollectionView = [[NSDictionary alloc]init];
self.arrayWithData = [[NSMutableArray alloc]init];
[self createArrayWithJson:jsonDict andIndex:1];
[self createArrayWithJson:jsonDict andIndex:2];
}
- (void)createArrayWithJson:(NSDictionary*)json andIndex:(NSString*)i {
NSDictionary *products = [json objectForKey:i];
NSString *name = [products objectForKey:#"name"];
NSString *imgUrl = [products objectForKey:#"image_url"];
// Scarico l'immagine e calcolo le dimensioni
if (name != nil && imgUrl != nil) {
[self loadImageFromWeb:imgUrl forName:name];
}
}
I hope you understand what I did
what happen is that your class is make before that your json is download, for have a good sequence you have to call your method for parse the json inside the completionHandler block, when you are sure that it is download. then when you have your object load you can parse it like this example:
for (NSDictionary *dic in reader.arrayWithData){
NSLog("height: %#",[dic objectForKey:#"height"]);
NSLog("title: %#",[dic objectForKey:#"title"]);
NSLog("width: %#",[dic objectForKey:#"width"]);
}