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];
Related
With iOS8, I noticed that a view controller was no longer receiving a UIKeyboardWillSHowNotification, when it previously was with iOS7.
Here's the scenario:
1.) View Controller A is displaying a keyboard, and pushes View Controller B without resigning first responder
2.) View Controller B has a control that becomes first responder during its viewDidLoad call, while it's being created by VCA, before it's pushed onto the nav controller
3.) If VC A is NOT displaying a keyboard when pushing B, the notifications work fine. However, if A is still editing when pushing B, then B does not get a keyboard will show notification.
Without the keyboard notification, VC B is not resizing / repositioning and does not look right.
The workaround I'm using until I find a solution is to do the following from any view controllers that might be editing when pushing another view controller that might be editing:
i.e., before pushing another view controller, be sure to call:
[self.view endEditing:YES];
While it works, it doesn't seem good that the view controller (B) can be 'broken' by the state of the app prior to displaying it.
Question: Am I doing something wrong here?
As far as I can tell, one of 3 things are possible:
A.) I should be getting the notifications, but I'm not b/c I'm doing something wrong
B.) I should be getting the notifications, but I'm not b/c of a bug
C.) I can't rely on always getting the notifications...But if I don't get the notifications in VC B when it appears, I need to be able to get the keyboard dimensions of the displayed keyboard without relying on the keyboard notification info. All the apple docs say to use the notifications though (as far as I can find).... which points back to options A.) or B.).
I can create and upload sample code later tonight / early tomorrow to try and isolate / for you all to test/reproduce to see what I'm doing.
I can see the same issue with iOS8 / xCode6 (works with iOS7 and xCode5). In my case, I'm observing a systemStatus property on the model in my AppDelegate so as to log the user out and bring the user back to the login screen when the user logs out from anywhere in the app. I'm doing that by setting the window.rootViewController to the loginViewController in my App Delegate observeValueForKeyPath: method.
This works fine on iOS7 / xCode5 but on iOS8 / xCode6, I loose the keyboard in the way. Looks like my loginViewController might be registering for keyboard notifications (in its ViewWillAppear method) before the window's rootViewController switch is complete (in iOS8) thus registering to the old window's notification center...
I moved the registration for keyboard notifications to the ViewDidAppear: method instead and that seems to fix it but somehow this seems to be called twice for some reason.
When subclassing PFLogInViewController for customization. How do I change the size of the view?
I have looked at this tutorial: https://parse.com/tutorials/login-and-signup-views
but it does not seem to have the answer.
My app is based on a UITabBarController and one of the tabs needs log in.
Nevertheless if the user cannot log in, he should still be able to use the other tabs.
In the present situation, when the user taps on the tab asking for login; he has to log in or kill the app to get out. Because the PFLogInViewController takes up all the screen and there is no way out by hitting a different tab (all covered).
This is obviously not very nice.
How can I keep the tabs at the bottom visible?
I tried to change the self.view.frame or the self.logInView.frame in the viewDidLoad method of my PFLogInViewController subclass, but it seems to have no effect at all.
Then you should make your app so that it doesn't start with the login viewcontroller, but rather opens to the parts that are available to all. Include some button or other mechanic to take the user to the login page.
You could include a button on the login page that says "Use the app anonymously" or similar, which triggers a segue to a main view. On subsequent app launches, the user is taken to this main view immediately. You would still need a way for the user to login later on.
I have an iPad app that uses a UIPopover from within a UIVIew; I need to show an alert-type message when a certain condition has been met.
The problem is using a UIAlertView from within the UIPopover, when the user taps on a button in the UIAlertView, it also dismisses the UIPopover, which defeats the purpose of the alert.
I tried using UIActionSheets, but they don't display at all, probably because they are not being called from a controller-type view.
Is there a way to circumvent this behavior?
No, and you shouldn't do that. Popovers are supposed to go away as soon as you touch anything else.
You could enlarge the popover slightly and make room for a status message. When the user creates an appointment that overlaps, you could display a message in the status area.
Or, you could dismiss the popover and display an alert with "ok"/"cancel" buttons. The OK button would create the overlapping appointment, and the cancel button would discard it.
You will need some place to save the info from the popover while you are waiting for the user to decide what to do with the alert. Perhaps have the popover pass a message back to the view controller it comes from, and then have the source view controller create the alert, set itself as delegate, and handle the responses from the user.
According to Apple's Human Interface Guidelines, it is OK to display a UIAlertView on top of a popover:
https://developer.apple.com/library/ios/documentation/userexperience/conceptual/MobileHIG/Alerts.html
To quote specifically:
On iPad, don’t display a modal view on top of a popover. With the
possible exception of an alert, nothing should display on top of a
popover.
Displaying a UIAlertView from a popover does not automatically dismiss the popover. There is likely some of your own code being executed which is causing it to dismiss. For example, in a similar situation I had, I found that displaying a UIAlertView was invoking "shouldAutorotate" in my split view controller, and (due to earlier iOS bugs) I had placed code there to dismiss the popover. For iOS7+ this was no longer necessary, so I was able to move this code into willRotateToInterfaceOrientation, where it no longer causes dismissal of the popover upon display of UIAlertView, because in this case, even though "autoRotate" gets called "willRotateToInterfaceOrientation" does not.
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.
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.