I am using AFNetworking to obtain JSON from a URL, the JSON is parsed and is supposed to be converted into an NSData format which is then in turn put into an array. However it doesn't seem to be working. I think i'm being stupid because it worked previously but now-
-(void)loadFromServer{
NSString *trendsURL = [NSString stringWithFormat:#"http://myurl.com/data.json"];
NSURL *url = [NSURL URLWithString:trendsURL];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation
JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id json) {
self.results = [json valueForKeyPath:#"data"];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
}];
[operation start];
NSError *anError = nil;
NSArray *parsedElements = [NSJSONSerialization JSONObjectWithData:elementsData
options:NSJSONReadingAllowFragments
error:&anError];
for (NSDictionary *aModuleDict in parsedElements){
MosData *aMosModule = [[MosData alloc] initWithDictionary:aModuleDict];
[elements addObject:aMosModule];
}
}
The data is displayed in a collection like view separately, there is no problem with this separate view as it works when I access data from a file rather than server.
-(void)loadFromDisk{
NSString *pathString = [[NSBundle mainBundle] pathForResource:#"data" ofType:#"json"];
NSData *elementsData = [NSData dataWithContentsOfFile:pathString];
NSError *anError = nil;
NSArray *parsedElements = [NSJSONSerialization JSONObjectWithData:elementsData
options:NSJSONReadingAllowFragments
error:&anError];
for (NSDictionary *aModuleDict in parsedElements){
MosData *aMosModule = [[MosData alloc] initWithDictionary:aModuleDict];
[elements addObject:aMosModule];
}
}
The JSON that is fetched is like so:
{
"imageLink": "http://link.com/image.jpg",
"size": 1,
"title": "Food"
}
I gave it another go, and still it's not working. results is a declared NSArray.
-(void)loadFromServer{
NSString *trendsURL = [NSString stringWithFormat:#"http://url.com/data.json"];
NSURL *url = [NSURL URLWithString:trendsURL];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation
JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id json) {
NSLog(#"Custom Mosaic: %#", json);
self.results = [json valueForKeyPath:#"data"];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
}];
[operation start];
for (NSDictionary *aModuleDict in self.results){
MosData *aMosModule = [[MosData alloc] initWithDictionary:aModuleDict];
[elements addObject:aMosModule];
}
}
I think the issue might actually be this having played around a little, for some reason, it won't pick up the results of the data parsed in the AFNetworking operation.
-(id)init{
self = [super init];
if (self){
elements = [[NSMutableArray alloc] init];
[self loadFromServer];
}
return self;
}
// WWDC 2012 proposed method
+ (CustomMosDatasource *)sharedInstance {
static CustomMosDatasource *sharedInstance;
if (sharedInstance == nil)
sharedInstance = [CustomMosDatasource new];
return sharedInstance;
}
#pragma mark - MosViewDatasourceProtocol
-(NSArray *)mosElements{
NSArray *retVal = elements;
return retVal;
}
The results of the log is just JSON:
Custom Mosaic: {
data = (
{
imageFilename = "http://distilleryimage6.instagram.com/9969123a6af311e2b6c722000a9d0edd_7.jpg";
size = 1;
title = "Title";
},
AFJSONRequestOperation *operation = [AFJSONRequestOperation
JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id json) {
self.results = [json valueForKeyPath:#"data"];
NSError *anError = nil;
NSArray *parsedElements = [NSJSONSerialization JSONObjectWithData:elementsData
options:NSJSONReadingAllowFragments
error:&anError];
for (NSDictionary *aModuleDict in parsedElements){
MosData *aMosModule = [[MosData alloc] initWithDictionary:aModuleDict];
[elements addObject:aMosModule];
}
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
}];
[operation start];
Your json don't seem to have keyPath "data", remove the valueForKeyPath:#"data", please paste the result of "NSLog(#"Custom Mosaic: %#", json)" in your question.
The operation is asynchronized. The success block is called after the request returns data. Please put code in the success block like this
-(void)loadFromServer{
NSString *trendsURL = [NSString stringWithFormat:#"http://url.com/data.json"];
NSURL *url = [NSURL URLWithString:trendsURL];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation
JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id json) {
NSLog(#"Custom Mosaic: %#", json);
// your json doesn't have keyPath "data"
self.results = json;
// Codes moved into success block
for (NSDictionary *aModuleDict in self.results){
MosData *aMosModule = [[MosData alloc] initWithDictionary:aModuleDict];
[elements addObject:aMosModule];
}
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
}];
[operation start];
}
Related
I'm trying to understand how to use and have back the right value from the dropbox longpool_delta api call. I successfully retrieve the cursor value but always get the 400 code as response. Can anyone help me to fix it or help me to understand where i'm wrong?
For quickly test i've setup the request with AFNetworking.
Below the sample code.
Thanks
NSString *myUrl = #"https://api.dropbox.com/1/delta/";
NSURL *url = [NSURL URLWithString:myUrl];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//here set the header with access token with oAuth2 api
[request setValue: [self headerForApiCall] forHTTPHeaderField:#"Authorization"];
request.timeoutInterval = 90.0;
[request setHTTPMethod:#"POST"];
__weak typeof(self) weakSelf = self;
AFJSONRequestOperation * operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSString* cursor = JSON[#"cursor"];
NSString *myUrl = [NSString stringWithFormat:#"https://api-notify.dropbox.com/1/longpoll_delta/?cursor=%#",cursor];
NSURL *url = [NSURL URLWithString:myUrl];
NSMutableURLRequest *request2 = [NSMutableURLRequest requestWithURL:url];
request2.timeoutInterval = 90.0;
[request2 setHTTPMethod:#"GET"];
AFJSONRequestOperation * operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request2 success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"long %#",JSON);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"failure long %#",response.description);
}];
[operation start];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"failure %#",response.description);
}];
[operation start];
[edit]
As suggested here the response code 400 from the failure block
status code: 400, headers {
"Cache-Control" = "no-cache";
Connection = "keep-alive";
"Content-Type" = "text/plain";
Date = "Wed, 14 May 2014 16:04:28 GMT";
Pragma = "no-cache";
Server = nginx;
"Transfer-Encoding" = Identity;
"X-DB-Timeout" = 120;
}
removing / the response always from the failure block but with a (null) value
Error 400 is from bad parameters, I think your problem is here :
NSString *myUrl = [NSString stringWithFormat:#"https://api-notify.dropbox.com/1/longpoll_delta/?cursor=%#",cursor];
Try to remove the / between longpoll_delta and ? as follow :
NSString *myUrl = [NSString stringWithFormat:#"https://api-notify.dropbox.com/1/longpoll_delta?cursor=%#",cursor];
By the way should create a Dropbox HTTP client which will help you a lot to manage your request. Create a class which inherits from AFHTTPClient. your create a singleton as follow :
+ (DBAPIClient *)sharedClientWithBaseUrl:(NSString *)baseUrl {
static DBAPIClient *sharedInstance = nil;
static dispatch_once_t apiToken;
dispatch_once(&apiToken, ^{
sharedInstance = [[DBAPIClient alloc] initWithBaseURL:[NSURL URLWithString:#"https://api.dropbox.com/1/"]];
// Do any other initialisation stuff here
});
return sharedInstance;
}
- (id)initWithBaseURL:(NSURL *)url {
self = [super initWithBaseURL:url];
if (!self) {
return nil;
}
return self;
}
In this way you'll be able to use like this which is much more simple :
NSDictionary *params = // Your params;
[[DBPIClient sharedClient]
getPath://the endpoint you want access to
parameters:params
success:^(AFHTTPRequestOperation *operation, id JSON) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
I'm trying to parse some text from a JSON-file on my server. There's three different values I'm parsing from the file: "value1":"some_value", "value2":"some_value", "value3":"some_value".
I'm declaring a NSMutableArray called statsHome which I initializing in the viewDidLoad method, like this: statsHome = [[NSMutableArray alloc] init];
The problem is that after I have initialized the array, I need to set up a NSDictionary. And if i would do this in the table view, I would write:
NSDictionary *stats = [self.statshome objectAtIndex:indexPath.row];
But I'm not parsing these values to the table view. I want to parse them to UILabels. So what I tried was to declare new NSUInteger. Because I can't use indexPath.row in the viewDidLoad method. I called it statsIndex.
But when I launch the app it crashes and gives me this error message: Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
The rest of the code looks like this:
#interface DEMOHomeViewController () {
NSUInteger statsIndex;
}
#end
#implementation DEMOHomeViewController
#synthesize statsHome;
#synthesize twitterFollowers;
#synthesize facebookLikes;
#synthesize instagramFollowers;
- (void)viewDidLoad
{
[super viewDidLoad];
statsHome = [[NSMutableArray alloc] init];
NSDictionary *stats = [self.statsHome objectAtIndex:statsIndex];
value1.text = [stats objectForKey:#"value1"];
value2.text = [stats objectForKey:#"value2"];
value3.text = [stats objectForKey:#"value3"];
NSURL *url1 = [[NSURL alloc] initWithString:#"the-json-file-with-the-values.php/file.json"];
NSURLRequest *request1 = [[NSURLRequest alloc] initWithURL:url1];
AFJSONRequestOperation *operation1 = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
self.statsHome = [[NSArray alloc] initWithArray:JSON];
[self.activityIndicatorView stopAnimating];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
[operation1 start];
}
#end
Error is correct: you are trying to get data from an array before data is set. You should do something like in code below.
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *url1 = [[NSURL alloc] initWithString:#"the-json-file-with-the-values.php/file.json"];
NSURLRequest *request1 = [[NSURLRequest alloc] initWithURL:url1];
AFJSONRequestOperation *operation1 = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
[self.activityIndicatorView stopAnimating];
[self updateDataWithJSON:JSON]; // <- Here we will update our data
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
[operation1 start];
}
- (void)updateDataWithJSON:(id)JSON
{
self.statsHome = [[NSArray alloc] initWithArray:JSON];
NSDictionary *stats = [self.statsHome objectAtIndex:statsIndex];
value1.text = [stats objectForKey:#"value1"];
value2.text = [stats objectForKey:#"value2"];
value3.text = [stats objectForKey:#"value3"];
}
Let me give you an advice. Seems like your statsIndex initialised in other part of your app. In this case it's better to check if statsIndex is suitable for array length every time you access this array. Otherwise it could be a reason of app crash in some cases: For example you got your array in other controller and it has 10 elements. You select last element but reload a request in your viewDidLoad of DEMOHomeViewController. And in this time array has only 9 elements (last element was deleted already by someone else). -> Crash
NSURL *url = [NSURL URLWithString: [NSString stringWithFormat:#"url"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"GET"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
NSString *authStr = [NSString stringWithFormat:#"%#:%#", #"usernmae", #"password"];
NSData *authData = [authStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *authValue = [NSString stringWithFormat:#"Basic %#", [authData base64EncodedStringWithOptions:0]];
NSLog(#"%#",authValue);//
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
[request setURL:url];
NSLog(#"%#",url);
NSError *error;
NSHTTPURLResponse *response;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"Response code: %ld", (long)[response statusCode]);
NSLog(#"Data is %#",data);
I have run into a strange situation when creating trying to save the objects from an array to a rails backend. I have two array and I have no problem saving each one on its own. The problem is that I am also creating a table that is a combination of the two objects. So it would be best to create an action for index path 1 for both arrays, index path 2 for both arrays and so on. The arrays will always have the same amount of objects inside of them. This way, for index path one, it could save both of them and make the combination table at the same time, thus eliminating my problem. My second problem is that I have no idea how to create a block of code that executes for an index path of multiple array. I know this is probably quite weird, but any help would be great.
Here is how I was doing it for every object of a single array:
-(void)savePeroid {
[self.periodArray enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
if (self.navigationItem.rightBarButtonItem.tintColor == [UIColor redColor]) {
NSURL *url = [NSURL URLWithString:#"http://localhost:3000/"];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
object, #"period[name]",
nil];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST"
path:#"api/period"
parameters:params];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"ID: %#", [JSON valueForKeyPath:#"id"]);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failure Because %#",[error userInfo]);
}];
[operation start];
}
}];
[self saveSubject];
}
How about this:
-(void)savePeroid {
for (int i=0; i<self.periodArray.count; i++) {
id periodObject = self.periodArray[i];
id otherArrayObject = self.otherArray[i];
if (self.navigationItem.rightBarButtonItem.tintColor == [UIColor redColor]) {
NSURL *url = [NSURL URLWithString:#"http://localhost:3000/"];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
periodObject, #"period[name]",
otherArrayObject, #"other[something]",
nil];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST"
path:#"api/period"
parameters:params];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"ID: %#", [JSON valueForKeyPath:#"id"]);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failure Because %#",[error userInfo]);
}];
[operation start];
}
};
[self saveSubject];
}
I'm searching for a good tutorial for Restkit 2. Everywhere I'm seeing, they are talking about Object Mapping. Is it not possible to use Restkit and obtain a JSON as string and then use the JSON directly.
AFNetworking Does the Job,
AFNetworking can be installed using cocoapads as shown here,
A sample request using AFNetworking:
NSURL *url = [[NSURL alloc] initWithString:#"https://www.ez-point.com/search"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setValue:#"xxxxxxxxxxx" forHTTPHeaderField:#"Authorization" ];
[request setHTTPMethod:#"GET"];
NSMutableDictionary *jsonDic = [[NSMutableDictionary alloc]init];
[jsonDic setValue:#"UJO526" forKey:#"search_text" ];
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDic options:NSJSONWritingPrettyPrinted error:nil];
[request setHTTPBody:jsonData];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSArray *searchResults = JSON;
if ([searchResults count] == 1){
id result = [searchResults objectAtIndex:0];
double latitude = [[result valueForKey:#"latitude"] doubleValue];
double longitude = [[result valueForKey:#"longitude"] doubleValue];
NSString *ezPoint = [result valueForKey:#"value"];
NSString *tags = [result valueForKey:#"tags"];
[self setAnnotation:latitude ForLongitude:longitude withEZPoint:ezPoint WithTags:tags];
}
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
}
];
[operation start];
I am trying to make a POST request using AFNetworking. I went through SO and found that I need to include httpClient.parameterEncoding = AFJSONParameterEncoding
It still doesn't work even after making that change. Anything else I am missing ? Here is the code
NSDictionary *subDictionaryUsers = [[NSDictionary alloc]initWithObjectsAndKeys:myObject.name,#"name", myObject.topic_description,#"description", nil];
NSString *_restPath = [NSString stringWithFormat:#"spaces.json/auth_token=%#",myObject.auth_token];
NSDictionary *params = [[NSDictionary alloc]initWithObjectsAndKeys:subDictionaryUsers,#"space",nil];
myAppAFNClient *httpClient = [myAppAFNClient sharedClient];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST" path:_restPath parameters:params];
httpClient.parameterEncoding = AFJSONParameterEncoding;
[httpClient getJsonResponse:request notificationString:#"add.hydramixer.topics"];
myAppAFNClient.m
-(void)getJsonResponse:(NSURLRequest *)_request notificationString:(NSString *)notifString{
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:_request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
if([notifString length] != 0){
// handling success
}
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON){
// handling errors
}];
[operation start];
}