i am really new to IOS development. i want to develop an application which is dealing with some web services and display in a table view. somehow i found a 3rd party library for do the networking stuffs [AFNetworking 2]. below is my code to get the json response for any given url and parameters.
-(NSDictionary*)getWebServiceResponce:(NSString *)url :(NSDictionary *)object
{
// NSDictionary *parameters = [[NSDictionary alloc] initWithObjectsAndKeys:#"47", #"caregiverPersonId", nil];
__block NSDictionary* result=Nil;
__block NSString* person=Nil;
AFSecurityPolicy *policy = [[AFSecurityPolicy alloc] init];
[policy setAllowInvalidCertificates:YES];
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
[operationManager setSecurityPolicy:policy];
operationManager.requestSerializer = [AFJSONRequestSerializer serializer];
operationManager.responseSerializer = [AFJSONResponseSerializer serializer];
[operationManager POST:url
parameters:object
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", [responseObject description]);
person = [responseObject[#"d"]objectForKey:#"PersonId"];
// [self returnedResponce:responseObject];
result = (NSDictionary *) responseObject[#"d"];
NSLog(#"RESULT: %#", result);
NSLog(#"personm: %#", person);
[operation waitUntilFinished];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", [error description]);
//result = [error];
}
];
return result;
}
this code works perfectly.. but my point is when i put some breakpoints to check what are the values i got for several variables, it shows null. but my log shows the entire json response.
and i want to return my response object as a dictionary. because i want to do some process with the response.. can some one help me with this ?
The problem is that result is nil when it gets returned. AFNetworking uses ObjC's awesome blocks, they get executed asynchronously. Read more about it here.
You should include a callback block in your getWebServiceResponce method. I've thrown together a bit of code but you should really read more about blocks.
-(void)webServiceResponceForURL:(NSString *)url dictionary:(NSDictionary *)object success:(void (^)(NSDictionary *responseObject))success {
// NSDictionary *parameters = [[NSDictionary alloc] initWithObjectsAndKeys:#"47", #"caregiverPersonId", nil];
__block NSDictionary* result=Nil;
__block NSString* person=Nil;
AFSecurityPolicy *policy = [[AFSecurityPolicy alloc] init];
[policy setAllowInvalidCertificates:YES];
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
[operationManager setSecurityPolicy:policy];
operationManager.requestSerializer = [AFJSONRequestSerializer serializer];
operationManager.responseSerializer = [AFJSONResponseSerializer serializer];
[operationManager POST:url
parameters:object
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", [responseObject description]);
person = [responseObject[#"d"]objectForKey:#"PersonId"];
// [self returnedResponce:responseObject];
result = (NSDictionary *) responseObject[#"d"];
NSLog(#"RESULT: %#", result);
NSLog(#"personm: %#", person);
//We are executing the block as soon as we have the results.
if (success) {
success(responseObject);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", [error description]);
//result = [error];
}
];
}
Edit:
[self webServiceResponceForURL:#"foo://foo" dictionary:nil success:^(NSDictionary *responseObject) {
//your code here
}
[self webServiceResponceForURL:#"foo://foo" dictionary:nil success:^(NSDictionary *responseObject) {
//your code here
}
Here you will got complete responseObject in form NSDictionary. You can assign responseObject to instance variable. Now This instance Variable will be used at point time. in your case, it will passed on button event.
Related
I'm developing iOS application with Zendesk, I'm using REST v2 api and I have a problem with attachments to comments. Operation of sending attachments looks fine but when trying read attachment from comment I have a problem becouse file is corrupted (I'm sending image). I'm using AFNetworking library. Here is my code:
- (void)addAttachment:(NSData*)data withFileName:(NSString*)fileName {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager.requestSerializer setAuthorizationHeaderFieldWithUsername:API_USER password:API_TOKEN];
[manager.responseSerializer setAcceptableContentTypes:[NSSet setWithObject:#"text/plain"]];
[manager.requestSerializer setValue:#"image/jpeg" forHTTPHeaderField:#"Content-Type"];
NSDictionary *parameters = #{#"image":#{ #"content_type": #"image/jpeg", #"filename":fileName, #"file_data": [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]}};
[manager POST:[NSString stringWithFormat:#"%#uploads.json?filename=%#", API_URL, fileName] parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSDictionary *dictionary = responseObject;
if (dictionary != nil && [dictionary objectForKey:#"upload"] != nil) {
NSString *token = [[dictionary objectForKey:#"upload"] objectForKey:#"token"];
if ([self.delegate respondsToSelector:#selector(didFinishedAddAttachmentWithSuccess:andToken:)]) {
[self.delegate didFinishedAddAttachmentWithSuccess:YES andToken:token];
}
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"%#", error);
if ([self.delegate respondsToSelector:#selector(didFinishedAddAttachmentWithSuccess:andToken:)]) {
[self.delegate didFinishedAddAttachmentWithSuccess:NO andToken:nil];
}
}];
}
Any suggestions?
I resolved this issue by using Zendesk Mobile SDK:
ZDKUploadProvider *uploadProvider = [[ZDKUploadProvider alloc] init];
[uploadProvider uploadAttachment:data withFilename:fileName andContentType:#"image/jpg" callback:^(ZDKUploadResponse *uploadResponse, NSError *error) {
if (uploadResponse != nil && [self.delegate respondsToSelector:#selector(didFinishedAddAttachmentWithSuccess:andToken:)]) {
[self.delegate didFinishedAddAttachmentWithSuccess:YES andToken:uploadResponse.uploadToken];
}
else {
if ([self.delegate respondsToSelector:#selector(didFinishedAddAttachmentWithSuccess:andToken:)]) {
[self.delegate didFinishedAddAttachmentWithSuccess:NO andToken:nil];
}
}
}];
I am passing the URL in this method and getting the data as output. i want to assign a new value to nsmutabledictionary but it is not assigning the value.
-(NSDictionary*) getDatafromURL: (NSString*)url{
__block NSMutableDictionary *returnData=[[NSMutableDictionary alloc] init];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
returnData=(NSMutableDictionary*)responseObject;
NSLog(#"Data 1: %#",returnData);// it is printing the data
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
NSLog(#"Data 2: %#",returnData);// it is not printing any data
return returnData;
}
in this above example the Data 1 is showing value successfully
Data 2 gives me empty dictionary.why it is not assigning the new value?
That happens because you get to the line with "Data 2" first and the block is executed only afterwards, since it is an async request. I would suggest that you change your method to something like:
- (void)getDataFromURL:(NSString *)url completionHandler:(void (^)(NSMutableDictionary *returnData, NSError *error))handler {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
returnData=(NSMutableDictionary*)responseObject;
NSLog(#"Data 1: %#",returnData);// it is printing the data
handler(returnData, nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
handler(nil, error);
}];
}
There might be some compile errors in the code I provided.
The other solution would be to do a synchronous request, in which case the block would be executed before the code that is after the block.
EDIT:
If you are choosing the first solution, you have to continue using it asynchronously. So you would call it like:
[self getDataFromURL:#"abc.com" completionHandler:^ (NSMutableDictionary *returnData, NSError *error) {
// process your dictionary and the error object
}];
Please check whether your Data 2 is printing before data 1? If yes, its because, the response object gets downloaded only after a certain delay. Take away the return statements. Pass the data to the dictionary to which you return the method. For eg: like
instead of
self.myDictionary = [self getDatafromURL:someURl];
to
-(void) getDatafromURL: (NSString*)url{
__block NSMutableDictionary *returnData=[[NSMutableDictionary alloc] init];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
returnData=(NSMutableDictionary*)responseObject;
NSLog(#"Data 1: %#",returnData);// it is printing the data
self.myDictionary = returnData;
// Continue whatever you want to do
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
Or use the dispatch methods instead of the blocks.
like
Or use manager waitUntilFinish method below.
This is what my server API document shows me to return a successful request.
curl -X PUT -d {"questions":[{"type":"control_head"}]} "https://api.request.com/forms"
{"questions":[{"type":"control_head"}]} this is the parameter.
https://api.request.com/forms this is the URL.
How can I handle this properly handle this using AFNetWorking? This is what I've got so far.
NSString *urlStr = [NSString stringWithFormat:#"https://api.request.com/forms"];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager PUT:urlStr parameters:parameter success:^(AFHTTPRequestOperation *operation, id responseObject) {
[operation setUserInfo:userinfo];
SBJsonParser *jsonparser = [SBJsonParser new];
id result = [jsonparser objectWithString:[operation responseString]];
if ( self.delegate != nil && [self.delegate respondsToSelector:finishSelector] ) {
[self.delegate performSelector:finishSelector withObject:result];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[operation setUserInfo:userinfo];
if ( self.delegate != nil && [self.delegate respondsToSelector:failSelector] ) {
[self.delegate performSelector:failSelector withObject:[operation error]];
}
}];
I am not sure how to handle parameter correctly.
You can construct an NSDictionary equivalent of your parameters with:
NSDictionary *parameters = #{#"questions": #[#{#"type": #"control_head"}]};
Just pass that into PUT, and it should work as expected.
i have a request which returns information from a php web service. I'm having trouble adding this to a array which can be used in my UICollectionView. It seems like whatever i do i cant return the data. I think it is because i'm returning the array before i've added any objects. I've tried placing the NSLog several places, but without luck. What am i doing wrong?
When i place this NSLog(#"%d", imagesArray.count); beyond the request it returns 0.
ViewDidAppear:
-(void)viewDidAppear:(BOOL)animated {
imagesArray = [[NSMutableArray alloc] init];
[self getImages];
}
getImages method:
-(void)getImages {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager GET:#"http://URL.COM" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseObject options:kNilOptions error:nil];
NSString *theTitle = [[json objectForKey:#"response"] valueForKey:#"title"];
NSString *theUrl = [[json objectForKey:#"response"] valueForKey:#"imageUrl"];
[imagesArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:
theTitle, #"title",
theUrl, #"url",
nil]];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
NSLog(#"%d", imagesArray.count);
}
AFNetworking is Asynchronous, you have to place the log inside the success block. Otherwise the array will always be empty.
One good solution would be to pass a block to your getImages function like that
-(void) getImages:(void (^)(BOOL result))callback {
// your code here then you call callback(YES or NO) inside your success or failure block.
}
[self getImages:^(BOOL result){
if(result)
//we got the images, we can now display them etc.
}];
I am using AFNetworking 2.0 and have run into a problem.
I am trying to PUT an array in json to the server.
I am posting the Array like (See Code Below). I am adding the following array to the Json params to send to the server:
themes = (
"Fashion - Men",
Kids,
"Styling / Hair"
);
and this gets send to the server:
{
id = 654;
tags = test;
themes = (
"Fashion - Men",
Kids,
"Styling / Hair"
);
}
However the server receives the json like so WHICH IS WRONG:
{'id': '654', 'themes[]': ['Kids', 'Styling / Hair', 'Accessories - Women'], 'tags': 'test'}
AFNetworking is putting [] square brackets by themes in the sent json like themes[] so the cal is right except for this:themes[]
Have no idea how to fix this.
- (void) piccMedia: (NSString*) aPiccId Tags: (NSString *) aTags Themes: (NSMutableArray *) anThemes
success:(void (^)(NSArray *response))success
failure:(void (^)(NSError *error))failure
{
NSMutableDictionary * params = [[NSMutableDictionary alloc] init];
[params setObject: #"654" forKey:#"id"];
[params setObject: aTags forKey:#"tags"];
[params setObject: anThemes forKey:#"themes"];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *piccingAuthToken = [prefs stringForKey:#"piccingAuthToken"];
NSString *piccingUsername = [prefs stringForKey:#"piccingUsername"];
NSLog(#"piccingAuthToken %# %#", piccingAuthToken,piccingUsername);
NSString *postQueryString = [NSString stringWithFormat:#"http://dev.com/services/rest/profiles/%#/media",piccingUsername];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [JSONResponseSerializerWithData serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:#"application/json", #"text/json", #"text/javascript", #"text/plain", #"text/html", nil];
manager.responseSerializer = [JSONResponseSerializerWithData serializerWithReadingOptions:NSJSONReadingAllowFragments | NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves];
[manager.requestSerializer setValue:piccingAuthToken forHTTPHeaderField:#"x-authtoken"];
[manager PUT:postQueryString parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
success(responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
id json = error.userInfo [JSONResponseSerializerWithDataKey];
failure(json);
}];
}
2014-02-24 16:49:25.265 App[7314:70b] JSON Parameters{
id = 654;
tags = test;
themes = (
"Accessories - Women",
"Styling / Hair",
Kids
);
}
You should set requestSerializer to AFJSONRequestSerializer
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager setRequestSerializer:[AFJSONRequestSerializer serializer]];
[manager POST:#"http://example.com/resources.json" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];