I have the following code and it is working to an extent :
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSString *strURL = [NSString stringWithFormat:#"http://localhost:8888/service.php"];
NSURL *url = [NSURL URLWithString:strURL];
NSData * data = [NSData dataWithContentsOfURL:url];
NSError * error;
NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
AdObject *someAdObject = [[AdObject alloc] init];
//NSLog(#"%#", json);
self.detailLabel.text = self.tempString;
}
Now when the commented out NSLog actually prints the JSON dictionary, I get :
{
brand = "";
category = Games;
country = "Japan";
"discount_rate" = 50;
duration = 5;
id = 1;
"issue_date" = "2014-04-07";
location = "Heishi Mall";
title = "Gamestory videogames sales!";
user = "";
}
)
I created an Ad object which has properties such as title, location, country, etc (as reflected above). I would like to access the JSON above and store value in object variables.
You can access that values :-
for(NSDictionary *item in json) {
NSLog(#"%#",[item valueForKey:#"key"]);
someAdObject.key = [item valueForKey:#"key"];
}
Try this and review your json also
AdObject *someAdObject = nil;
for(NSDictionary *item in json) {
someAdObject = [[AdObject alloc] init];
someAdObject.category = [item valueForKey#"category"];
someAdObject.country = [item valueForKey#"country"];
someAdObject.discount_rate = [item valueForKey#"discount_rate"];
someAdObject.duration = [item valueForKey#"duration"];
//and same all of your required object properties
}
Related
What I'm trying to do is to pass data from my Objective-C to my swift file.
Recently, when I have successfully connected my objective c file with my swift file, I can print data that get from UNIUrlConnection(which means the connection between swift and objective-c works fine).
Then I create a NSMutableDictionary object and add those data into NSMutableDictionary. I want to pass this NSMutableDictionary object to my swift file so that I can output them on my viewController.
However, the NSMutableDictionary contains correct data within the UNIUrlConnection but then contains none out of UNIUrlConnection. Thus the NSMutableDictionary passed to swift file would always contain no data. How can I solve this?
This is my objective c file.
#import <Foundation/Foundation.h>
#import <UNIRest.h>
#import "findByIngredients.h"
#implementation findByIngredients
-(NSMutableDictionary*) connectAPI:(NSString*) ingredients Number:(NSString*) number{
NSMutableDictionary *temp = [NSMutableDictionary dictionaryWithCapacity:10];
NSString* url = #"https://spoonacular-recipe-food-nutrition-v1.p.mashape.com/recipes/findByIngredients?fillIngredients=false";
if (![ingredients isEqual: #""]) {
NSString* ingre = #"&ingredients=";
ingre = [ingre stringByAppendingString:ingredients];
url = [url stringByAppendingString:ingre];
}
else {
NSString* ingre = #"&ingredients=<required>";
url = [url stringByAppendingString:ingre];
}
NSString* LL = #"&limitLicense=false";
url = [url stringByAppendingString:LL];
if (![number isEqual: #""]) {
NSString* numberOfReturn = #"&number=";
numberOfReturn = [numberOfReturn stringByAppendingString:number];
url = [url stringByAppendingString:numberOfReturn];
}
NSString* ranking = #"&ranking=1";
url = [url stringByAppendingString:ranking];
// These code snippets use an open-source library. http://unirest.io/objective-c
NSDictionary *headers = #{#"X-Mashape-Key": #"KEY", #"Accept": #"application/json"};
UNIUrlConnection *asyncConnection = [[UNIRest get:^(UNISimpleRequest *request) {
[request setUrl:url];
[request setHeaders:headers];
}] asJsonAsync:^(UNIHTTPJsonResponse *response, NSError *error) {
NSInteger code = response.code;
NSDictionary *responseHeaders = response.headers;
UNIJsonNode *body = response.body;
NSData *rawBody = response.rawBody;
if (rawBody) {
id allKeys = [NSJSONSerialization JSONObjectWithData:rawBody options:0 error:&error];
for (int i=0; i<[allKeys count]; i++) {
NSDictionary *arrayResult = [allKeys objectAtIndex:i];
// NSString* myNewString = [NSString stringWithFormat:#"%d", i];
NSString *key = [arrayResult objectForKey:#"id"];
NSString *value = [arrayResult objectForKey:#"title"];
[temp setObject:value forKey:key];
NSLog(#"id=%#",[arrayResult objectForKey:#"id"]);
NSLog(#"title=%#",[arrayResult objectForKey:#"title"]);
}
}
int size = [temp count];
NSLog(#"temp size is %d",size);
NSLog(#"successfully test API");
}];
// int size = [temp count];
// NSLog(#"temp size is %d",size);
return temp;
}
#end
Here the size of temp within UNIUrlConnection is correct. But if I put the size before return (which I comment out), it shows 0, which is wrong.
This is my swift file.
#IBAction func search(_ sender: Any) {
let ingreArr = IngredientsText.text.components(separatedBy: [",", " "])
var ingre:String = ingreArr[0]
let sep:String = "%2C"
for (index,element) in ingreArr.enumerated() {
if (index >= 1) {
ingre = ingre + sep + element
}
}
let test = findByIngredients()
// test.connectAPI(ingre, number: NumberOfResults.text)
let result: Dictionary = test.connectAPI(ingre, number: NumberOfResults.text) as Dictionary
let num:Int = result.count
print(num)
}
The num is 0.
The JSON Data
Please HELP I beg
2015-10-30 12:15:58.866 GooglePlaces[17141:989254] Google Data: (
{
geometry = {
location = {
lat = "55.599881";
lng = "-2.64616";
};
};
icon = "https://maps.gstatic.com/mapfiles/place_api/icons/generic_business-71.png";
id = 4e3047fc80549f89389827d05fb89a999705fcf2;
name = "Scott's view";
photos = (
{
height = 2368;
"html_attributions" = (
"Clarke Thomas"
);
"photo_reference" = "CmRdAAAADgCHDAr9O_RZg24-kHykYexBOTpKfhOAWTV-K1Go-sn6CGUoikhGc3beyjErYvXzCPLwFLRr32lC8tPpgfIA-CXue6l75ziHrlRXMOt72IZFBcbZfCBSSbttW5lHjSdfEhD5d08GC5Myl8L1_Zs0VmW2GhTzCD7bh_klEqsROxGDZLvskhzaBw";
width = 3200;
}
);
"place_id" = ChIJP5eCRF54h0gR9nc97bjfO8k;
rating = "4.7";
reference = "CmRgAAAAfN6yeOvYQEeRAzOcidZiE83kPoIdw_vDDH7orFr3gbZVXHeb3prAMlOCVWnVqeeK786c8x-V1QUtWfpSn-50Bk4Q5lO7fY04cNLsXigf1nx1JWiTee5d4TdKI1ij-jGDEhDXYtJPM_1H5t9KhqdSJiyuGhQAXqV2rosfllEOfE-suQ_ur89Bmg";
scope = GOOGLE;
types = (
parking,
"point_of_interest",
establishment
);
vicinity = B6356;
},
{
geometry = {
location = {
lat = "55.756977";
lng = "-4.17221";
};
};
icon = "https://maps.gstatic.com/mapfiles/place_api/icons/generic_business-71.png";
id = 481f927c8ea30c24ae902a14dd85efd7e2bae1d1;
name = "Kwik Fit";
"opening_hours" = {
"open_now" = 1;
"weekday_text" = (
);
};
photos = (
{
height = 608;
"html_attributions" = (
"Kwik Fit"
);
"photo_reference" = "CmRdAAAAY152xIVsahSMoZgsMMN1IdIlMq6fbPeMCJ_1feXg1BIOhRTaW-s_wauDF8WSVPXnOG4dOR3nE9fLzqHmTmdoyKIAef_tZVFKOK43880DeItFOKNejmt_QaEamB4nX8uvEhCPQYbVi8day5vi1KSzGPFtGhT8KzkGs_FuA5ZM11lydRplhPM8uA";
width = 1080;
}
);
"place_id" = "ChIJ1zdwq2s_iEgR1fI1QvrsCas";
reference = "CmRcAAAAkkARPnw1ApSjDPECBxsmTmcDDr5LESbSAWF0aNPvI2rX8BDJGfUj3dytKOotK2IbsCUaFbbhYZ8mgoDXfvYqtGliy2v06F2CarEAPSfD_25BGRYqUBsNKYiO05c-seGUEhDsuTEEt6PPKoZhmkBkj2VFGhQ-5vq-S7o73KmF2zw-MIJsPpWYgg";
scope = GOOGLE;
types = (
store,
parking,
"car_repair",
"point_of_interest",
establishment
);
vicinity = "1 Telford Road, East Kilbride";
},
{
geometry = {
location = {
lat = "55.618894";
lng = "-2.810683";
};
};
icon = "https://maps.gstatic.com/mapfiles/place_api/icons/generic_business-71.png";
id = 8ec3c7e9dc0da1d102d516107178cd440579ecff;
name = "Kwik-Fit";
"opening_hours" = {
"open_now" = 1;
"weekday_text" = (
);
};
photos = (
{
height = 608;
"html_attributions" = (
"Kwik-Fit"
);
"photo_reference" = "CmRdAAAAfbp51L51v3Mz4STPTBbUPvSy8b0GW_PYHQMcP6kXBDKIqhANAnVJINu3mdJk4mrEnG8-RSmR9SBa59z9qjRSxIVSEJapVWMSgGZzLHC3EVnib3-P3n1PnJyewKHVzR2tEhC5qWkLkJlXZl-6ETTap3GZGhSZCS6Wm9jEVAHx0nHwMTi6TNkVsw";
width = 1080;
}
);
"place_id" = ChIJqf1X7LyEh0gRK7GrZbR1qlI;
reference = "CmRbAAAAoIW6Uer6wFdg9f9c_kRg0s5Wc-6wyUwg49CWQtn9hphJTfCqmidaP_unuejhxZBS_hChwfTHYWsspU7nOOFZx08cmzQ9bAW7cTp1N7vxepNfqR1YNybBBtB4romQAZO7EhCfxI62ia7XGtVPIyEPRSIPGhR4HnxB4lrDp1o4daDSipUAvFoG4Q";
scope = GOOGLE;
types = (
store,
parking,
"car_repair",
"point_of_interest",
establishment
);
vicinity = "Bridge Street, Galashiels";
},
{
geometry = {
location = {
lat = "55.827528";
lng = "-4.041783";
};
};
icon = "https://maps.gstatic.com/mapfiles/place_api/icons/generic_business-71.png";
id = 993dd6caf6e87b27c95b597170f82fc535db8464;
name = "Scania Truck Rental";
photos = (
{
height = 416;
"html_attributions" = (
"Ian McCully"
);
"photo_reference" = "CmRdAAAAgxB25gl4CRnm6PENE9QPRq0WqPqIFUQCrvz7eOWsirTLMLZM_3gd_plKy9teW9AQdDIIZ3Ikmz96ADPiPD-wtDRvjDFMZl274q1HuA4zg8gVNi6QggypXkSPDdOdrfxUEhCf_qaIvJK0_iWgvnmT-TjcGhSRvsf9XiE5hkqcgwQdbKTm7oI5FA";
width = 640;
}
);
"place_id" = "ChIJ0YTxdlVqiEgRlNZz-R6gs9M";
reference = "CnRnAAAAGNBVd-2Rzx_pF8lzxZ5WsI1qC8752BhlsKAXwS36PkmNVCZ4VQkH2FjmRDJ3swxoGLfJ0YmG4Cr1MACDFNaPSv0QdBo5zjIXQyRfytk77g2g0XVspPR7IhO9mQpuQHNCA-DDp5m1ph_ry1W3kt8IahIQiW-loOYmR9yACbxLie-eyhoUQF04W9ZNAeasiM5OqTqPlyDn6g8";
scope = GOOGLE;
types = (
parking,
"car_repair",
"point_of_interest",
establishment
);
vicinity = "Melford Road, Bellshill";
},
{
geometry = {
location = {
lat = "55.778158";
lng = "-4.053103";
};
};
icon = "https://maps.gstatic.com/mapfiles/place_api/icons/generic_business-71.png";
id = 5b4e2e7beef36bc21e795144d512adb9cbc9ba54;
name = "National Tyres and Autocare";
"opening_hours" = {
"open_now" = 1;
"weekday_text" = (
);
};
photos = (
{
height = 631;
"html_attributions" = (
"National Tyres and Autocare"
);
"photo_reference" = "CmRdAAAALn7YnxOv_yKF3Sfkau09mJ1T7aY_L7La0E_2dxN9AGndS6evIYUPWCvYrQgSxD6Y69IsdGhkh08iY4gX0-YgXrbdtD0OBW6y8AjwVjYA34FLAAH9c122Kr_ImAGAmogREhDUOxeBxKmpZPcawyxxfnC9GhTJNNzPhS1xvgh_XPBXGOdhFhFgpQ";
width = 789;
}
);
"place_id" = ChIJrVjMcTMViEgRqc4gOlJfoDs;
reference = "CnRuAAAAoOOZVebI5pz8rifXu3_n9RbZv0sobjodbPcP1DhknZcwTuZ_zCjch7l3D0tPqSO21S4wQlhYuH6tOrgBzHwkYBcRMS2-XP5r234IevwkdYV04gAk4BPBfuJMQIyrvASsDtRN9LJkPp8By7OleSyyqhIQco-kf732PwomY9loLvEtbBoUc2ZZKVbvMIYk0pVeFQronor3UM8";
scope = GOOGLE;
types = (
store,
parking,
"car_repair",
"point_of_interest",
establishment
);
vicinity = "Peacock Cross, Almada Street, Hamilton";
}
2015-10-30 12:16:05.573 GooglePlaces[17141:989254] name Yosemite National Park
The header file
Where currentCenter is defined
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#define kGOOGLE_API_KEY #"the key here"
#interface AboutPlaceViewController : UIViewController <MKMapViewDelegate , CLLocationManagerDelegate>
{
CLLocationManager *locationManager;
CLLocation *location;
// Where Current Centre is defined
CLLocationCoordinate2D currentCentre;
int currenDist;
BOOL firstLaunch;
}
#property (weak, nonatomic) IBOutlet UILabel *placeLabell;
#end
The Implementation file
#import "AboutPlaceViewController.h"
#import "ViewController.h"
#interface AboutPlaceViewController ()
#end
#implementation AboutPlaceViewController
- (void)viewDidLoad {
[super viewDidLoad];
locationManager = [[CLLocationManager alloc]init];
locationManager.delegate = self;
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[locationManager startUpdatingLocation];
location = [locationManager location];
//Do any additional setup after loading the view.
NSDictionary *jsonDic = [[NSDictionary alloc]init];
[self getApiResponse:&jsonDic];
NSLog(#"jsonDic %#",jsonDic);
NSDictionary *resultDic = [jsonDic[#"results"] objectAtIndex:0];
NSString *name = resultDic[#"name"];
NSLog(#" name %#", name);
self.placeLabell.text = name;
}
-(void)getApiResponse:(NSDictionary**)dataDictionary
{
// Where i dig into the Json array one example provided above
NSDictionary *responseDict = [[NSDictionary alloc]init];
responseDict = [responseDict valueForKey:#"geometry"];
NSArray *responseArray = [responseDict valueForKey:#"location"];
NSDictionary *dict;
// The for loop it doesnt go inside the for loop when debugging
for(int i = 0; i< [responseDict count]; i++){
dict = [responseArray objectAtIndex:i];
NSLog(#"- %#",[responseArray objectAtIndex:i]);
}
// Where I declare but it returns nil :(
currentCentre.latitude = [dict[#"lat"]doubleValue];
currentCentre.longitude = [dict[#"lng"]doubleValue];
NSString *api_key = kGOOGLE_API_KEY;
NSString *urlString = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/search/json?location=%f,%f&radius=50&types=%#&sensor=true&key=%#",currentCentre.latitude , currentCentre.longitude,[NSString stringWithFormat:#"%i", currenDist],api_key];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLResponse *response;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:
request returningResponse:&response error:&error];
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
dataDictionary = [[NSDictionary alloc]initWithDictionary:jsonObject copyItems:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
The responseDict and the responseArray are also returning nil.
The currentCenter is returning nil and when I debug the code it doesn't go into the for loop. I have looked into the json format to find.
NSDictionary *responseDict = [[NSDictionary alloc]init];
responseDict = [responseDict valueForKey:#"geometry"];
These two lines of code are utter nonsense. Throw away any thought of what you think what these do lines should do, but look at them and figure out what they are doing. How code responseDict possibly be anything other than nil after executing these two lines?
First on all:
You have the following line:
location = [locationManager location];
You call the location straight after you initialise the manager.
If you look at the location method description it says:
/*
* location
*
* Discussion:
* The last location received. Will be nil until a location has been received.
*/
#property(readonly, nonatomic, copy, nullable) CLLocation *location;
I.E you should wait till the first location has been received.
Your class needs to implement CLLocationManagerDelegate and override:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
Make sure that you requestAlwaysAuthorization before you access the user location
Moreover,
What are you trying to do in this line?
NSDictionary *responseDict = [responseDict valueForKey:#"geometry"];
You are basically defining the dictionary and use it straight away.
As I found(If I am right) you are trying to fetch values from son data form server.
You can use NSJsonSerilazation for getting data from NSData. Below is only a demo code for getting values
NSData *yourDataFromServer;
NSError*error;
id records= [NSJSONSerialization JSONObjectWithStream:yourDataFromServer options:NSJSONReadingMutableContainers error:&error];
if (error!=nil)
{
if ([records isKindOfClass:[NSArray class]]) //Since you are getting Array Of Dictionary
{
NSDictionary *dictAtZeroIndex = records[0];
NSDictionary *latLonDict= [dictAtZeroIndex valueForKey:#"geometry"]; //Again it will be a dictionary. For safety, Here you can again check wheter you are getting dictionary or array using "isKindOfClass"
}
}
else{
NSLog(#"error is :%#",error.localizedDescription);
}
"yourDataFromServer" is NSData object coming from server. Might be helpful. Let me know if you are having any query. Use valueForKey with "latLonDict" for getting lat-lon values.
Anamica first of all you need to get the latitude and longitude value correctly.If you don not get that,you can't get other details by passing latitude and longitude values.
Getting Latitude and longitude values from your response
NSString *lataddr=[[[responseDict objectForKey:#"geometry"]objectForKey:#"location"]objectForKey:#"lat"];
NSString *longaddr=[[[responseDict objectForKey:#"geometry"]objectForKey:#"location"]objectForKey:#"lng"];
Then pass these strings to your url.Now you can get the response without nil.
Also please remove below coding from your part
NSArray *responseArray = [responseDict valueForKey:#"location"];
NSDictionary *dict;
// The for loop it doesnt go inside the for loop when debugging
for(int i = 0; i< [responseDict count]; i++){
dict = [responseArray objectAtIndex:i];
NSLog(#"- %#",[responseArray objectAtIndex:i]);
}
// Where I declare but it returns nil :(
currentCentre.latitude = [dict[#"lat"]doubleValue];
currentCentre.longitude = [dict[#"lng"]doubleValue];
instead of these part, you need to add
NSString *lataddr=[[[responseDict objectForKey:#"geometry"]objectForKey:#"location"]objectForKey:#"lat"];
NSString *longaddr=[[[responseDict objectForKey:#"geometry"]objectForKey:#"location"]objectForKey:#"lng"];
currentCentre.latitude = [lataddr doubleValue];
currentCentre.longitude = [longaddr doubleValue];
Above code for getting only single latitude and longitude value.
Now if you want to get the multiple latitude and longitude values for showing in map
NSMutableArray *arrayLat = [[NSMutableArray alloc]init];
NSMutableArray *arrayLng = [[NSMutableArray alloc]init];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:nil]; //This is for actually you are getting response to dict.
NSArray *arrayResponse = [dict copy];
NSLog(#"The response is - %#",arrayResponse);
for(int i=0;i<[arrayResponse count];i++)
{
NSString *lataddr=[[[[[arrayResponse objectAtIndex:i]valueForKey:#"geometry"]valueForKey:#"location"]valueForKey:#"lat"];
NSString *longaddr=[[[[[arrayResponse objectAtIndex:i]valueForKey:#"geometry"]valueForKey:#"location"]valueForKey:#"lng"];
[arrayLat addObject:lataddr];
[arrayLng addObject:longaddr];
}
for(int j=0;j<[arrayLat count];j++)
{
currentCentre.latitude = [[arrayLat objectAtIndex:j] doubleValue];
currentCentre.longitude = [[arrayLng objectAtIndex:j] doubleValue];
NSString *api_key = kGOOGLE_API_KEY;
NSString *urlString = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/search/json?location=%f,%f&radius=50&types=%#&sensor=true&key=%#",currentCentre.latitude , currentCentre.longitude,[NSString stringWithFormat:#"%i", currenDist],api_key];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLResponse *response;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:
request returningResponse:&response error:&error];
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
dataDictionary = [[NSDictionary alloc]initWithDictionary:jsonObject copyItems:YES];
}
All the best Anamica:-)
I'm still new to using NSURL to get data and seem to have issues whenever trying to use this. In this case I use debug to check all the date coming in in ViewDidload and all the correct data comes in and is split into the arrays I then want to use to build my table view controller. However when we reach the NumberOfRows in section method, all of the arrays seem to have been reset to nil.
I've tried using various combinations of NSURL solutions but none seem to get any further than the one I am using right now (which at least shows some data arrriving). Can anyone please let me know if I am making an obvious mistake, or if not give me a reliable piece of code which I should use to perform a simple GET like this.
Thank you very much.
Here below my code:
#implementation MyLessonsTableViewController
NSArray *pastarr = nil;
NSArray *todoarr = nil;
NSArray *comingarr = nil;
NSArray *jsonless = nil;
- (void)viewDidLoad {
[super viewDidLoad];
// GET MY LESSONS FROM DATABASE
jsonless = [[NSArray alloc] init];
pastarr = [[NSArray alloc] init];
todoarr = [[NSArray alloc] init];
comingarr = [[NSArray alloc] init];
NSString *token = #"5cfd28bed3f5f5bd63143c81a50d434a";
NSString *urlString = [NSString stringWithFormat:#"http://soon.nextdoorteacher.com/apps/api/nextdoorteacher/student-lessons?t=%#", token];
NSURL *urlcc = [NSURL URLWithString:urlString];
NSData *data = [NSData dataWithContentsOfURL:urlcc];
NSError *error;
NSMutableDictionary *jsonLess = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions
error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
NSLog(#"My Lessons Json == %#", jsonLess);
// SPLIT ARRAY
NSArray *pastarr = [jsonLess valueForKeyPath:#"past"];
NSArray *todoarr = [jsonLess valueForKeyPath:#"todo"];
NSArray *comingarr = [jsonLess valueForKeyPath:#"upcoming"];
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
NSUInteger lessonRowCount = 0;
switch (section) {
case 0:
lessonRowCount = todoarr.count;
break;
case 1:
lessonRowCount = comingarr.count;
break;
case 2:
lessonRowCount = pastarr.count;
break;
default:
break;
}
return lessonRowCount;
}
Several issues.
You call reloadData needlessly in dispatch_async.
You call reloadData before you process jsonLess.
You never assign anything to your array ivars.
You don't actually have ivars for your arrays. You have global variables.
Here's your posted code all fixed up:
#implementation MyLessonsTableViewController {
NSArray *pastarr = nil;
NSArray *todoarr = nil;
NSArray *comingarr = nil;
}
- (void)viewDidLoad {
[super viewDidLoad];
// GET MY LESSONS FROM DATABASE
NSString *token = #"5cfd28bed3f5f5bd63143c81a50d434a";
NSString *urlString = [NSString stringWithFormat:#"http://soon.nextdoorteacher.com/apps/api/nextdoorteacher/student-lessons?t=%#", token];
NSURL *urlcc = [NSURL URLWithString:urlString];
NSData *data = [NSData dataWithContentsOfURL:urlcc];
NSError *error;
NSMutableDictionary *jsonLess = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions
error:&error];
NSLog(#"My Lessons Json == %#", jsonLess);
// SPLIT ARRAY
pastarr = [jsonLess valueForKeyPath:#"past"];
todoarr = [jsonLess valueForKeyPath:#"todo"];
comingarr = [jsonLess valueForKeyPath:#"upcoming"];
[self.tableView reloadData];
}
Now this still suffers from one big problem. You are doing Internet access on the main thread. That's bad. You really should do it this way:
- (void)viewDidLoad {
[super viewDidLoad];
// GET MY LESSONS FROM DATABASE
NSString *token = #"5cfd28bed3f5f5bd63143c81a50d434a";
NSString *urlString = [NSString stringWithFormat:#"http://soon.nextdoorteacher.com/apps/api/nextdoorteacher/student-lessons?t=%#", token];
NSURL *urlcc = [NSURL URLWithString:urlString];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:urlcc];
NSError *error;
NSMutableDictionary *jsonLess = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions
error:&error];
NSLog(#"My Lessons Json == %#", jsonLess);
// SPLIT ARRAY
pastarr = [jsonLess valueForKeyPath:#"past"];
todoarr = [jsonLess valueForKeyPath:#"todo"];
comingarr = [jsonLess valueForKeyPath:#"upcoming"];
// Now this must be done on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}};
}
I load data from json and then add it to nsmutablearray like this:
- (void)loadData
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// Create array to hold dictionaries
myObject = [[NSMutableArray alloc] init];
NSData *jsonData = [NSData dataWithContentsOfURL:
[NSURL URLWithString:#"http://www.domain.com/json.php"]];
if(jsonData != nil)
{
NSError *error = nil;
id jsonObjects = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
if (error == nil){
dispatch_sync(dispatch_get_main_queue(), ^{
// values in foreach loop
for (NSMutableArray *tempArray in jsonObjects) {
[myObject addObject:tempArray];
NSSortDescriptor * sortDesc = [[NSSortDescriptor alloc] initWithKey:#"id.doubleValue" ascending:NO];
[myObject sortUsingDescriptors:[NSArray arrayWithObject:sortDesc]];
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
[self performSelectorOnMainThread:#selector(endAnimating) withObject:nil waitUntilDone:YES];
}
});
}
}
});
}
if I check with NSLog "tempArray" it's looks ok, but if I check "myObject", data added to it multiple times. How to add data just one time in to my "myObject" array?
EDIT:
My JSON result:
[{"id":"7","title":"monkey","thumb":"http:\/\/icon.s.photosight.ru\/img\/8\/e09\/5045427_thumb.jpg","url":"http:\/\/icon.s.photosight.ru\/img\/8\/e09\/5045427_large.jpg","day":"perjantai","date":"0","likes":"2","device_id":"1111","active":"1"},
{"id":"11","title":"Bukashka","thumb":"http:\/\/icon.s.photosight.ru\/img\/f\/b3b\/5078973_thumb.jpg","url":"http:\/\/icon.s.photosight.ru\/img\/f\/b3b\/5078973_large.jpg","day":"perjantai","date":"0","likes":"1","device_id":"1111","active":"1"},
{"id":"12","title":"blya","thumb":"http:\/\/icon.s.photosight.ru\/img\/f\/c1d\/5076251_thumb.jpg","url":"http:\/\/icon.s.photosight.ru\/img\/f\/c1d\/5076251_large.jpg","day":"perjantai","date":"0","likes":"1","device_id":"1111","active":"1"}]
My NSLog(#"%#", myObject);
2013-06-12 18:45:52.228 testApp[960:60b] (
{
active = 1;
date = 0;
day = perjantai;
"device_id" = 1111;
id = 7;
likes = 2;
thumb = "http://icon.s.photosight.ru/img/8/e09/5045427_thumb.jpg";
title = monkey;
url = "http://icon.s.photosight.ru/img/8/e09/5045427_large.jpg";
}
)
2013-06-12 18:45:52.230 testApp[960:60b] (
{
active = 1;
date = 0;
day = perjantai;
"device_id" = 1111;
id = 11;
likes = 1;
thumb = "http://icon.s.photosight.ru/img/f/b3b/5078973_thumb.jpg";
title = Bukashka;
url = "http://icon.s.photosight.ru/img/f/b3b/5078973_large.jpg";
},
{
active = 1;
date = 0;
day = perjantai;
"device_id" = 1111;
id = 7;
likes = 2;
thumb = "http://icon.s.photosight.ru/img/8/e09/5045427_thumb.jpg";
title = monkey;
url = "http://icon.s.photosight.ru/img/8/e09/5045427_large.jpg";
}
)
2013-06-12 18:45:52.237 testApp[960:60b] (
{
active = 1;
date = 0;
day = perjantai;
"device_id" = 1111;
id = 12;
likes = 1;
thumb = "http://icon.s.photosight.ru/img/f/c1d/5076251_thumb.jpg";
title = blya;
url = "http://icon.s.photosight.ru/img/f/c1d/5076251_large.jpg";
},
{
active = 1;
date = 0;
day = perjantai;
"device_id" = 1111;
id = 11;
likes = 1;
thumb = "http://icon.s.photosight.ru/img/f/b3b/5078973_thumb.jpg";
title = Bukashka;
url = "http://icon.s.photosight.ru/img/f/b3b/5078973_large.jpg";
},
{
active = 1;
date = 0;
day = perjantai;
"device_id" = 1111;
id = 7;
likes = 2;
thumb = "http://icon.s.photosight.ru/img/8/e09/5045427_thumb.jpg";
title = monkey;
url = "http://icon.s.photosight.ru/img/8/e09/5045427_large.jpg";
}
)
WORKING SOLUTION BY: danypata
in viewDidLoad put myObject = [[NSMutableArray alloc] init];
then
- (void)loadData
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSData *jsonData = [NSData dataWithContentsOfURL:
[NSURL URLWithString:#"http://www.domain.com/json.php"]];
if(jsonData != nil)
{
NSError *error = nil;
id jsonObjects = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
if (error == nil){
[myObject removeAllObjects];
for (NSMutableDictionary *tempDict in jsonObjects) {
[myObject addObject:tempDict];
}
NSSortDescriptor * sortDesc = [[NSSortDescriptor alloc] initWithKey:#"id.doubleValue" ascending:NO];
[myObject sortUsingDescriptors:[NSArray arrayWithObject:sortDesc]];
dispatch_sync(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
[self.tableView.pullToRefreshView stopAnimating];
});
}
}
});
}
One possible cause of your problem is that the tempArray arrays contains same objects, but to reply to your question `how to add just one time in to my "myObject" array" there are two easy solutions
One, use containsObject: method like this:
if([myObject containsObject:tempArray] == NO) {
[myObject addObject:tempArray]
}
Second, which I think is more elegant use NSMutableSet (`NSMutableSet adds objects only if the object is not already added). You can use it like this:
NSMutableSet *set = [[NSMutableSet alloc] init];
[set addObject:tempArray];
//after you added all objects just do the following after you init your myObject
[myObject addObjectsFromArray:[set allObjects]]
EDIT
Your problem is caused by the for loop. You are nto extracting properly the data, in your JSON you have an array of dictionaries not an array of arrays so you should change the for loop like this:
for (NSDictionary *tempDict in jsonObjects) {
[myObject addObject:tempDict];
//other operations here
}
I am trying to pull an LDAP "jpegPhoto" attribute from an openLDAP server using a iOS openLDAP framework. The framework pulls the data as a dictionary of NSStrings.
I need to convert the NSString of "jpegPhoto" (which also appears to be base64 encoded) to UIImage, with the end result being that I display the jpegPhoto as the user's image when they login.
More Info:
-(NSDictionary *)doQuery:(NSString *)query:(NSArray *)attrsToReturn {
...
while(attribute){
if ((vals = ldap_get_values_len(ld, entry, attribute))){
for(int i = 0; vals[i]; i++){
//Uncomment if you want to see all the values.
//NSLog(#"%s: %s", attribute, vals[i]->bv_val);
if ([resultSet objectForKey:[NSString stringWithFormat:#"%s",attribute]] == nil){
[resultSet setObject:[NSArray arrayWithObject:[NSString stringWithFormat:#"%s",vals[i]->bv_val]] forKey:[NSString stringWithFormat:#"%s",attribute]];
}else{
NSMutableArray *array = [[resultSet objectForKey:[NSString stringWithFormat:#"%s",attribute]] mutableCopy];
[array addObject:[NSString stringWithFormat:#"%s",vals[i]->bv_val]];
[resultSet setObject:array forKey:[NSString stringWithFormat:#"%s",attribute]];
}
}
ldap_value_free_len(vals);
};
ldap_memfree(attribute);
attribute = ldap_next_attribute(ld, entry, ber);
};
...
}
-(UIIMage *)getPhoto{
NSString *query = [NSString stringWithFormat:#"(uid=%#)",self.bindUsername];
NSArray *attrsToReturn = [NSArray arrayWithObjects:#"cn",#"jpegPhoto", nil];
NSDictionary *rs = [self doQuery:query:attrsToReturn];
NSString *photoString = [[rs objectForKey:#"jpegPhoto"] objectAtIndex:0];
NSLog(#"The photoString is: %i %#",[photoString length],#"characters long"); //returns 4
NSData *photoData = [NSData dataWithBase64EncodedString:photoString];
UIImage *userPhoto = [UIImage imageWithData:photoData];
return userPhoto;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.studentNameLabel.text = [NSString stringWithFormat:#"Hi %#!",[self.ldap getFullName]];
self.studentPhotoImage.image = [self.ldap getPhoto];
[self checkForProctor];
}
Try this code
NSData *dataObj = [NSData dataWithBase64EncodedString:beforeStringImage];
UIImage *beforeImage = [UIImage imageWithData:dataObj];
There are many similar questions in Stackoverflow.. Please refer the following links
UIImage to base64 String Encoding
UIImage from bytes held in NSString
(Since there has been no working code posted for getting the image data from LDAP, I wanted to add this answer for the benefit of future visitors.)
The missing piece was reading the binary data into an NSData object rather than an NSString when you have binary data that might contain NULL (zero) values within it, such as images or GUIDs.
value = [NSData dataWithBytes:vals[0]->bv_val length:vals[0]->bv_len];
+ (NSArray *)searchWithBaseDN:(const char *)baseDN andFilter:(const char *)filter andScope:(int)scope {
...
while(entry)
{
// create a dictionary to hold attributes
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
attribute = ldap_first_attribute(ld, entry, &ber);
while(attribute)
{
if ((vals = ldap_get_values_len(ld, entry, attribute)))
{
if (ldap_count_values_len(vals) > 1) {
NSMutableArray *values = [[NSMutableArray alloc] init];
for(int i = 0; vals[i]; i++) {
[values addObject:[NSString stringWithUTF8String:vals[i]->bv_val]];
}
[dictionary setObject:values forKey:[NSString stringWithUTF8String:attribute]];
} else {
NSObject *value = nil;
if (strcmp(attribute, "thumbnailPhoto") == 0 || strcmp(attribute, "objectGUID") == 0) {
value = [NSData dataWithBytes:vals[0]->bv_val length:vals[0]->bv_len];
} else {
value = [NSString stringWithFormat:#"%s", vals[0]->bv_val];
}
[dictionary setObject:value forKey:[NSString stringWithUTF8String:attribute]];
}
ldap_value_free_len(vals);
};
ldap_memfree(attribute);
attribute = ldap_next_attribute(ld, entry, ber);
};
...
}