Covering the root view with another immediately upon launch or resume - objective-c

I'm trying to build a security app that prompts the user to enter a passcode before allowing access to the application. This is done on the first launch or when the application is resumed.
Right now, I'm using a view controller, PasscodeViewController, which is presented modally on application launch or resume, i.e., in the app delegate:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if (!self.passcodeViewController.view.window)
[self.window.rootViewController presentViewController:self.passcodeViewController animated:NO completion:NULL];
}
The problem is that the main view controller's view is flashed momentarily before the PasscodeViewController is presented. This is a security risk because the user can quickly get a glimpse of the data before being asked to enter a passcode.
How do you solve this? How do programs like DotLockData, and other security programs, implement such a feature?

Seems it would be better to do that sort of thing on suspend rather than resume. Perhaps in applicationWillResignActive

Related

MBProgressHUD blocking user interaction

My application has a MBProgressHUD on the screen while the CLLocationManager is getting the user current location at a separate thread in the background. Sometimes the location process start to take so long and obviously I would like to let the user decide to leave or not the screen. The problem is that the User Interface seems to be blocked by the MBProgressHUD so the user can't press the back button.
Is there any implementation design to solve this problem?
In order to achieve a non-modal behavior, simply disable the user interaction on the MBProgressHUD so that the touches will fall through it.
Objective-C
theHUD.userInteractionEnabled = NO;
Swift 4.x
theHUD.isUserInteractionEnabled = false

Modal UINavigationController hides although not dismisses

Okay, so I'm building an universal iOS app with an initial login view (view controller named LoginVC), just a plain simple UIViewController. If the login is successful the app segues to an navigation controller (MainNavigationVC). I created this segue through the storyboard gui of XCode, so no programmatic creation of the nav controller is done. The nav controller is presented modally in fullscreen, so the rest of the app is run atop the login view, with this nav controller as the centerpiece of everything.
The navigation controller contains a view (with a view controller named UserStartPageVC), and in its navigation bar is a logout button. This button sends an target action to UserStartPageVC, with the goal of dismissing the nav controller thus bringing the user back to the login view.
So far everything works fine. I can login and use the app as intended. But! When I log out and then re-login XCode tells me this:
Warning! Attempt to present <MainNavigationVC: 0x753110> on
<LoginVC: 0x756fcf0> while a presentation is in progress!
I suppose this means that the login view is trying to modally display a MainNavigationVC navigation controller, but another one is already displayed, right? But how? Can a view be presented without showing?
And how can I get rid of the old nav controller when logging out? I've tried several ways of dismissing the modal view, for instance:
from within UserStartpageVC running
[x dismissViewControllerAnimated:YES completion:NULL]
[x dismissModalViewControllerAnimated:YES]
where x is either self, self.parentViewController or self.presentingViewController.
setting the LoginVC as a property in UserStartpageVC and running
[self.loginVC dismissViewControllerAnimated:YES completion:NULL]
and so on.
All of the tested calls actually brings me back to the login screen, so it's kind of working.
Any ideas? Relevant code samples can be provided if necessary, I just couldn't figure out which pieces that were of interest. The seguing to the navigation controller has no code (except for a performSegueWithIdentifier:sender:), and the code for dismissing it is the part I cannot seem to get straight.
As a sidenote. So far this isn't a REAL problem; the app runs, and it IS possible to logout and re-login without any other side-effects than an error message in XCode. But I suppose this will be a memory leak if users logout and login multiple times, and I'm not in the mood of an unnecessary rejection from Apple.
I discovered another way to get the exact same error message. Lucky me!
If you created a segue at one point and had it tied to a button (click button -> new view) and then later give that segue a name and invoke it directly using
[self performSegueWithIdentifier:#"identifierName" sender:self];
then you can get this error because you can effectively trigger the segue twice. I thought making the button invoke an IBAction would turn off the segue I had set up in the first place, but apparently not. Hitting the button triggered the segue twice, but after I deleted the segue and re-created it as a manual segue on the view with the same identifier then I was able to invoke it via the above code and not get the warning message.
Hoopla! My bad.
Seemed I had set up the notification observing from the login API call in a stupid way. For every time the user triggered a login (or re-login), it added itself as an observer for the notification; the result was that it performed one more segue for every time a login was done.
And doing multiple segues at the same time, is... well, obviously bad.

iOS Objective-C: Unbalanced calls to begin/end appearance transitions for <GKModalRootViewController>

I was hoping someone would be able to answer my question.
In my app I have a button you can press that takes you a leaderboard I have created. In the sandbox environment, the first time a user clicks on this the user is asked to sign in - with an existing account or a new account.
If a user clicks on use existing account, after verifying their username, password, GameCenter display name and so forth, when the screen closes to go back to the screen with the leaderboard button - none of the buttons will now respond. The user is forced to quit the app (and the instance through the double-click of the home button) and reopen the app, where now they can play as usual and even click on the leaderboard with no problems.
I was wondering why this was, and the only clue I seem to have is through the output screen in Xcode which says while running:
ClubHistory[4989:707] Unbalanced calls to begin/end appearance transitions for <GKModalRootViewController: 0x1bcd90>.
From looking up other questions it seems this might mean a clash of opening/closing views. But I don't really understand where I should implement this.
Part of the code which opens the leaderboard in the first instance is:
-(void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController
{
[self dismissModalViewControllerAnimated:YES];
}
-(IBAction ) showLeaderboard
{
GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc]init];
if (leaderboardController != NULL)
{
leaderboardController.category = self.currentLeaderBoard;
leaderboardController.timeScope = GKLeaderboardTimeScopeWeek;
leaderboardController.leaderboardDelegate = self;
[self presentModalViewController: leaderboardController animated:YES];
}
}
Perhaps the alteration I need to make is made here.
I had a look online for similar problems to no avail. Does anyone know how I can solve this issue?
Thanks everyone,
Andy.
///// Quick edit: Just to clarify I have ARC turned on for my app.
[...] the first time a user clicks on this the user is asked to sign in - with an existing account or a new account
How are you presenting this interface for the user to sign in? Is it also a Modal View Controller? If this is the case, maybe you're not presenting and dismissing these two Modal View Controllers properly. From Apple's docs:
Any view controller object can present a single view controller at a time.
Try dismissing the View Controller with the sign in interface before presenting the GKLeaderboardViewController.

UIAlert during splashcreen

This is a two part question.
I have created a user agreement that the user must agree to when first launching the app (it is an alert with some information and agree/ do not agree button)
I call upon the method that creates this alert inside myAppDelegate.m and within the method
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
The problem is the alert pops up when the splash screen has finished loading and my first view comes up. I want this to happen during the splash screen. How would I do this?
The second question is When the users presses the "Do not agree button", I want them to exit the app so I have programmed it with
exit(0);
Is there a better way and will apple reject my app because of this?
Thanks in advance
1) You can't -- during the splash screen (your default.png) the app is loading into memory, and it cannot therefore execute any code, including presentation of a UIAlertView. That's why you don't see the alert until the splash disappears -- removal of the splash screen is the last thing that the app does before calling applicationDidFinishLoading:withOptions:.
What you can do is create a view controller that mimics your splash screen. This is easy -- you can even reuse default.png as a background if you want, though a better idea is just to present in this first view controller your agreement text and agree/disagree buttons.
As to your question re: use of exit(), it's best to avoid doing that. If the user refuses, you can simply do nothing. Of course, if you go the view controller route as I suggest, you can leave presented another opportunity for the user to agree.
Another thought is that Apple allows you to customize the EULA of your app when you upload a binary -- you could put it there and be covered.
Why not load our default.png as the background of you initial view and just handle the Alert in it's controller. you can always add another view or segue based on the answer.
The problem is the UIAlert blocks the Main thread, so it could stop your app from launching in time, and the process could be terminated.

Fullscreen ad causing keyboard to not appear

My iOS app sometimes displays a Greystripe fullscreen ad on startup. If this ad shows, then when I dismiss it, later I will tap a textfield in a UIWebView but the keyboard won't show up. However, if the Greystripe ad DOESN'T appear, then all is well and the keyboard will show up as expected.
After doing some research I think it has something to do with Greystripe making itself the first responder, but I'm not sure how to fix this.
Edit:
I use adwhirl and so to get the startup ad I do exactly as it says here: http://wiki.greystripe.com/index.php/AdWhirl
The UIWebView is inside another controller that is presented with presentModalViewController:animated: from the main view.
I narrowed the problem down: the problem is caused after initiating Greystripe, which occurs either from the full screen startup ad that I initiate manually or from AdWhirl automatically initiating it to display a 320x50 Greystripe banner.
After hours of debugging I finally figured it out. I use SVProgressHUD to show loading status while my UIWebView is loading. SVProgressHUD.m makes itself the key window, then when it is dismissed, it returns the key window status to the "topmost" window. For some reason Greystripe, unlike all the other ad networks I'm using, makes itself the topmost window. So the problem could be Greystripe making itself too important, or SVProgressHUD miscalculating the topmost window!
To solve this, I had to manually make my view controller which contains my UIWebView the key window every time after dismissing SVProgressHUD:
[SVProgressHUD dismiss];
[self.view.window makeKeyWindow];