I'm trying to create an NSDictionary that looks like it has duplicate keys, but the values are different.
The reason for this is due tot he web service that I am sending that data it - it accepts a multi-form post message and needs values like this:
SomeKey: value1
SomeKey: value2
SomeKey value 3
And not like this:
SomeKey: value1, value2, value 3...
I have the values in an NSArray - however I am not sure how to get them into an NSDictionary that looks like the above - maybe some sort of object?
Edit
So, here is how I make a web service request to our main server.
Networking Library: AFNetworking 2.0
From viewControllerA
This code runs after a previous web service request has been made:
NSDictionary *results = [[BBDataStore sharedDataStore]fetchuserIdResult];
BBSeller *seller = [[BBSeller alloc]init];
seller.alias = results[#"userAlias"];
seller.userId = results[#"userid"];
[self.sellerListIds addObject:seller.userId];
[self.sellerListAliases addObject:seller];
This splits the data into two arrays:
self.sellerListIds
Is for the userId which I am really interested in. Its just a NSString
self.sellerListAliases
Is just to display the username on screen to the user - nothing more, really. The web service I need to send this data to, only looks at userIds.
Right - then I call a method
[self setupSearchParameters:seller.userId];
Which looks like this:
-(void)setupSearchParameters: (NSString *)userId
{
self.sellerListidString = userId;
[self.parameters setObject:self.sellerListidString forKey:self.typeOfSellerSearch];
}
This allows one userId for the key: self.typeOfSellerSearch
Now, when the user presses confirm button to execute the web service search it calls a method in my data start with the self.parameters dictionary and adds other values to an existing dictionary - which include other search keywords.
Finally, it calls the network request method - which looks like this:
-(void)fetch:(NSDictionary *)urlParameters
{
if (!self.webService.isBusy){
BBWebService *webService = [[BBWebService alloc]initWithURL:self.url RequestType:GET_REQUEST UrlParameters:urlParameters];
self.webService = webService;
self.webService.webServiceId = wsID;
[self.webService setDelegate:self];
}
}
That calls this method:
-(instancetype)initWithURL:(NSString *)url RequestType:(NSString *)requestType UrlParameters:(NSDictionary *)urlParameters
{
[self getSessionManager];
if ([requestType isEqualToString:#"GET"]){
self.isBusy = YES;
[self.manager GET:url parameters:urlParameters
success:^(NSURLSessionDataTask *task, id responseObject){
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
int statusCode = (int)response.statusCode;
[self requestDone:responseObject StatusCode:statusCode];
}failure:^(NSURLSessionDataTask *task, NSError *error){
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
int statusCode = (int)response.statusCode;
[self requestFailed:error StatusCode:statusCode];
}];
return self;
}
From there AFNetworking 2.0 takes care of constructing the parameters into the URL and makes the request. When it comes back successful, I take the data and parse it.
Right now -this works. However, I need it to work with more than one key / value pair.
If I try #Selvin's code the web service doesn't work correctly. I spoke with the Java Develeopers and they say the web service expects this:
Key / value 1
Key / Value 2
Key / Value 3
.....
it won't work with this:
key / value1, value2, value 3///
Nor does it seem to work with this:
key2 / some random value -> key / value1
As it does't know what key2 is so it ignores it.
NSArray *paramsArray = #[#{#"SomeKey": #"value1"},
#{#"SomeKey": #"value2"},
#{#"SomeKey": #"value3"},
#{#"OtherKey": #"value4"}];
[paramsArray enumerateObjectsUsingBlock:^(NSDictionary *paramDict, NSUInteger idx, BOOL *stop){
[paramDict enumerateKeysAndObjectsUsingBlock:^(NSString *key,NSString *value, BOOL *stop){
//apply the key and value on the HTTP request
}];
}];
The framework you are using accepts the NSDictionary format. You need to edit the framework to suit your needs.
Edit
You need to edit the AFNetworking code where it applies the parameters. Your initWithURL method takes urlParameters as NSDictionary. But according to my answer you need to pass NSArray with collection of NSDIctionary elements.
What needs to be done inorder to get this work is, in AFNetworking code the urlParameters has to be checked and handled. if urlParameters is NSDictionary then let the code behave as it is. If its NSArray then you need to do the "Applying HTTP parameters" yourself.
Can you make it in such a way that the NSDictionary is inside the array?
For example:
[
{SomeKey:value1},
{SomeKey:value2},
{SomeKey:value3}
]
Related
Here is what it looks like in the Mainviewcontroller.
I have two separate classes, LinkedInUser and _User. The accessToken is stored in the LinkedInUser not in the _User. There is a pointer in the LinkedInUser class called "user" which points to the "objectID" in _User. I want to retrieve the accessToken from LinkedInUser but overtime I try a query it returns no results and when I run the code below, it results in a null. What am I doing wrong and how can I fix it?
[PFLinkedInUtils logInWithBlock:^(PFUser *user, NSError *error) {
NSLog(#"User: %#, Error: %#", user, error);
PFObject *linkedin = [PFObject objectWithClassName:#"LinkedInUser"];
NSString *accessToken = linkedin[#"accessToken"];
[PFLinkedInUtils.linkedInHttpClient GET:[NSString stringWithFormat:#"https://api.linkedin.com/v1/people/~:(blahblahblah)?oauth2_access_token=%#&format=json", accessToken] parameters:nil success:^(AFHTTPRequestOperation *operation, id result)
This line:
PFObject *linkedin = [PFObject objectWithClassName:#"LinkedInUser"];
is creating a new instance of a LinkedInUser object. It will not have a value for the accessToken property. Instead you should query Parse for the existing object associated with the user.
Additionally, if you are able to change your data model slightly, it might be better to have a pointer on _User that references the LinkedInUser. That way, you can just get that object directly without having to make another query.
i need to compare the response of my writeValue with an expected string.
Ive created a Button to send the command:
- (IBAction)pair:(id)sender {
NSString * test = #"0/PAIR/START";
NSData *data = [test dataUsingEncoding:NSUTF8StringEncoding];
[_discoveredPeripheral writeValue:data forCharacteristic: hr_characteristic type:CBCharacteristicWriteWithResponse];
NSLog(#"send");
}
My peripherals returns: 0/OK or 0/ERROR
Now i want to compare the response in the method with the string i expect. Is this possible to evaluate in the method? Do i need a timer?
Ive a big pool of commands. How should i organize this pool of commands?
//sorry for my bad english
Edit wording..
I am using a 3rd party library called Drupal-IOS-SDk to connect my Drupal website with my under development IOS app. I use a method to index nodes on my website and I am just wondering if anyone has any knowledge about how to deal with the response from my website. To give a little context if I run a similar bit of code to my index method (a getNode method) which works fine and I am able to access my response perfectly as shown below:
//code for correctly working nodeGet method
NSMutableDictionary *nodeData = [NSMutableDictionary new];
[nodeData setValue:#"650" forKey:#"nid"];
[DIOSNode nodeGet:nodeData success:^(AFHTTPRequestOperation *operation, id responseObject) {
//print out responseObject
//NSLog(#"%#", responseObject);
//pull data from the responseObject
NSInteger testNumber = [responseObject objectForKey:#"changed"];
NSLog(#"%ld", (long)testNumber);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//we failed, uh-oh lets error log this.
NSLog(#"%#, %#", [error localizedDescription], [operation responseString]);
}];
This is the what gets printed by response object(I didnt include the whole thing but youll get the point):
//printed statement for correctly working nodeGet method
{
changed = 1390534644;
comment = 0;
created = 1390534644;
data = "b:0;";
"ds_switch" = "";
"field_additional_pictures" = (
);
"field_author" = {
und =
The above code gets node data and calling the "objectforkey" method on responseObject lets me access numbers or whatever else is stored in my responseObject. Where I have commented pull data from response object I get back the integer "1390534644" which correctly corresponds to the "changed" variable as you can see from the printed response above. The above section works fine. It is the next step where I get confused:
//code for index method that is in question
NSMutableDictionary *paramsDictionary = [NSMutableDictionary new];
[paramsDictionary setValue:#"books_e_books_other_books" forKey:#"type"];
[DIOSNode nodeIndexWithPage:#"0" fields:#"nid" parameters:paramsDictionary pageSize:#"20"
success:^(AFHTTPRequestOperation *operation, id responseObject) {
//print response object
NSLog(#"%#", responseObject);
NSLog(#"GREAT SUCCESS");
//HERE IS MY PROBLEM!!!
//what do I do with response object?
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//code
NSLog(#"Oh no failed when trying to get the index");
NSLog(#"%#, %#", [error localizedDescription], [operation responseString]);
}];
In this section I index all of the nodes and get fields from each instead of getting all of the information from only one node. I get a response which shows things are working correctly thus far because the response has the correct info. I am confused though because I am not sure what my response object is exactly. It is a collection of nodes each with a "nid" and "uri" as shown from the index method responseObject below. If I wanted to get the value "650" for example from my first "nid" in the below printed area how would I go about doing this? I dont think I can call "objectForKey" as I did in the first working example because each node has a "nid". If I told my app to look for a key named nid it doesnt know which one to look for. With no unique keys how can I access the number 650? I have printed my index method responseObject below so you can see what I am talking about.
//printed statement from index method, this is what i am confused about, there are no unique keys how do I access the value 650 or the first nid
{
nid = 650;
uri = "http://www.domain.com/domain_endpoint/node/650";
},
{
nid = 649;
uri = "http://www.domain.com/domain_endpoint/node/649";
},
{
nid = 647;
uri = "http://www.domain.com/domain_endpoint/node/647";
},
It's been a few months since you asked this question, so I'm not sure if you're still looking for an answer, but in case anyone in the future needs it.
The responseObject is an array of NSDictionary objects. You can access the responseObject items just like an array and do whatever you need to with them depending on what you need the data for.
For example:
NSArray *responseArray = responseObject;
for (NSDictionary *item in responseArray)
{
// Do something with your item here
// For example:
NSString *uriStr = [item valueForKey:#"uri"];
}
I am trying to fetch youtube channel id using the google-api-objectivec-client. The problem I am having is basically that for some reason I am receiving exception when trying to access the channelId. The code I am using:
GTLServiceYouTube *service = [[GTLServiceYouTube alloc] init];
service.APIKey = _MY_API_KEY_;
GTLQueryYouTube *query = [GTLQueryYouTube queryForSearchListWithPart:#"id"];
query.q = #"google";
query.type = #"channel";
query.maxResults = 1;
GTLServiceTicket *ticket = [service executeQuery:query completionHandler:^(GTLServiceTicket *ticket, id object, NSError *error) {
if (error == nil) {
GTLYouTubeSearchListResponse *products = object;
for (id item in products.items) {
GTLYouTubeSearchResult *result = item;
NSLog(#"Identifier:%#",result.identifier);
GTLYouTubeResourceId* resourceId = result.identifier;
NSLog(#"kind:%#",resourceId.kind);
NSLog(#"channel:%#",resourceId.channelId);
}
}else{
NSLog(#"Error: %#", error.description);
}
}];
The output I get when i am running this code is:
2013-04-05 11:37:12.615 YouTest[21704:11303] Identifier:GTLYouTubeChannel 0x7233b00: {kind:"youtube#channel" channelId?:"UCK8sQmJBp8GCxrOtXWBpyEA"}
2013-04-05 11:37:12.617 YouTest[21704:11303] kind:youtube#channel
2013-04-05 11:37:12.617 YouTest[21704:11303] -[GTLYouTubeChannel channelId]: unrecognized selector sent to instance 0x7233b00
2013-04-05 11:37:12.618 YouTest[21704:11303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[GTLYouTubeChannel channelId]: unrecognized selector sent to instance 0x7233b00'
So my implementation crashes on the point where I am trying to access the channelId of the resourceId. From the documentation I understood that the channelId should be there as the type of the resourceId is youtube#channel. The channelId can be off course parsed from the result.identifier string that I am also printing, but since there is a property for the channelId I would prefer using that.
Any ideas about what is wrong with my code?
There is indeed a bug in the Google libraries. However I solved this problem by accessing the JSON string directly and parsing it with the help of the NSString+SBJSON.h class, as in this example.
#import "NSString+SBJSON.h"
...
GTLYouTubeResourceId *resource = channel.snippet.resourceId;
NSDictionary *jsonObject = [resource.JSONString JSONValue];
NSString *channelid = [jsonObject valueForKey:#"channelId"];
I'm not very familiar with Objective-C, but yeah, that looks like there's something wrong with the generated client library's YouTube Data API v3 bindings. Are you using the latest version from the project page? You might want to file a bug against the client library if you can reproduce it with the latest version. While troubleshooting this further, I'd check to see if you have the same problem when query.type = #"video"; and you try to access the videoId of the response item.
Here's an alternative you could try, though. The channel's id is also returned in the snippet.channelId property. If you request the snippet part via GTLQueryYouTube *query = [GTLQueryYouTube queryForSearchListWithPart:#"snippet"]; see if you can read that value instead.
I had the same issue. Solved it with the following...
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:[resourceId.JSONString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
NSString *channelId = [jsonObject valueForKey:#"channelId"];
NSLog(#"channelId is %#", channelId);
Workaround Code:
channel.snippet.resourceId.JSON[#"channelId"];
No need to parse the JSON yourself as the underlying JSON is exposed.
It looks like the automatic binding is not working for GTLYouTubeResourceId because the "kind" element of "youtube#channel" is throwing off the runtime object creation and creating a GTLYouTubeChannel instead.
Thorough Workaround Code:
ticket.surrogates = #{ (id)[GTLYouTubeChannel class] : [GTLYouTubeResourceId class] };
If you really want to force that binding to work you can workaround a little further upstream on the ticket when you execute the query.
Global Workaround Patch:
https://github.com/google/google-api-objectivec-client/pull/109
There's open tickets for the issue:
https://github.com/google/google-api-objectivec-client/issues/63
https://github.com/google/google-api-objectivec-client/issues/92
It seems they want to change the API to not call the resourceId.kind 'kind' to avoid this problem. But while we wait for the API to change, any of these three workarounds should serve your purposes.
I'm trying to do a fairly basic HTTP PUT using RestKit. I don't want to put the entire object, since the API call was designed to accept a single query parameter and just update that field. I've tried two approaches so far, both unsuccessful.
URL to post to: https://myserver/api/users/{userId}
Query string parameter: verificationCode=
Example usage: PUT https://myserver/api/users/101?verificationCode=646133
Approach #1: Put the query parameter in a RKParams object and make the PUT call with those params.
NSString *putUrl = [NSString stringWithFormat:#"/api/users/%i", [APIUserInfo sharedAPIUserInfo].apiUserIdx];
NSLog(#"the PUT url is %#", putUrl);
// Send a PUT to a remote resource. The dictionary will be transparently
// converted into a URL encoded representation and sent along as the request body
NSDictionary* paramsDict = [NSDictionary dictionaryWithObject:[_verificationCode text] forKey:#"verificationCode"];
// Convert the NS Dictionary into Params
RKParams *params = [RKParams paramsWithDictionary:paramsDict];
[[RKClient sharedClient] put:putUrl params:params delegate:self];
Approach #2: Build the entire url and try a PUT with params set to nil.
NSString *putUrl = [NSString stringWithFormat:#"/api/users/%i?verificationCode=%#", [APIUserInfo sharedAPIUserInfo].apiUserIdx, [_verificationCode text]];
NSLog(#"the PUT url is %#", putUrl);
[[RKClient sharedClient] put:putUrl params:nil delegate:self];
Neither approach is working for me. The first fails saying "RestKit was asked to retransmit a new body stream for a request. Possible connection error or authentication challenge?" then runs for about 10 seconds and times out. The second approach fails saying HTTP Status 405 - Method Not Allowed.
Can anyone point out where I'm going wrong, or provide me with a simple PUT example using RestKit? Most of the examples I've found at there are putting the entire object which I don't want to do in this case.
UPDATE:
Approach #2 worked well once I got a few things sorted out on the server side. Final solution:
NSString *putUrl = [NSString stringWithFormat:#"/api/users/verify/%i?verificationCode=%#", [APIUserInfo sharedAPIUserInfo].apiUserIdx, [_verificationCode text]];
NSLog(#"the PUT url is %#", putUrl);
[[RKClient sharedClient] put:putUrl params:nil delegate:self];
the HTTP PUT method is disabled on your webserver. It is by default on all webserver for security reasons.
HTTP Status 405 - Method Not Allowed.