Login in a user using AFNetworking 2 (or some other framework - afnetworking-2

I am trying to write some code to have a user enter their username and password and then authenticate against a server using basic HTTP authentication. I can do it using AFNetworking 2 BUT I want to be able to return whether or not the request was successful. The code below works, but how can I refactor it so that I can call the method and then return a BOOL true or false?? It is driving me crazy that I can't do this.
- (void)authenticateWithUserEmail:(NSString *)pUserEmail
withUserPassword:(NSString *)pUserPassword {
NSString *loginURL =
#"https://mydomain/login";
AFHTTPRequestOperationManager *manager =
[AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager.requestSerializer
setAuthorizationHeaderFieldWithUsername:pUserEmail
password:pUserPassword];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
AFHTTPRequestOperation *operation = [manager GET:loginURL
parameters:[self jsonDict]
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success");
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure");
}];
[operation start];
}
- (IBAction)btnAuthenticate:(id)sender {
[self authenticateWithUserEmail:self.userEmail.text
withUserPassword:self.userPassword.text];
}

Because the network call is performed asynchronously, you can't simply return a BOOL because the method returns as soon as you call [operation start];, at which point the network call hasn't completed. What you need to do is add a block parameter to your method that get's invoked in the completion or failure block of the AFHTTPRequestOperation So your method signature will look like this:
- (void)authenticateWithUserEmail:(NSString *)pUserEmail
withUserPassword:(NSString *)pUserPassword
completion:(void (^)(BOOL success))completionBlock;
In this method, add to your success/failure blocks to invoke your new block parameter. Like so:
AFHTTPRequestOperation *operation = [manager GET:loginURL
parameters:[self jsonDict]
success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (completionBlock) {
completionBlock(YES);
}
NSLog(#"Success");
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (completionBlock) {
completionBlock(NO);
}
NSLog(#"Failure");
}];
And your invocation of this method will now look like this:
- (IBAction)btnAuthenticate:(id)sender {
[self authenticateWithUserEmail:self.userEmail.text
withUserPassword:self.userPassword.text
completion:^(BOOL success) {
if (success) {
//login successful, do stuff
} else {
//login failed, do other stuff
}
}];
}
This generally how to handle responding to asynchronous events, since you can't return something that hasn't been determined yet.

Related

How to get the redirected URL using AFNetworking?

I use AFNetworking get method, the url is something like :
http://www.hi-pda.com/forum/redirect.php?from=notice&goto=findpost&pid=31089630&ptid=1631932
using chrome I can see the true URL is :
It is in the location .
How can I get the url when using AFNetworking , I tried the following method, it does not work
[
manager GET:threadNotice.URLString
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"%#",[operation.response allHeaderFields]);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}
];
The response is
2015-05-31 00:11:03.349 HiPDA V2[20006:751020] {
Connection = "keep-alive";
"Content-Encoding" = gzip;
"Content-Type" = "text/html";
Date = "Sat, 30 May 2015 16:10:59 GMT";
Server = "nginx/1.6.2";
"Transfer-Encoding" = Identity;
"X-Powered-By" = "PHP/5.3.10";
}
no location field,how can I get that? thank you.
I solved the answer used the following method:
AFHTTPRequestOperation *requestOperation=[[AFHTTPRequestOperation alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:_URLString]]];
[requestOperation setRedirectResponseBlock:^NSURLRequest *(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse) {
if (redirectResponse) {
//this is the redirected url
NSLog(#"%#",request.URL);
}
return request;
}];
[requestOperation start];

Mapping response from POST without nested KVC

I am trying to map attributes to a class in RESTKit without a nested KVC and without much luck i keep getting nil for my values even though the response contains values.
I have read over the object mapping manual and tried it with path patterns without path patterns etc. Does anyone have any insight?
Request and Response from server
2014-06-16 15:58:07.162 game[5961:60b] T
restkit.network:RKObjectRequestOperation.m:178 POST 'https://api.myURL.com/api/0_0_1/notify/player':
request.headers=
{
Accept = "application/json";
"Accept-Language" = "en;q=1, fr;q=0.9, de;q=0.8, zh-Hans;q=0.7, zh-Hant;q=0.6, ja;q=0.5";
"Content-Type" = "application/json; charset=utf-8";
"User-Agent" = "game/1470 (iPhone; iOS 7.1; Scale/2.00)";
}
request.body=
{
"game":"539e75acadae8fb03900057e",
"to":"533bd7eb5317b88f61000006",
"message":"‎Ben Fowler is waiting for you to play the game",
"from":"5332b4f5edfc9beb7900004d"
}
2014-06-16 15:58:08.856 game[5961:5607] T restkit.network:RKObjectRequestOperation.m:248 POST 'https://api.myURL.com/api/0_0_1/notify/player' (200 OK / 1 objects) [request=1.6911s mapping=0.0020s total=1.6989s]:
response.headers={
Connection = "keep-alive";
"Content-Length" = 42;
"Content-Type" = "application/json; charset=utf-8";
Date = "Mon, 16 Jun 2014 07:58:09 GMT";
"X-Powered-By" = Express;
}
response.body=
{
"result": 1,
"notify": "871720292"
}
The class being mapped
-(void)WtfGameNotifcationResponse
{
RKObjectMapping *notifyMapping = [RKObjectMapping mappingForClass:[WTFGameNotification class]];
[notifyMapping addAttributeMappingsFromDictionary:
#{
#"result" : #"result",
#"notify" : #"notifyID",
}];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:notifyMapping
method:RKRequestMethodGET
pathPattern:#"notify/player"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[RKObjectManager sharedManager] addResponseDescriptor:responseDescriptor];
}
The class in question
#interface WTFGameNotification : NSObject
#property (nonatomic,copy) NSString* to;
#property (nonatomic,copy) NSString* from;
#property (nonatomic,copy) NSString* gameID;
#property (nonatomic,copy) NSString* message;
#property (nonatomic,strong) NSNumber* result;
#property (nonatomic,copy) NSString *notifyID;
+ (WTFGameNotification*)Create;
#end
It seems that if you are trying to map a response from a POST this is the method and syntax one should use.
+ ( void )SendNotification:(GameInfo*)gameInfo withMessage:(NSString*)message forView:(UIViewController*)view
{
WTFGameNotification *_wtfGameNotif = [WTFGameNotification Create];
[_wtfGameNotif setTo:[gameInfo opponentWTFID]];
[_wtfGameNotif setFrom:[PlayerWTFInfo Load]._wtfID];
[_wtfGameNotif setGameID:[gameInfo gameID]];
[_wtfGameNotif setMessage:message];
if ([_wtfGameNotif to] && [_wtfGameNotif gameID])
{
RKObjectRequestOperation *operation = [[RKObjectManager sharedManager] appropriateObjectRequestOperationWithObject:_wtfGameNotif
method:RKRequestMethodPOST
path:nil
parameters:nil];
RFResponse *r1 = [RFResponse new];
operation.targetObject = r1;
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)
{
if (r1.result.integerValue != 0)
{
[Utilities FacebookPostWithResult:#{#"fbId": r1.notify}];
}
}
failure:^(RKObjectRequestOperation *operation, NSError *error)
{
DDLogError(#"POST REQUEST FAILED IN CONFIRMFOTOVC : %#",[error description]);
if (view)
{
[LoadingView PopToRootShutterCloseOnView:view willOpen:YES];
}
}];
[operation start];
}
else
{
DDLogInfo(#"NO PLAYER ID");
}
}
If you are POSTing the object to the server then the response descriptor you have will not match because you link it to a GET with method:RKRequestMethodGET. You need to change that to method:RKRequestMethodPOST.
When using a path pattern of #"notify/player" the base URL should be set to https://api.myURL.com/api/0_0_1/, but it doesn't look like this is an issue for you.

Alert View directs to an empty view controller without buttons

I'm trying to make an alert view so that upon selecting "Yes" (one of the buttons in AlertView), the user is directed to a new view controller with a button which I made via Storyboard. My code for the IBAction is as follows:
- (IBAction)alertButton:(UIButton *)sender
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Welcome Back to SymTrack!" message:#"Did you have reoccuring symptoms?" delegate:self cancelButtonTitle:#"No" otherButtonTitles:#"Yes", nil];
[alert show];
}
This is the code for the clickedButtonAtIndex which gives me the empty view controller without the button:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1)
{
UpdateViewController *updateVC = [[UpdateViewController alloc] init];
[self presentViewController:updateVC animated:YES completion:nil];
}
}
I've also tried these other codes for clickedButtonAtIndex but I got NSException for all of them:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1)
{
UpdateViewController *updateVC = [self.storyboard instantiateViewControllerWithIdentifier:#"UpdateViewController"];
[self presentViewController:updateVC animated:YES completion:nil];
}
}
or
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1)
{
UpdateViewController *updateVC = [self.storyboard instantiateViewControllerWithIdentifier:#"UpdateViewController"];
UINavigationController *alertNC = [[UINavigationController alloc] initWithRootViewController:updateVC];
[self presentViewController:updateVC animated:YES completion:nil];
}
}
note: all this code is within the view controller with the button that upon clicking brings the alert view up.
Thanks in advance!

Getting user specified information from URL in Objective C iOS

Currently I am working with a UIWebview which shows web content provided from a user. In this content there will be links to other web content and I need to decide whether to open links in safari or in the UIWebview.
My current solution is to add a queryString to the URL in the html e.g. <a href=http://www.w3schools.com?StayInApp target=_blank>Visit W3Schools</a>
When the user presses the link the following method in the UIViewController decides how to open the link.
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = [request URL];
NSLog(#"%#",url);
NSLog(#"%#",[url scheme]);
NSLog(#"%#",[url user]);
NSLog(#"%#",[url query]);
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
if ([[url query]isEqualToString:#"OutOfAppApp"]) {
NSLog(#"go out");
[[UIApplication sharedApplication] openURL:url];
return NO;
}
else if([[url query]isEqualToString:#"StayInApp"])
{
return YES;
}
}
return YES;
}
I do not have very much experience within web development and can therefore not see the consequences of using this approach. Is this a valid approach or should I use another way?
Regards
EDIT:
I have now come up with another approach using custom URL schemes, but I would still like comments on whether this is a valid solution :)
I have added a prefix to the links such as <a href=InAPP:http://www.w3schools.com target=_blank>Visit W3Schools</a>
When a user presses a link the app examines the prefix and decides whether to launch the rest of the url in the app or in safari. This is done with the following methods:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = [request URL];
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
if ([[url scheme]isEqualToString:#"InAPP"]) {
NSLog(#"go in");
NSURLRequest *req=[NSURLRequest requestWithURL:[self removeExtensionFromURL:url]];
[[self browserView] loadRequest:req];
return NO;
}
else if([[url scheme]isEqualToString:#"OutAPP"])
{
NSLog(#"go out");
[[UIApplication sharedApplication] openURL:[self removeExtensionFromURL:url]];
return NO;
}
}
return YES;
}
-(NSURL*)removeExtensionFromURL:(NSURL*)url
{
NSMutableString *urlString=[NSString stringWithFormat:#"%#",url];
NSString *newURLString;
if ([[url scheme]isEqualToString:#"InAPP"]) {
newURLString = [urlString stringByReplacingOccurrencesOfString:#"InAPP:" withString:#""];
}
else if([[url scheme]isEqualToString:#"OutAPP"])
{
newURLString = [urlString stringByReplacingOccurrencesOfString:#"OutAPP:" withString:#""];
}
return [NSURL URLWithString:newURLString];
}

iOS 5.0 ignoring NSSetUncaughtExceptionHandler?

I've noticed some strange behavior in iOS 5: NSSetUncaughtExceptionHandler() doesn't seem to do anything anymore.
I have the following code:
static NSString* documentsDirectory()
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
static void handleException(NSException *exception)
{
// Write something to the documents dir
NSString* path = [documentsDirectory() stringByAppendingPathComponent:#"crashlog.txt"];
NSString* str = #"Handled exception";
NSError* err;
if(![str writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&err])
{
NSLog(#"Failed to write to file");
}
NSLog(#"Handled exception");
}
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSSetUncaughtExceptionHandler(&handleException);
[NSException raise:#"Test" format:#"Testing"];
...
}
The above code works on any device or simulator running 4.x or earlier. However, when I run it on the 5.0 simulator, the exception handler doesn't get called (doesn't write the file to the documents dir, doesn't log, and doesn't trigger if I set a breakpoint inside the handler).
Unfortunately, I don't have a 5.0 device available for testing, so I'm hoping someone could confirm that it's broken on 5.0 so I can file a bug report (or correct me, if there's a problem with my code).
Use iOS 6.0 SDK, build and run it on simulator 5.0! It works!
//////Code:
static NSString* documentsDirectory()
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
static void handleException(NSException *exception)
{
// Write something to the documents dir
NSString* path = [documentsDirectory() stringByAppendingPathComponent:#"crashlog.txt"];
NSString* str = #"Handled exception";
NSError* err;
if(![str writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&err])
{
NSLog(#"Failed to write to file");
}
NSLog(#"Handled exception");
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSSetUncaughtExceptionHandler(&handleException);
[NSException raise:#"Test" format:#"Testing"];
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.viewController = [[[NSSetUncaughtExceptionHandlerTestViewController alloc] initWithNibName:#"NSSetUncaughtExceptionHandlerTestViewController" bundle:nil] autorelease];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
//////Terminal log:
2012-10-09 20:06:24.726 NSSetUncaughtExceptionHandlerTest[7815:c07] Handled exception
2012-10-09 20:06:24.727 NSSetUncaughtExceptionHandlerTest[7815:c07] *** Terminating app due to uncaught exception 'Test', reason: 'Testing'
*** First throw call stack:
(0x14a4052 0xea4d0a 0x144ca78 0x144c9e9 0x29d7 0x129d6 0x138a6 0x22743 0x231f8 0x16aa9 0x138efa9 0x14781c5 0x13dd022 0x13db90a 0x13dadb4 0x13daccb 0x132a7 0x14a9b 0x28b2 0x27e5)
terminate called throwing an exception(lldb)
I'm seeing the same thing. It works on my iPad, but not in the simulator. If someone confirms on the phone, please feel free to edit this answer to reflect that.