I use library soap the return of this function in on nsdictionary i change it into nsarray after i close ];} and type nslog it give that nsarray =null but if i put it before close of the method in the method give data
- (void)showlinks
{
SYSoapClient *show_links_obj = [SYSoapClient new];
links_tags = [[NSMutableArray alloc] initWithObjects:#"empid", #"type", nil];
links_vars = [[NSMutableArray alloc] initWithObjects:txt_username, type_user, nil];
[show_links_obj callSoapServiceWithParameters__functionName:#"getlinks"
tags:links_tags
vars:links_vars
callback:^(NSDictionary *result,
BOOL response)
{
link_raw_Data = [result allValues];
link_con_Data = [link_raw_Data componentsJoinedByString:#""];
//NSArray *links = [con_Data componentsSeparatedByString:#"#"];
links = [link_con_Data componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"#^"]];
NSUInteger x = links.count;
NSLog(#"%#",link_raw_Data);
//NSLog(#"%d",x);
//NSLog(#"%#",links[5]);
}];
NSLog(#"%#",links[5]);
}
Judging by the callback argument to the soap service, it's an asynchronous call. This means that it will return right away, do the networking on a background thread and call the callback sometime later when it is done.
Since it's asynchronous and doesn't wait/block, the log statement just after it will be executed before getting any data back from the soap service.
Related
Please see code below:
+ (void)splashDataFromJSON:(NSData *)objectNotation error:(NSError **)error
{
NSError *localError = nil;
NSDictionary *parsedObject = [NSJSONSerialization JSONObjectWithData:objectNotation options:0 error:&localError];
if (localError != nil) {
*error = localError;
}
NSMutableArray* btms = [[NSMutableArray alloc] init];
NSMutableDictionary* btmManufacturerResolutionDictionary = [[BTMCache sharedManager] btmManufacturerResolutionDictionary];
NSArray *results = [parsedObject valueForKey:#"results"];
NSLog(#"Count %d", parsedObject.count);
NSString* imageBaseUrl = [[parsedObject valueForKey:#"general"] valueForKey:#"image_base_url"];
imageBaseUrl = [imageBaseUrl stringByAppendingString:#"hdpi/"];
NSString* splashImageName = [[[parsedObject valueForKey:#"general"] valueForKey:#"splash"] valueForKey:#"img"];
NSString* splashAdvertiserURL = [[[[parsedObject valueForKey:#"general"] valueForKey:#"splash"] valueForKey:#"url"] copy];
NSMutableString* appendedString = [[NSMutableString alloc] init];
for(int i =0 ;i<[splashAdvertiserURL length]; i++) {
char character = [splashAdvertiserURL characterAtIndex:i];
printf(&character);
sleep(0.1);
if (character != "!")
{
[appendedString appendFormat:#"%c", character];
}
}
[[SplashData sharedManager] setSplashAdvertiserURL:appendedString];
[[SplashData sharedManager] setSplashImageName:splashImageName];
splashAdvertiserURL = [[SplashData sharedManager] splashAdvertiserURL];
}
The point of interest is in splashAdvertiserURL. When I receive this data and print it out using po, it comes out as "https://radar.com/ref/go/84/". This is fine and what was expected. When I look at the incoming data in JSONLint it looks like this:
"general": {
"image_base_url": "https:\/\/radar.com\/img\/manufacturers\/",
"splash": {
"img": "image1.png",
"url": "https:\/\/radar.com\/ref\/go\/84\/"
}
},
As you can see, further on I put the NSString into a singleton with an NSString property. Nothing abnormal here. I then proceed to retrieve it to see that all is ok. Further to this the program continues. In another class I wish to retrieve this information, and when I try and do that, it throws EXC_BAD_ACCESS. There appears to be garbage in there.
I then put in a loop in the code as you can see to print out the characters one at a time. Very curiously, when I print that out using po I get:
https://
r
a
d
ar.com/ref/go/8 4!/"
Exactly in that format. If I then proceed to hardcode the string https://radar.com/ref/go/84/ - including escape characters and everything, then all works fine. No issues. If I handle a normal string incoming without escape characters it stores fine in the singleton as well, no issue. enter code here
I am pretty stumped here as to what is going on. Can someone assist?
Thank you
For URL you received as string you need to encode before use it to in your app. Have a look at below code:
NSString *sampleUrl = #"https:\/\/radar.com\/ref\/go\/84\/";
NSString *encodedUrl = [sampleUrl stringByAddingPercentEscapesUsingEncoding:
NSUTF8StringEncoding];
When using JSON.parse(parameter-value) in JavaScript, the adapter invocation is working correctly, however when doing similarly in a native iOS app, it is failing with the following error.
Javascript Adapter Call:
var invocationData = {
adapter : 'TEST_ADAP',
procedure : 'PROC1',
parameters : [JSON.parse(A)],
};
Native Call:
json= // some json value will be come
MyConnect *connectListener = [[MyConnect alloc] initWithController:self];
[[WLClient sharedInstance] wlConnectWithDelegate:connectListener];
WLProcedureInvocationData *myInvocationData = [[WLProcedureInvocationData alloc] initWithAdapterName:#"TEST" procedureName:#"test"];
myInvocationData.parameters = [NSArray arrayWithObjects:json, nil];
for (NSString *str in myInvocationData.parameters) {
NSLog(#"values of account test %#",str);
}
PasswardPage *invokeListener = [[PasswardPage alloc] initWithController:self];
[[WLClient sharedInstance] invokeProcedure:myInvocationData withDelegate:invokeListener];
Your line
myInvocationData.parameters = [NSArray arrayWithObjects:json, nil];
is almost right.
The parameters property should be an NSArray (as you did) but the array must be made of string values - NOT a JSON object.
myInvocationData.parameters = [NSArray arrayWithObjects:#"myValue1", #"myValue2", #"myValue3", nil];
If the data you received is not in this format, you need to first convert it to this format. This is out of the scope of this question.
If you are not sure how to convert your existing format into a valid NSArray, please open a new question (tagged with Objective-C, not worklight).
We can pass JSON as NSString in iOS Native code to invoke adapter
Example
//Created Dictionary
NSMutablec *dict = [[NSMutableDictionary alloc]init];
[dict setObject:#"xyz" forKey:#"Name"];
[dict setObject:#"iOS" forKey:#"Platform"];
//Convert it to JSON Data
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict
options:nil
error:&error];
//JSON Data To NSString
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
WLProcedureInvocationData * invocationData = [[WLProcedureInvocationData alloc] initWithAdapterName:#"XYZAdapter" procedureName:#"FunctionXYZ"];
//Passing jsonString (NSString Created out of JSON Data) as array to set Parameters.
[invocationData setParameters:[NSArray arrayWithObject:jsonString]];
[[WLClient sharedInstance] invokeProcedure:invocationData withDelegate:self];
I'm new to Objective C and XML, so this is going to look pretty rough.
My code is as follows:
#import "dbCommunicator.h"
#import "BookInfo.h"
#import "TouchXML.h"
#implementation dbCommunicator
-(void)getNextBooks {
if(self.bookListing == nil) {
for(int i = 0; i < 5; i++) {
BookInfo *newBook = [[BookInfo alloc] init];
[self.bookListing addObject:newBook];
}
self.currentPage = 0;
}
if(self.currentPage == 10) {
self.currentPage = 0;
}
NSString *test = #"<Authors><Book.Author><Id>1026</Id><Name>Mark Twain</Name></Book.Author></Authors>";
NSString *bookQueryString = [NSString stringWithFormat:#"http://bookworm.azurewebsites.net/api/book/list/5/%d",_currentPage];
NSURL *bookQueryURL = [NSURL URLWithString: bookQueryString];
self.currentPage++;
NSError *theError = NULL;
NSDictionary *mappings = [NSDictionary dictionaryWithObjectsAndKeys:
#"http://schemas.datacontract.org/2004/07/Bookworm.Models.ResponseModels",
#"datacontract",
nil];
CXMLDocument *xmlReturn = [[CXMLDocument alloc] initWithXMLString:test options:0 error:&theError];
NSArray *returnedBooks = [xmlReturn nodesForXPath:#"//Authors" error:&theError];
for(CXMLElement *resultElement in returnedBooks) {
NSLog(#"%s", "We actually got here");
}
}
There's a lot of junk code in there at the moment. The intention is to pull an XML file from a database and put its information into an array of BookInfo classes. For the moment, I simplified by just using a test XMLstring to ensure it wasn't an issue with what the database was sending me. This makes the dictionary (to deal with the namespace issues TouchXML has) superfluous. Anyways.
It always crashes with a unrecognized selector error on this line:
[theArray addObject:[CXMLNode nodeWithLibXMLNode:theNode freeOnDealloc:NO]];
In this context:
if (xmlXPathNodeSetIsEmpty(theXPathObject->nodesetval))
theResult = [NSArray array]; // TODO better to return NULL?
else {
NSMutableArray *theArray = [NSMutableArray array];
int N;
for (N = 0; N < theXPathObject->nodesetval->nodeNr; N++) {
xmlNodePtr theNode = theXPathObject->nodesetval->nodeTab[N];
[theArray addObject:[CXMLNode nodeWithLibXMLNode:theNode freeOnDealloc:NO]];
}
}
and with that, I'm totally at a loss. I've tried plenty of things, scoured every StackOverflow post even closely related and tried their fixes, nothing's working. Any suggestions?
array is a static method on NSArray a super class of NSMutableArray that returns an NSArray object. NSArray does not respond to the method addObject:
Try instead NSMutableArray *theArray = [NSMutableArray new];
The problem probably is on this selector:
nodeWithLibXMLNode:freeOnDealloc:
if you try to see your crash log in the console, should be written the selector unrecognized and should be this. If so check the class reference of the CXMLNode.
I checked now, and that method doesn't exists. Just a method might be useful for you in some way, that is:
- (NSArray *)nodesForXPath:(NSString *)xpath error:(NSError **)error;
Enjoy ;)
I came across few posts here related to what I am doing but I am working with some nested objects that I want to extract.
This is a sample of my returned data - https://gist.github.com/ryancoughlin/8043604
I have this in my header so far :
#import "TideModel.h"
#protocol TideModel
#end
#implementation TideModel
-(id)initWithDict:(NSDictionary *)json {
self = [super init];
if(self) {
self.maxheight = [dictionary valueForKeyPath:#"tide.tideSummaryStats.minheight"];
self.minheight = [dictionary valueForKeyPath:#"tide.tideSummaryStats.maxheight"];
self.tideSite = [dictionary valueForKeyPath:#"tide.tideInfo.tideSite"];
}
return self;
}
#end
I have declared a property for each string and i am accessing it accordingly.
But what I have above doesn't work, maybe because it wont know what to drill in to correct?... Or will it?
tide.tideSummaryStats returns an array.
tide.tideInfo returns an array.
So you can't do -valueForKeyPath: all the way.
Also, this is incorrect: [dictionary valueForKeyPath:...];
it should be : [json valueForKeyPath:...];
because json is the name of the NSDictionary variable passed (not dictionary)
Try this (not sure):
-(id)initWithDict:(NSDictionary *)json {
self = [super init];
if(self) {
NSArray *arrOfTideSummaryStats = [json valueForKeyPath:#"tide.tideSummaryStats"];
NSDictionary *dctOfTideSummaryStats = [arrOfTideSummaryStats objectAtIndex:0];
//since self.maxheight and self.minheight are NSString objects and
//the original keys "minheight" & "maxheight" return float values, do:
self.maxheight = [NSString stringWithFormat:#"%f", [dctOfTideSummaryStats valueForKey: #"maxheight"]];
self.minheight = [NSString stringWithFormat:#"%f", [dctOfTideSummaryStats valueForKey: #"minheight"]];
/*============================================================*/
NSArray *arrOfTideInfo = [json valueForKeyPath:#"tide.tideInfo"];
NSDictionary *dctOfTideInfo = [arrOfTideInfo objectAtIndex:0];
self.tideSite = [dctOfTideInfo valueForKey:#"tideSite"];
}
return self;
}
Similar Questions:
How to parsing JSON object in iPhone SDK (XCode) using JSON-Framework
Getting array elements with valueForKeyPath
Keypath for first element in embedded NSArray
Recently had to create a app that worked with a remote RESTful server that returned JSON data and was then deserialised into an object for graphing.
I used unirest for the requests and responses and then deserialised the returned JSON into an object. Below is an extract of the code where "hourlySalesFigures" within dictionary "jsonResponseAsDictionary" was a JSON collection of 24 figures which I put into an array. Please note the function is a lot larger but I removed anything which I thought was distracting.
- (PBSSales*) deserializeJsonPacket2:(NSDictionary*)jsonResponseAsDictionary withCalenderType:(NSString *)calendarViewType
{
PBSSales *pbsData = [[PBSSales alloc] init];
if(jsonResponseAsDictionary != nil)
{
// Process the hourly sales figures if the day request and returned is related to Daily figures
if([calendarViewType isEqualToString:#"Day"]){
NSArray *hourlyFiguresFromJson = [jsonResponseAsDictionary objectForKey:#"hourlySalesFigures"];
PBSDataDaySales *tmpDataDay = [[PBSDataDaySales alloc] init];
NSMutableArray *hSalesFigures = [tmpDataDay hourlySalesFigures];
for(NSInteger i = 0; i < [hourlyFiguresFromJson count]; i++){
hSalesFigures[i] = hourlyFiguresFromJson[i];
}
[[pbsData dataDay] setHourlySalesFigures:hSalesFigures];
[pbsData setCalViewType:#"Day"];
}
}
return pbsData;
}
I've been breaking my head over this the whole day.
I wish to integrate my iOS app with Withings api. It uses OAuth 1.0 and I can't seem to understand fully how to implement it.
I've been downloading multiple OAuth framworks (MPOAuth,gtm-oauth,ssoauthkit) but couldn't figure out completely what exactly I should do.
I searched a lot, also in stack overflow for good references on how to go about implementing OAuth 1.0 in general & integrating with Withings in particular with no success.
Kindly explain the flow of integrating an iOS app with an api that requires OAuth 1.0. Code examples would be very helpful. Suggested 3rd party frameworks would be nice too.
Just to clarify, I fully understand the OAuth 1.0 principles, I just have problems in actually implementing it in my app.
I think that a thorough answer with code examples and good references would be very helpful for lots of people as I couldn't find one. If anyone has good experience with implementing it, please take the time to share it.
TDOAuth in my opinion was the best solution. it is clean and simple, only one .h and .m file to work with, and no complicated example projects..
This is the OAuth 1.0 flow:
step 1 - get request token
//withings additional params
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:CALL_BACK_URL forKey:#"oauth_callback"];
//init request
NSURLRequest *rq = [TDOAuth URLRequestForPath:#"/request_token" GETParameters:dict scheme:#"https" host:#"oauth.withings.com/account" consumerKey:WITHINGS_OAUTH_KEY consumerSecret:WITHINGS_OAUTH_SECRET accessToken:nil tokenSecret:nil];
//fire request
NSURLResponse* response;
NSError* error = nil;
NSData* result = [NSURLConnection sendSynchronousRequest:rq returningResponse:&response error:&error];
NSString *s = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
//parse result
NSMutableDictionary *params = [NSMutableDictionary dictionary];
NSArray *split = [s componentsSeparatedByString:#"&"];
for (NSString *str in split){
NSArray *split2 = [str componentsSeparatedByString:#"="];
[params setObject:split2[1] forKey:split2[0]];
}
token = params[#"oauth_token"];
tokenSecret = params[#"oauth_token_secret"];
step 2 - get authorize token (by loading the request in a UIWebView, the webViewDidFinishLoad delegate method will handle the call back..)
//withings additional params
NSMutableDictionary *dict2 = [NSMutableDictionary dictionary];
[dict setObject:CALL_BACK_URL forKey:#"oauth_callback"];
//init request
NSURLRequest *rq2 = [TDOAuth URLRequestForPath:#"/authorize" GETParameters:dict2 scheme:#"https" host:#"oauth.withings.com/account" consumerKey:WITHINGS_OAUTH_KEY consumerSecret:WITHINGS_OAUTH_SECRET accessToken:token tokenSecret:tokenSecret];
webView.delegate = self;
[DBLoaderHUD showDBLoaderInView:webView];
[webView loadRequest:rq2];
handle the webView as follow to initiate step 3 (I know the isAuthorizeCallBack smells a lot, but it does the job, should refactor it..)
- (void)webViewDidFinishLoad:(UIWebView *)aWebView
{
[DBLoaderHUD hideDBLoaderInView:webView];
NSString *userId = [self isAuthorizeCallBack];
if (userId) {
//step 3 - get access token
[DBLoaderHUD showDBLoaderInView:self.view];
[self getAccessTokenForUserId:userId];
}
//ugly patchup to fix an invalid token bug
if ([webView.request.URL.absoluteString isEqualToString:#"http://oauth.withings.com/account/authorize?"])
[self startOAuthFlow];
}
- (NSString *)isAuthorizeCallBack
{
NSString *fullUrlString = webView.request.URL.absoluteString;
if (!fullUrlString)
return nil;
NSArray *arr = [fullUrlString componentsSeparatedByString:#"?"];
if (!arr || arr.count!=2)
return nil;
if (![arr[0] isEqualToString:CALL_BACK_URL])
return nil;
NSString *resultString = arr[1];
NSArray *arr2 = [resultString componentsSeparatedByString:#"&"];
if (!arr2 || arr2.count!=3)
return nil;
NSString *userCred = arr2[0];
NSArray *arr3 = [userCred componentsSeparatedByString:#"="];
if (!arr3 || arr3.count!=2)
return nil;
if (![arr3[0] isEqualToString:#"userid"])
return nil;
return arr3[1];
}
- (void)startOAuthFlow
{
[self step1];
[self step2];
}
and finally - step 3 - get access token
- (void)getAccessTokenForUserId:(NSString *)userId
{
//step 3 - get access token
//withings additional params
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:CALL_BACK_URL forKey:#"oauth_callback"];
[dict setObject:userId forKey:#"userid"];
//init request
NSURLRequest *rq = [TDOAuth URLRequestForPath:#"/access_token" GETParameters:dict scheme:#"https" host:#"oauth.withings.com/account" consumerKey:WITHINGS_OAUTH_KEY consumerSecret:WITHINGS_OAUTH_SECRET accessToken:token tokenSecret:tokenSecret];
//fire request
NSURLResponse* response;
NSError* error = nil;
NSData* result = [NSURLConnection sendSynchronousRequest:rq returningResponse:&response error:&error];
NSString *s = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
//parse result
NSMutableDictionary *params = [NSMutableDictionary dictionary];
NSArray *split = [s componentsSeparatedByString:#"&"];
for (NSString *str in split){
NSArray *split2 = [str componentsSeparatedByString:#"="];
[params setObject:split2[1] forKey:split2[0]];
}
[self finishedAthourizationProcessWithUserId:userId AccessToken:params[#"oauth_token"] AccessTokenSecret:params[#"oauth_token_secret"]];
}
I additionaly save request headers here
NSMutableDictionary *dict2 = [NSMutableDictionary dictionary];
[dict2 setObject:CALL_BACK_URL forKey:#"oauth_callback"];
NSURLRequest *rq2 = [TDOAuth URLRequestForPath:#"/authorize"
GETParameters:dict2
scheme:#"https"
host:#"oauth.withings.com/account"
consumerKey:WITHINGS_OAUTH_KEY
consumerSecret:WITHINGS_OAUTH_SECRET
accessToken:self.token
tokenSecret:self.tokenSecret];
headers = rq2.allHTTPHeaderFields;
And in callback method i will add missing parameters to the request. By doing it this way, i avoid "ugly patchup fix".
- (BOOL)webView:(UIWebView *)wV shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
if (![request.allHTTPHeaderFields objectForKey:#"Authorization"] &&
[request.URL.absoluteString rangeOfString:#"acceptDelegation=true"].location == NSNotFound){
NSMutableURLRequest *mutableCp = [request mutableCopy];
NSLog(#"request :::%#", request);
[mutableCp setAllHTTPHeaderFields:headers];
dispatch_async(dispatch_get_main_queue(), ^{
[webView loadRequest:mutableCp];
});
return NO;
}
return YES;
}
I hope it will help somebody
I would suggest you to check this project both as a reference and as a really working OAuth class. It inherits from another great project, so you you will need to add both in yours.Check if the license will suits your requirements.
https://github.com/rsieiro/RSOAuthEngine