I am using GMTOAuth2 in an application with one viewController and it works fine, Then I add same code to another application that contains more viewControllers, It loads the webView with textfields for username and password but if I click on anything in this view it crashes with Thread 1: EXC_BAD_ACCESS (code=2, address=0xbf7ffffc) with void SendDelegateMessage(NSInvocation *): delegate (webView:decidePolicyForNavigationAction:request:frame:decisionListener:) failed to return after waiting 10 seconds. main run loop mode: kCFRunLoopDefaultMode in the console. My code for authorization part looks like this:
- (void)awakeFromNib {
[super awakeFromNib];
GTMOAuth2Authentication *auth = nil;
auth = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName
clientID:kMyClientID
clientSecret:kMyClientSecret];
if (auth)
{
[auth authorizeRequest:nil
delegate:self
didFinishSelector:#selector(authentication:request:finishedWithError:)];
}
}
- (void)signInToGoogle {
[self signOut];
NSString *keychainItemName = kKeychainItemName;
NSString *scope = #"https://spreadsheets.google.com/feeds https://docs.google.com/feeds";
NSString *clientID = kMyClientID;
NSString *clientSecret = kMyClientSecret;
if ([clientID length] == 0 || [clientSecret length] == 0) {
NSString *msg = #"The sample code requires a valid client ID and client secret to sign in.";
[self displayAlertWithMessage:msg];
return;
}
SEL finishedSel = #selector(viewController:finishedWithAuth:error:);
GTMOAuth2ViewControllerTouch *viewController = [[GTMOAuth2ViewControllerTouch alloc] initWithScope:scope
clientID:clientID
clientSecret:clientSecret
keychainItemName:keychainItemName
finishedSelector:finishedSel];
delegate:self
[self presentViewController:viewController animated:YES completion:^{}];
[[self navigationController] pushViewController:viewController animated:YES];
}
- (void)authentication:(GTMOAuth2Authentication *)auth
request:(NSMutableURLRequest *)request
finishedWithError:(NSError *)error {
if (error != nil) {
NSLog(#"error!");
} else {
[self isAuthorizedWithAuthentication:auth];
self.auth = auth;
}
}
And copied the same class from first application to second one, and made exactly same nib file.
Related
FBSDKGameRequestContent *content = [[FBSDKGameRequestContent alloc]init];
content.message = #"Great FB";
content.title = #"Invite Friends";
FBSDKGameRequestDialog *gameDialog = [[FBSDKGameRequestDialog alloc]init];
gameDialog.content = content;
gameDialog.frictionlessRequestsEnabled = YES;
gameDialog.delegate = self;
if ([gameDialog canShow]) {
[gameDialog show];
}
I am using the above code for showing FBFriends. The dialog is opened, but I want to perform some of my custom functionality after user hits send/cancel.
How should I do it?
You're doing:
gameDialog.delegate = self;
So, why don't you use the delegate methods (FBSDKGameRequestDialogDelegate): gameRequestDialogDidCancel: and
gameRequestDialog:didCompleteWithResults: to know if user has cancelled of sent its invitation?
Source
In your YourCurrentClass.h:
#interface YourCurrentClass : NSObject < FBSDKGameRequestDialogDelegate >
In your YourCurrentClass.m:
- (void)gameRequestDialog:(FBSDKGameRequestDialog *)gameRequestDialog
didCompleteWithResults:(NSDictionary *)results
{
//User has done something.
//Check "results" and do something.
}
- (void)gameRequestDialogDidCancel:(FBSDKGameRequestDialog *)gameRequestDialog
{
//User has cancelled
//Do somathing
}
- (void)gameRequestDialog:(FBSDKGameRequestDialog *)gameRequestDialog
didFailWithError:(NSError *)error
{
//An error happened
NSLog(#"Error: %#", error);
//Do something
}
I am recieving an error on this line in my ViewControllerLogin.m file or anywhere a UIAlert shows up...
[UIAlertView error:#"Enter username and password over 4 chars each."];
The above code gives me an error in the issues editor: "no known class for method selector". I identified the method 'error' in another class in Xcode. Does anyone know why I am getting this error?
UPDATE ViewControllerLogin.m (the UIViewAlets are at the bottom)
#import "ViewControllerLogin.h"
#import "UIAlertView+error.h"
#import "API.h"
#include <CommonCrypto/CommonDigest.h>
#define kSalt #"adlfu3489tyh2jnkLIUGI&%EV(&0982cbgrykxjnk8855"
#implementation ViewControllerLogin
- (void)viewWillAppear:(BOOL)animated {
[self.navigationController setNavigationBarHidden:NO animated:animated];
[super viewWillAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
[self.navigationController setNavigationBarHidden:NO animated:animated];
[super viewWillDisappear:animated];
}
-(void)viewDidLoad {
[super viewDidLoad];
//focus on the username field / show keyboard
[fldUsername becomeFirstResponder];
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"qwertygreen.png"] forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.titleTextAttributes = #{NSForegroundColorAttributeName: [UIColor whiteColor]};
self.title = #"play";
//changes the buttn color
self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
// Do any additional setup after loading the view.
// Do any additional setup after loading the view, typically from a nib.
}
#pragma mark - View lifecycle
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
-(IBAction)btnLoginRegisterTapped:(UIButton*)sender {
//form fields validation
if (fldUsername.text.length < 4 || fldPassword.text.length < 4)
{
[UIAlertView error:#"Enter username and password over 4 chars each."];
return;
}
//salt the password
NSString* saltedPassword = [NSString stringWithFormat:#"%#%#", fldPassword.text, kSalt];
//prepare the hashed storage
NSString* hashedPassword = nil;
unsigned char hashedPasswordData[CC_SHA1_DIGEST_LENGTH];
//hash the pass
NSData *data = [saltedPassword dataUsingEncoding: NSUTF8StringEncoding];
if (CC_SHA1([data bytes], [data length], hashedPasswordData)) {
hashedPassword = [[NSString alloc] initWithBytes:hashedPasswordData length:sizeof(hashedPasswordData) encoding:NSASCIIStringEncoding];
} else {
[UIAlertView error:#"Password can't be sent"];
return;
}
//check whether it's a login or register
NSString* command = (sender.tag==1)?#"register":#"login";
NSMutableDictionary* params =[NSMutableDictionary dictionaryWithObjectsAndKeys:command, #"command", fldUsername.text, #"username", hashedPassword, #"password", nil];
//make the call to the web API
[[API sharedInstance] commandWithParams:params onCompletion:^(NSDictionary *json) {
//result returned
NSDictionary* res = [[json objectForKey:#"result"] objectAtIndex:0];
if ([json objectForKey:#"error"]==nil && [[res objectForKey:#"IdUser"] intValue]>0) {
[[API sharedInstance] setUser: res];
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
//show message to the user
[[[UIAlertView alloc] initWithTitle:#"Logged in" message:[NSString stringWithFormat:#"Welcome %#",[res objectForKey:#"username"]] delegate:nil cancelButtonTitle:#"Close" otherButtonTitles: nil] show];
} else {
//error
[UIAlertView error:[json objectForKey:#"error"]];
}
}];
}
#end
You need to import UIKit.
#import <UIKit/UIKit.h>
This is some code from my sms plugin for phonegap. I'm trying to make callbacks work properly: https://github.com/aharris88/phonegap-sms-plugin/issues/11
Here's the code I'm working on. You can see that I get the callback function at the beginning of the send method like this:
NSString* callback = command.callbackId;
Then I present an MFMessageComposeViewController and I need to call that callback when it finishes. So I'm using the messageComposeViewController:didFinishWithResult:, but how can I access that callback function that I need to call?
#import "Sms.h"
#import <Cordova/NSArray+Comparisons.h>
#implementation Sms
- (CDVPlugin *)initWithWebView:(UIWebView *)theWebView {
self = (Sms *)[super initWithWebView:theWebView];
return self;
}
- (void)send:(CDVInvokedUrlCommand*)command {
NSString* callback = command.callbackId;
if(![MFMessageComposeViewController canSendText]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Notice"
message:#"SMS Text not available."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
return;
}
MFMessageComposeViewController* composeViewController = [[MFMessageComposeViewController alloc] init];
composeViewController.messageComposeDelegate = self;
NSString* body = [command.arguments objectAtIndex:1];
if (body != nil) {
[composeViewController setBody:body];
}
NSArray* recipients = [command.arguments objectAtIndex:0];
if (recipients != nil) {
[composeViewController setRecipients:recipients];
}
[self.viewController presentViewController:composeViewController animated:YES completion:nil];
[[UIApplication sharedApplication] setStatusBarHidden:YES];
}
#pragma mark - MFMessageComposeViewControllerDelegate Implementation
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result {
int webviewResult = 0;
CDVPluginResult* pluginResult = nil;
switch(result) {
case MessageComposeResultCancelled:
webviewResult = 0;
break;
case MessageComposeResultSent:
webviewResult = 1;
break;
case MessageComposeResultFailed:
webviewResult = 2;
break;
default:
webviewResult = 3;
break;
}
[self.viewController dismissViewControllerAnimated:YES completion:nil];
[[UIApplication sharedApplication] setStatusBarHidden:NO];
if (webviewResult == 1) {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
} else {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:#"Arg was null"];
}
[self.commandDelegate sendPluginResult:pluginResult callbackId:callback];
}
#end
You'll want to store the callback ID as a property on the class.
#interface Sms
#property (nonatomic, strong) NSString *callbackId
#end
And then store it when you are in your send method.
- (void)send:(CDVInvokedUrlCommand*)command {
self.callbackId = command.callbackId;
You can then access it again from your delegate method:
NSString *callbackId = self.callbackId;
You should be good to go.
I have an iPhone app connects to a server using OAuth. On success, it fetches the a user from the server. Again, upon success, it adds an item to the array of objects that populates the table view. Here is the code that does this:
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
if (editing) {
[super setEditing:YES animated:YES];
self.backButton = self.navigationItem.leftBarButtonItem;
UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(signInWithCatapult)];
self.navigationItem.leftBarButtonItem = leftButton;
} else {
[super setEditing:NO animated:YES];
self.navigationItem.leftBarButtonItem = self.backButton;
}
}
- (void)signInWithCatapult
{
[self signOut];
GTMOAuth2Authentication *auth = [self catapultAuthenticaiton];
NSURL *authURL = [NSURL URLWithString:#"https://oauth.lvh.me:3000/oauth/authorize"];
GTMOAuth2ViewControllerTouch *viewController;
viewController = [[GTMOAuth2ViewControllerTouch alloc] initWithAuthentication:auth
authorizationURL:authURL
keychainItemName:kCatapultKeychainItemName
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)];
[[self navigationController] pushViewController:viewController animated:YES];
}
- (GTMOAuth2Authentication *)catapultAuthenticaiton
{
NSURL *tokenURL = [NSURL URLWithString:kDoorkeeperTokenURL];
NSString *redirectURI = #"https://catapultcentral.com/iOSClientCallback";
GTMOAuth2Authentication *auth;
auth = [GTMOAuth2Authentication authenticationWithServiceProvider:#"Catapult Central"
tokenURL:tokenURL
redirectURI:redirectURI
clientID:kDoorkeeperClientID
clientSecret:kDoorkeeperClientSecret];
return auth;
}
- (void)signOut
{
}
- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuth2Authentication *)auth
error:(NSError *)error
{
if (error != nil) {
#if DEBUG
NSLog(#"ERROR: %#", error);
#endif
} else {
NSURL *url = [NSURL URLWithString:#"https://api.lvh.me:3000/api/users/me"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
GTMHTTPFetcher *fetcher = [GTMHTTPFetcher fetcherWithRequest:request];
[fetcher setAuthorizer:auth];
[fetcher beginFetchWithDelegate:self didFinishSelector:#selector(currentUserFetcher:finishedWithData:error:)];
}
}
- (void)currentUserFetcher:(GTMHTTPFetcher *)fetcher
finishedWithData:(NSData *)data
error:(NSError *)error
{
if (error != nil) {
#if DEBUG
NSLog(#"ERROR: %#", error);
#endif
} else {
NSLog(#"Before: %#", self.accounts);
[self.tableView beginUpdates];
[self.accounts addObject:#"Success!!!"];
[self.tableView endUpdates];
// [self.tableView reloadData];
NSLog(#"After %#", self.accounts);
}
}
It's in the currentUserFetcher:finishedWithData:error: method that I add the object to the self.accounts mutable array. Now if I use this code it doesn't work:
[self.tableView beginUpdates];
[self.accounts addObject:#"Success!!!"];
[self.tableView endUpdates];
It fails at the line [self.tableView endUpdates]; with the following error message:
2013-03-28 08:56:21.040 Catapult for iOS[55012:c07] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableView.m:1054
And on the endUpdates line, XCode is complaining saying Thread 1: breakpoint 1.3. Now, if I use this code, it works normally:
[self.accounts addObject:#"Success!!!"];
[self.tableView reloadData];
Now I suspect that it is failing because I add an object to the self.accounts instance variable but I don't actually add the cell. So my question is: How do I add a cell to the tableView from the currentUserFetcher:finishedWithData:error: method?
If you just override this method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
Calling [UITableView reloadData] should just work itself out. The UITableViewController will just ask the amount of data (cells) that are there (using "tableView:numberOfRowsInSection:") and is requesting the Cell for every indexPath using the first mentioned method.
I'm trying to login to Tumblr via OAuth and a Mac App I begin to code.
I donwloaded gtm-oauth source code, everything is fine.
I just began with this code inside a view controller :
- (GTMOAuthAuthentication *)myCustomAuth {
GTMOAuthAuthentication *auth;
auth = [[[GTMOAuthAuthentication alloc] initWithSignatureMethod:kGTMOAuthSignatureMethodHMAC_SHA1
consumerKey:kConsumerKey
privateKey:kConsumerSecret] autorelease];
auth.serviceProvider = #"Custom Auth Service";
return auth;
}
- (void)viewController:(GTMOAuthViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuthAuthentication *)auth
error:(NSError *)error {
NSLog(#"finishedWithAuth");
if (error != nil) {
NSLog(#"failed");
} else {
NSLog(#"done");
}
}
- (void)signInToCustomService {
GTMOAuthAuthentication *auth = [self myCustomAuth];
if (auth == nil) {
NSLog(#"A valid consumer key and consumer secret are required for signing in to Tumblr");
}
else
{
NSLog(#"Ok auth");
}
NSURL *requestURL = [NSURL URLWithString:#"http://www.tumblr.com/oauth/request_token"];
NSURL *accessURL = [NSURL URLWithString:#"http://www.tumblr.com/oauth/access_token"];
NSURL *authorizeURL = [NSURL URLWithString:#"http://www.tumblr.com/oauth/authorize"];
NSString *scope = #"http://api.tumblr.com"; // HERE I DON'T KNOW WHAT TO WRITE
GTMOAuthViewControllerTouch *viewController;
viewController = [[[GTMOAuthViewControllerTouch alloc] initWithScope:scope
language:nil
requestTokenURL:requestURL
authorizeTokenURL:authorizeURL
accessTokenURL:accessURL
authentication:auth
appServiceName:#"My App: Custom Service"
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)] autorelease];
[self presentModalViewController:viewController animated:YES];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self signInToCustomService];
}
But nothing happens.
- (void)viewController:(GTMOAuthViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuthAuthentication *)auth
error:(NSError *)error;
This method is never called.
Perhaps this is my scope variable. I don't know which value I have to write for it.
Thanks for your help !