I have coded a backend on google appengine API which is working (checked with API explorer).
On executing my API, I should get multiple products returned.
The ios code below works and I confirmed NSLog dumps all the objects.
GTLServiceTicket *apiCall = [shoesService executeQuery:shoesQuery completionHandler:^(GTLServiceTicket *ticket, GTLProductApiManyProduct *object, NSError *error)
{
NSArray *receivedItems = [object items];
NSLog(#"%#",receivedItems); // this works shows objects with all propeties and corresponding values
// This is apparently an error, xcode wont allow this even when typing
NSLog(#"Product id:%#", [[receivedItems objectatIndex:0] productId]);
//Type casting also does not work in either case below.
NSLog(#"Product id:%#", (GTLProductOneProduct *)[[receivedItems objectatIndex:0] productId])
}
];
I think the issue is because all the properties have be autodeclared as #dynamic
How do I access properties inside the GTLProductOneProduct class of the returned *object?
If your api receives blocks of products (GTLProductAPIManyProducts) which contains (GTLProductAPIOneProduct), how do you access the values inside GTLProductAPIOneProduct ??
Should have dug more before putting this question on.
Used a wrong typecast now working, thanks all.
Related
I saw this question but nobody answer how to change the language using the Google Places Api for iOS (GMSAutocompleteFilter). I need set by code the lenguaje parameter in order to Google api always return the results in english. I saw in the documentation that it's an optional parameter called 'language', but I cant find the way to set it in the iOS api (not as url example in the doc).
if(aQuery.length>0){
GMSAutocompleteFilter *filter = [[GMSAutocompleteFilter alloc] init];
filter.type = kGMSPlacesAutocompleteTypeFilterCity;
// filter.accessibilityLanguage = #"en";
[_placesClient autocompleteQuery:aQuery
bounds:nil
filter:filter
callback:^(NSArray *results, NSError *error) {
if (error != nil) {
NSLog(#"Autocomplete error %#", [error localizedDescription]);
handler(nil);
return;
}
if(results.count>0){
NSMutableArray *arrfinal=[NSMutableArray array];
for (GMSAutocompletePrediction* result in results) {
NSDictionary *aTempDict = [NSDictionary dictionaryWithObjectsAndKeys:result.attributedFullText.string,#"description",result.placeID,#"reference", nil];
PlaceObject *placeObj=[[PlaceObject alloc]initWithPlaceName:[aTempDict objectForKey:#"description"]];
placeObj.userInfo=aTempDict;
[arrfinal addObject:placeObj];
}
handler(arrfinal);
}else{
handler(nil);
}
}];
}else{
handler(nil);
}
You may need to use the Geocoding API to receive these responses in a different language. See here for the Reverse Geocoding article, with the language parameter a few paragraphs down.
You can make an NSURLRequest with the appropriate URL and language parameters. The response is in JSON format, so you should be able to handle this change dynamically within your code.
A cleaner way to do it might be to create a separate page that acts as a sort of web service for you. It accepts two parameters: A language code and an address. It loads the API using the language code requested, and reverse geocodes the address, providing the result. Your page would call this web service-like thing twice, once for each language, and then use the results as desired.
I am using Azure Mobile Service as a backend for an iOS app. I have set up everything to work with offline sync which allows me to view, add, or modify data even when there is no network connection. I am now into testing and I run into an error: "The item provided was not valid" when I try to synchronize data.
Here's what I am doing:
I add a new athlete to the syncTableWithName:#"Athlete" with this:
NSDictionary *newItem = #{#"firstname": #"Charles", #"lastname": #"Lambert", #"laterality" : #"Orthodox"};
[self.athletesService addItem:newItem completion:^{
NSLog(#"New athlete added");
}];
Here's the addItem function:
-(void)addItem:(NSDictionary *)item completion:(CompletionBlock)completion
{
// Insert the item into the Athlete table
[self.syncTable insert:item completion:^(NSDictionary *result, NSError *error)
{
[self logErrorIfNotNil:error];
// Let the caller know that we finished
dispatch_async(dispatch_get_main_queue(), ^{
completion();
});
}];
}
For now everything is fine and the item is in the syncTable. The problem is when I try to synchronize with the Azure Mobile Service. Here's the syncData function I am calling:
-(void)syncData:(CompletionBlock)completion
{
// push all changes in the sync context, then pull new data
[self.client.syncContext pushWithCompletion:^(NSError *error) {
[self logErrorIfNotNil:error];
[self pullData:completion];
}];
}
The pushWithCompletion gets me the error: "The item provided was not valid." and same for the pullData function that gets called after:
-(void)pullData:(CompletionBlock)completion
{
MSQuery *query = [self.syncTable query];
// Pulls data from the remote server into the local table.
// We're pulling all items and filtering in the view
// query ID is used for incremental sync
[self.syncTable pullWithQuery:query queryId:#"allAthletes" completion:^(NSError *error) {
[self logErrorIfNotNil:error];
// Let the caller know that we finished
dispatch_async(dispatch_get_main_queue(), ^{
completion();
});
}];
}
I have tried inserting directly in the MSTable and that works fine. It's really when I am using the MSSyncTable that I run into this error. Although when I insert data manually in my database and that I synchronize my context I can fetch data and display within my UITableView.
Lookin forward to see what you guys think about this. Thanks a lot!
I just edited my question thanks to #phillipv.
When I add an item using NSDictionary just like I did I run into the error "The item provided was not valid". So I tried adding an item by first inserting it to my managedObjectContext and then calling:
NSDictionary *dict = [MSCoreDataStore tableItemFromManagedObject:newAthlete];
I then I get the error when I try to sync: "The item provided did not have a valid id."
I feel like I am experiencing a circle.. :S
#Charley14, you can work around the bug by adding the following handler.
- (void)tableOperation:(nonnull MSTableOperation *)operation onComplete:(nonnull MSSyncItemBlock)completion
{
NSMutableDictionary *rwItem = [NSMutableDictionary dictionaryWithDictionary:operation.item];
// Temporary workaround
[rwItem removeObjectsForKeys:#[ #"relationship1", #"relationship2"]];
operation.item = rwItem;
[operation executeWithCompletion:completion];
}
The tableOperation:onComplete: handler is simply removing keys that correspond to the relationships. You will have to replace 'relationship1', 'relationship2' in the code snippet with names of actual relationships in your application.
Once the bug (https://github.com/Azure/azure-mobile-services/issues/779) is fixed, this workaround can be removed.
This appears to be a bug in the iOS SDK, as the Many to One relationship is not supposed to be exposed in the object given to the operation during a Push call.
Created the following bug with more details on GitHub: https://github.com/Azure/azure-mobile-services/issues/779
The cause of the error message is due to the fact that the relationship is a NSSet on the object, and the NSJSONSerializer throws as it does not know how to convert that to JSON.
Here is my code:
//create array with all the teams
NSMutableArray *leagueTeams = [[NSMutableArray alloc] init];
//send request
[[sessionManager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
NSDictionary *responseFromJSONDictionary = (NSDictionary *) responseObject;
//copy the team's attributes into temp variables
NSString *tempTeamIDCode = [responseFromJSONDictionary objectForKey:#"teamCode"];
NSString *tempTeamName = [responseFromJSONDictionary objectForKey:#"teamName"];
NSInteger tempTeamPoints = [(NSNumber *) [responseFromJSONDictionary objectForKey:#"teamPoints"] integerValue];
//use temp variables to create a temporary team
Team *aTeam = [[Team alloc] initWithTeamIdCode:tempTeamIDCode andTeamName:tempTeamName andLeaguePoints:tempTeamPoints];
//add team to array
[leagueTeams addObject:[aTeam copy]];
}]resume];
I am trying to make an app that retrieves JSON data from a server. for now I'm using a static JSON to retrieve entries. I used breakpoints to follow the variable values. The app successfully retrieves the JSON data, it successfully creates the 3 temp variables and successfully creates the team object AND successfully adds the object to the leageTeams mutablearray, while inside the success code block.
BUT, the moment the application leaves the success block, the leagueTeams array disappears. it doesn't exist in memory even as an empty array, like it did before the execution of the success block.
I'm probably doing something very wrong with trying to pass data to an outside variable inside the code block, but all other similar questions had the trouble of not getting the data from the server in time, but in my case the data request is always successful and the JSON response and turning it into an NSDICtionary all work fine....so anyone can help please? Thanks
Okay what's happening is the "dataTaskWithRequest:completionHandler:" method is asynchronous! Once it starts the program execution doesn't wait for it to return value it continues to next line outside of it. So probably the code which you have written below this method is executing first than the code inside the completion handler. So what you can do is trigger a Notification or call some delegate method to run any code after the completion Handler returns the required value.
I have the following code to read in passed URLs. I'm testing this with the Pocket app and although hasItemConformingToTypeIdentifier is returning YES for kUTTypeURL, trying to load it in returns a error instead stating
"Unexpected value class."
. If I try to load it as an id<NSSecureCoding> item and debug, I find that the passed in object is indeed just the title of the page and not the URL. How do I read the URL?
NSURL *pageURL = nil;
for (NSExtensionItem *item in self.extensionContext.inputItems) {
for (NSItemProvider *itemProvider in item.attachments) {
if ([itemProvider hasItemConformingToTypeIdentifier: (NSString*) kUTTypeURL]) {
[itemProvider loadItemForTypeIdentifier:(NSString*) kUTTypeURL options:nil completionHandler:^(id <NSSecureCoding> urlItem, NSError *error) {
if ([((NSObject*)urlItem) isKindOfClass: [NSURL class]]) {
pageURL = [((NSURL*)urlItem) absoluteString];
}
}];
}
}
}
If you read the documentation for:
loadItemForTypeIdentifier(_:options:completionHandler:)
You'll see that:
The type information for the first parameter of your completionHandler
block should be set to the class of the expected type. For example,
when requesting text data, you might set the type of the first
parameter to NSString or NSAttributedString. An item provider can
perform simple type conversions of the data to the class you specify,
such as from NSURL to NSData or NSFileWrapper, or from NSData to
UIImage (in iOS) or NSImage (in OS X). If the data could not be
retrieved or coerced to the specified class, an error is passed to the
completion block’s.
Maybe you can experiment by coercing to different types?
Try this
__block NSURL *pageURL = nil;
for (NSExtensionItem *item in self.extensionContext.inputItems) {
for (NSItemProvider *itemProvider in item.attachments) {
if ([itemProvider hasItemConformingToTypeIdentifier: (NSString*) kUTTypeURL]) {
[itemProvider loadItemForTypeIdentifier:(NSString*) kUTTypeURL options:nil completionHandler:^(NSURL *urlItem, NSError *error) {
if (urlItem) {
pageURL = urlItem;
}
}];
}
}
}
And now if you want take URL of your current site use
NSString *output = [pageURL absolutestring];
Output - will be your URL.
I stumbled over this issue now myself. The Pocket App seems to be the only App which shows this issue. The strange thing is that there are Apps which can get the URL form Pocket. Like for example Firefox for iOS. Firefox is Open Source so I looked at its code (at Github) and found that it is doing exactly the same to get the URL that is shown here. The only difference is that Firefox is written in Swift, and my code (and the one posted here) is Objective C. So I wonder if the Pocket App is doing something strange that is triggering a bug in the Objective C API of the iOS only, so Swift Apps are not affected? I do not have any Swift experience yet, so I haven’t checked if switching to Swift would „solve“ this.
The fact that the method "hasItemConformingToTypeIdentifier:“ states that there is a URL available but „loadItemForTypeIdentifier:“ can not deliver it, is a clear indication that the iOS itself has a bug here (at least in the Objective C API). But there still must be something special the Pocket App is doing to trigger this bug, because otherwise this would not work in all other Apps.
I'm trying to insert a "Moment" into a user's Google+ account, using the google-api-objectivec-client library. I think have the authentication process working properly. It's primarily the same way I have YouTube authentication set up, but with the correct scope and keychain name. However, when I try to run the query to insert the moment I get the following error:
Error Domain=com.google.GTLJSONRPCErrorDomain Code=401 "The operation
couldn’t be completed. (Unauthorized)"
After looking at Google's documentation more carefully (here) I found the following comment:
When authenticating for moments.insert, you must include the data-requestvisibleactions
parameter to specify which types of App Activities your application will write.
Google has several examples of how to do this with other programming languages, but they don't have any examples for the objective-c library, and the objective-c project doesn't contain any examples of how to do this either.
I know that there's another authentication method, using the GPPSignIn button, which has a way to set the actions. However, my application is using multiple other Google API clients (YouTube, YouTube Analytics, and URL Shortener). Mixing the GoogleOpenSource.framework with the other Objective-C libraries causes a conflict. So, I need to use the GTMOAuth2ViewControllerTouch class.
My Authentication Code
GTMOAuth2ViewControllerTouch *viewController =
[GTMOAuth2ViewControllerTouch controllerWithScope:kGTLAuthScopePlusLogin
clientID:kGoogleApiClientId
clientSecret:kGoogleApiClientSecret
keychainItemName:kGooglePlusKeychainName
completionHandler:^(GTMOAuth2ViewControllerTouch *viewController, GTMOAuth2Authentication *auth, NSError *error) {
if (error)
NSLog(#"Error: %#", error.description);
else
app.googlePlusService.authorizer = auth; //this sets a property of my app delegate, to be used elsewhere in the application
}];
[self.navigationController pushViewController:viewController animated:YES];
The code I'm using to insert the "Moment"
NSString *shareUrl = "http://www.google.com"; //just for this example
GTLPlusMoment *moment = [[GTLPlusMoment alloc] init];
moment.type = #"http://schemas.google.com/AddActivity";
GTLPlusItemScope *target = [[GTLPlusItemScope alloc] init];
target.url = shareUrl;
moment.target = target;
GTLQueryPlus *query =
[GTLQueryPlus queryForMomentsInsertWithObject:moment
userId:#"me"
collection:kGTLPlusCollectionVault];
[app.googlePlusService executeQuery:query
completionHandler:^(GTLServiceTicket *ticket,
id object,
NSError *error) {
if (error) {
NSLog(#"Got bad response from plus.moments.insert: %#", error);
} else {
NSLog(#"Moment inserted: %#",moment.identifier);
}
}];
Has anyone out there successfully found the place to add the data-requestvisibleactions parameter to either the authentication call or queryForMomentsInsertWithObject method to allow them to execute the moments.insert action without receiving an error?
Thanks!
You can add data-requestvisibleactions using Java Script code in Authentication. Once you authorized with java script, it will be authorized for all types of insert moments. There is no method in Objective c for adding data-requestvisibleactions in your code. Only the option is possible through Java Script.
For More derails Refer THIS