First of all, excuse me for my bad english but I'm french and I'll try my best to be understandable.
So, I'm coding a simple application with this structure :
- viewController class (deal with the UI)
- product class (define the object product)
- ws_product class (contains some functions which get json datas)
What I'm trying to do is to return the products array, that I get after I parsed my json in ws_product, in my viewController. Thanks to this I'll can fill my tableView and my application will no longer be empty !
My actual ws_product is :
#import "WS_Produit.h"
#import "Produit.h"
#import "ViewController.h"
#implementation WS_Produit
- (NSMutableArray *)getProduitsJSON
{
__block NSMutableArray *result;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^() {
NSLog(#"on passe en async");
NSError *error = nil;
NSData *jsonData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"the url to load"]];
NSDictionary *produits = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
if( error )
{
NSLog(#"%#", [error localizedDescription]);
}
else {
dispatch_sync(dispatch_get_main_queue(), ^(){
NSLog(#"retour en sync");
result = [[NSMutableArray alloc] init];
Produit *tmp;
NSArray *produit = produits[#"produits"];
for ( NSDictionary *property in produit )
{
tmp = [Produit new];
tmp.ref = property[#"ref"];
tmp.name = property[#"name"];
tmp.description = property[#"description"];
tmp.price = property[#"price"];
tmp.imgURL = property[#"imgURL"];
[result addObject:tmp];
NSLog(#"%#", result);
}
});
}
});
NSLog(#"sortie du block");
NSLog(#"%#", result);
return result;
}
#end
My problem is when I'm out of the dispatch_queue my result array is empty so it's useless to return it in my viewController class, what can I do ?
Because you're using dispatch_async, your results array will be returned as empty before it gets filled.
Blocks are exactly what you need. They can be used as callbacks for async methods.
In your viewController, you should pass blocks to your method
[myObject getProduitsJSON:
success:^(NSArray *results){
// Use your results here
// Reload table for example.
}
failure:^(NSError *error){
// Use your error message (show it for example)
}];
So you're method should look like this:
-(void)getProduitsJson:(void(^)(NSArray* results))success failure:(void(^)(NSError* error))failure {
{
NSMutableArray *result = [[NSMutableArray alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^() {
NSError *error = nil;
NSData *jsonData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"the url to load"]];
NSDictionary *produits = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
if(error) {
failure(error);
}else{
// Fill your array
success(result);
}
}
}
Related
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 have an app that has 2 views (table view and details view). I am retrieving data from MySql via PHP file using, the data load in the table fast. I do not know how to update the table! Lets say one of the users update his name in details view, as soon as he goes back to the table view it should changed.
Her is the code:
-(void)retrieveVideos {
NSString *myUrl = [NSString stringWithFormat:#"http://MyWebSite.com/phpfiles/data.php"];
NSURL *blogURL = [NSURL URLWithString:myUrl];
NSData *jsonData = [NSData dataWithContentsOfURL:blogURL];
NSError *error = nil;
NSDictionary *dataDictionary = [NSJSONSerialization
JSONObjectWithData:jsonData options:0 error:&error];
for (NSDictionary *bpDictionary in dataDictionary) {
ListOfObjects *list = [[ListOfObjects alloc]initWithVTheIndex:[bpDictionary objectForKey:#"TheIndex"] timeLineVideoUserName:[bpDictionary objectForKey:#"timeLineVideoUserName"] timeLineVideoDetails:[bpDictionary objectForKey:#"timeLineVideoDetails"] timeLineVideoDate:[bpDictionary objectForKey:#"timeLineVideoDate"] timeLineVideoTime:[bpDictionary objectForKey:#"timeLineVideoTime"] timeLineVideoLink:[bpDictionary objectForKey:#"timeLineVideoLink"] timeLineVideoLikes:[bpDictionary objectForKey:#"timeLineVideoLikes"] videoImage:[bpDictionary objectForKey:#"videoImage"] timeDeviceToken:[bpDictionary objectForKey:#"deviceToken"]];
[self.objectHolderArray addObject:list];
dispatch_async(dispatch_get_main_queue(), ^{
[spinner stopAnimating];
[UIApplication sharedApplication].networkActivityIndicatorVisible = FALSE;
});
}
if(jsonData != nil)
{
NSError *error = nil;
id result = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
if (error == nil)
NSLog(#"%#", result);
}
}
My question is how could I update the table with the new update?
Reload the data of tableview inside dispatch :
dispatch_async(dispatch_get_main_queue(), ^{
[spinner stopAnimating];
[UIApplication sharedApplication].networkActivityIndicatorVisible = FALSE;
[self.tableView reloadData];
});
you should notify about the update ,with Delegate or KVO (notification)
after notify about update you should update your data source ( self.objectHolderArray ) with new data, finally you must call :
[self.tableView reloadData];
or
[self.tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
Make sure that dataSource and delegate methods is set for tableview.
self.tableView.dataSource = self;
self.tableView.delegate = self;
To update UItable you can call tableview's reloadData method.
ex: [self.tableView reloadData];
im trying to show on a map two json files simulteniously. But there is the problem it gives me weird errors which I can't figure it out. So originaly there was
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray * annotations = [[NSMutableArray alloc] init];
self.mapView.visibleMapRect = MKMapRectMake(135888858.533591, 92250098.902419, 190858.927912, 145995.678292);
NSLog(#"Loading data…");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSData * JSONData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:self.seedFileName ofType:#"json"]];
for (NSDictionary * annotationDictionary in [NSJSONSerialization JSONObjectWithData:JSONData options:kNilOptions error:NULL])
{
ADClusterableAnnotation * annotation = [[ADClusterableAnnotation alloc] initWithDictionary:annotationDictionary];
[annotations addObject:annotation];
[annotation release];
}
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Building KD-Tree…");
[self.mapView setAnnotations:annotations];
});
});
[annotations release];
}
so i saw that i have two ViewControllers which holds the the seedfile
this one is
#import "CDStreetlightsMapViewController.h"
#implementation CDStreetlightsMapViewController
- (NSString *)pictoName {
return #"CDStreetlight.png";
}
- (NSString *)clusterPictoName {
return #"CDStreetlightCluster.png";
}
- (NSString *)seedFileName {
return #"CDStreetlights";
}
- (NSString *)seedFileName1 {
return #"CDToilets";
}
#end
the other one is
#import "CDToiletsMapViewController.h"
#implementation CDToiletsMapViewController
- (NSString *)seedFileName {
return #"CDToilets";
}
- (NSString *)pictoName {
return #"CDToilet.png";
}
- (NSString *)clusterPictoName {
return #"CDToiletCluster.png";
}
#end
The json files are named CDToilets and CDStreetlights... but i have a tab bar which holds Toilets and streetlights. But lets say i would like to display on the toilets viewController the streetlights and the toilets? thats my problem right know.. I tried this
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray * annotations = [[NSMutableArray alloc] init];
self.mapView.visibleMapRect = MKMapRectMake(135888858.533591, 92250098.902419, 190858.927912, 145995.678292);
NSLog(#"Loading data…");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSData * JSONData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:self.seedFileName ofType:#"json"]];
for (NSDictionary * annotationDictionary in [NSJSONSerialization JSONObjectWithData:JSONData options:kNilOptions error:NULL])
{
ADClusterableAnnotation * annotation = [[ADClusterableAnnotation alloc] initWithDictionary:annotationDictionary];
[annotations addObject:annotation];
[annotation release];
}
NSData * JSONData1 = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:self.seedFileName1 ofType:#"json"]];
for (NSDictionary * annotationDictionary in [NSJSONSerialization JSONObjectWithData:JSONData1 options:kNilOptions error:NULL])
{
ADClusterableAnnotation * annotation = [[ADClusterableAnnotation alloc] initWithDictionary:annotationDictionary];
[annotations addObject:annotation];
[annotation release];
}
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Building KD-Tree…");
[self.mapView setAnnotations:annotations];
});
});
[annotations release];
}
i renamed in the CDStreetlightsMapViewController the seedfile as seedfile1 so i can use it two times in viewDidLoad it didn't show errors but it didn't run well on simulator and I get an exception:
ClusterDemo[11014:c07]Loading data…
ClusterDemo[11014:1303]***Assertion failure in -[CDToiletsMapViewController seedFileName1], ADClusterMapView-master-7/ClusterDemo/Classes/CDMapViewController.m:86 2013-11-25 23:59:37.524
ClusterDemo[11014:1303]***Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'This abstract method must be overridden!' *** First throw call stack: (0x18b2012 0x1277e7e 0x18b1e78 0xd0df35 0x3fad 0x36cb 0x2deb53f 0x2dfd014 0x2dee2e8 0x2dee450 0x99843e72 0x9982bdaa) libc++abi.dylib: terminate called throwing an exception (lldb)
you can download the full app here... https://github.com/applidium/ADClusterMapView
If you read the exception it's quite clear that you're using an abstract method that contains an assertion to ensure that you know you've made a mistake. You need to implement the seedFileName1 method in CDToiletsMapViewController (just like you did in CDStreetlightsMapViewController).
From the code I guess you need to add:
- (NSString *)seedFileName1 {
return #"CDStreetlights";
}
What I am trying to do is a Facebook wrapper for the Facebook iOS SDK. Basically the idea is that my ViewController should do nothing but showing ex. my friends that will be acquired with a simple call like
self.friends = [FacebookWrapper myFriends];
[self.tableView reloadData];
My wrapper myFriends method should look like this
+ (NSArray *)myFriends
{
__block NSArray *friends = nil;
[FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
if(FB_ISSESSIONOPENWITHSTATE(status)) {
[FBRequestConnection startForMyFriendsWithCompletionHandler:^(FBRequestConnection *connection, id data, NSError *error) {
CFRunLoopStop(CFRunLoopGetCurrent());
if(error) {
return;
}
NSArray *friendsData = (NSArray *)[data data];
NSMutableArray *fbFriends = [NSMutableArray array];
for(id friendData in friendsData) {
Friend *friend = [Friend friendWithDictionary:friendData];
fbFriends addObject:friend];
}
friends = [NSArray arrayWithArray:fbFriends];
}];
CFRunLoopRun();
}
}];
return friends;
}
The issue is that the openActiveSessionWithReadPermissions and startForMyFriendsWithCompletionHandler are asynchronous blocks so the method returns before the blocks complete their task.
Any help would be much appreciated.
I created a similar wrapper in the past and my approach was passing a "completion block" when calling my wrapper method; this completion block is then triggered once all the asynchronous calls are done running, and it receives whatever data your method would return in a synchronous scenario (in your case, the array of friends).
To illustrate - you could have your "myFriends" method redefined as:
+ (void)myFriendsWithCompletionBlock:(void (^)(NSArray *friends))completionBlock;
Then in the implementation, right after the friends = [NSArray arrayWithArray:fbFriends]; line, you would add this:
if (completionBlock != nil) {
completionBlock(friends);
}
... and remove the return statement at the end.
Finally, on your view controller (or any object using the method, you would do something like this:
[FacebookWrapper myFriendsWithCompletionBlock:^(NSArray *friends){
// do what you need to do with the friends array
}];
Of course, this is still asynchronous - but there's no way around since that's how the Facebook SDK was build (and, to be fair, this is probably the best way to do it - waiting for requests to finish synchronous would be terrible!)
Edit: I noticed you're also returning from the wrapper method in case it fails; in that situation, instead of returning you would do something like this:
if (completionBlock != nil) {
completionBlock(nil);
}
That would cause the friends array to be nil when your completion block is called - you can then treat that error there however seems appropriate to you.
Hope this helped!
If you are dispatching an asynchronouos block, you can communicate with your UIViewController subclass by calling back to it:
[self someSelectorWithCallbackData:stuffWhichYouWantToGiveBack];
This will call self to get captured by the block, and so will work as expected. From the relevant method you can refresh the view / reload the tableview / dance a jig as required.
Depending on the context, you may need to __block scope self, eg
__block UIViewController *bsself = self;
But if you do the latter, be careful to avoid a retain loop (the build and analysis tools are fairly good at pointing this out).
Think you need to use a protol
#class Webservice;
#protocol WebserviceDelegate
#optional
-(void)webservice:(Webservice *)webservice didFetchPosts:(NSArray *)posts;
-(void)webservice:(Webservice *)webservice didFetchComments:(NSArray *)comments forPostID:(NSString *)postID launchComments:(BOOL)launch;
-(void)webservice:(Webservice *)webservice didLoginWithUser:(User *)user;
-(void)webservice:(Webservice *)webservice didVoteWithSuccess:(BOOL)success forObject:(id)object direction:(BOOL)up;
#end
#interface Webservice : NSObject {
__weak id <WebserviceDelegate> delegate;
}
//Delegate
#property (weak) id <WebserviceDelegate> delegate;
-(void)getHomepage {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSURLResponse *response;
NSError *error;
// Create the URL Request
NSMutableURLRequest *request = [Webservice NewGetRequestForURL:[NSURL URLWithString:#"https://www.hnsearch.com/bigrss"]];
// Start the request
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
//Handle response
//Callback to main thread
if (responseData) {
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSStringEncodingConversionAllowLossy];
if (responseString.length > 0) {
dispatch_async(dispatch_get_main_queue(), ^{
[self parseIDsAndGrabPosts:responseString];
});
}
else {
dispatch_async(dispatch_get_main_queue(), ^{
[delegate webservice:self didFetchPosts:nil];
});
}
}
else {
dispatch_async(dispatch_get_main_queue(), ^{
[delegate webservice:self didFetchPosts:nil];
});
}
});
}
-(void)parseIDsAndGrabPosts:(NSString *)parseString {
// Parse String and grab IDs
NSMutableArray *items = [#[] mutableCopy];
NSArray *itemIDs = [parseString componentsSeparatedByString:#"<hnsearch_id>"];
for (int xx = 1; xx < itemIDs.count; xx++) {
NSString *idSubString = itemIDs[xx];
[items addObject:[idSubString substringWithRange:NSMakeRange(0, 13)]];
}
// Send IDs back to HNSearch for Posts
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSURLResponse *response;
NSError *error;
// Create Request String
NSString *requestString = #"http://api.thriftdb.com/api.hnsearch.com/items/_bulk/get_multi?ids=";
for (NSString *item in items) {
requestString = [requestString stringByAppendingString:[NSString stringWithFormat:#"%#,", item]];
}
// Create the URL Request
NSMutableURLRequest *request = [Webservice NewGetRequestForURL:[NSURL URLWithString:requestString]];
// Start the request
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
//Handle response
//Callback to main thread
if (responseData) {
NSArray *responseArray = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:&error];
if (responseArray) {
NSMutableArray *postArray = [#[] mutableCopy];
for (NSDictionary *dict in responseArray) {
[postArray addObject:[Post postFromDictionary:dict]];
}
NSArray *orderedPostArray = [self orderPosts:postArray byItemIDs:items];
dispatch_async(dispatch_get_main_queue(), ^{
[delegate webservice:self didFetchPosts:orderedPostArray];
// Update Karma for User
if ([HNSingleton sharedHNSingleton].User) {
[self reloadUserFromURLString:[NSString stringWithFormat:#"https://news.ycombinator.com/user?id=%#", [HNSingleton sharedHNSingleton].User.Username]];
}
});
}
else {
dispatch_async(dispatch_get_main_queue(), ^{
[delegate webservice:self didFetchPosts:nil];
});
}
}
else {
dispatch_async(dispatch_get_main_queue(), ^{
[delegate webservice:self didFetchPosts:nil];
});
}
});
}
I am trying to pass data to labels from my JSON file onto a simple ViewController but I don't know where to actually pass that data. Would I be able to just add to my setDataToJson method or would I add the data in my viewDidLoad method?
here is my code
#interface NSDictionary(JSONCategories)
+(NSDictionary*)dictionaryWithContentsOfJSONString:(NSString*)fileLocation;
#end
#implementation NSDictionary(JSONCategories)
+(NSDictionary*)dictionaryWithContentsOfJSONString:(NSString*)fileLocation{
NSData* data = [NSData dataWithContentsOfFile:fileLocation];
__autoreleasing NSError* error = nil;
id result = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions error:&error];
if (error != nil) return nil;
return result;
}
#end
#implementation ViewController
#synthesize name;
- (void)viewDidLoad
{
[super viewDidLoad];
}
-(void)setDataToJson{
NSDictionary *infomation = [NSDictionary dictionaryWithContentsOfJSONString:#"Test.json"];
name.text = [infomation objectForKey:#"AnimalName"];//does not pass data
}
The problem is the way you're trying to retrieve your file. In order to do it right, you should find first its path in the bundle. Try something like this:
+(NSDictionary*)dictionaryWithContentsOfJSONString:(NSString*)fileLocation{
NSString *filePath = [[NSBundle mainBundle] pathForResource:[fileLocation stringByDeletingPathExtension] ofType:[fileLocation pathExtension]];
NSData* data = [NSData dataWithContentsOfFile:filePath];
__autoreleasing NSError* error = nil;
id result = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions error:&error];
// Be careful here. You add this as a category to NSDictionary
// but you get an id back, which means that result
// might be an NSArray as well!
if (error != nil) return nil;
return result;
}
After doing that and once your view is loaded, you should be able to set your labels by retrieving the json like this:
-(void)setDataToJson{
NSDictionary *infomation = [NSDictionary dictionaryWithContentsOfJSONString:#"Test.json"];
self.name.text = [infomation objectForKey:#"AnimalName"];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self setDataToJson];
}
It should be valueForKey instead.
Example:
name.text = [infomation valueForKey:#"AnimalName"];