I need to protect my application from taking screenshot before going to background. I have added a black view in applicationDidEnterBackground:. But when I check background applications in iOS7 simulator it is not showing the black image instead it shows the application itself as shown in image. How can I solve this? If I get notified before app goes background this problem might be solved. Any help would be greatly appreciated.
The best way to achieve the functionality you want throughout your entire app is making your app navigate to an entirely black UIViewController. This so you cannot see anything when you long press on the homebutton and see the background applications.
These 2 functions will do the trick:
- (void) applicationDidEnterBackground:(UIApplication *)application
{
//navigate to the black view controller
BlackViewController *controller = [[BlackViewController alloc] init];
[yourNavigationController pushViewController:viewController animated:yourAnimationSettings];
[controller release];
}
- (void) applicationWillEnterForeground:(UIApplication *)application
{
//pop the black view controller so the user won't be bothered with it
if(/*Check if your BlackViewController is the top of your navigationController stack*/)
{
[yourNavigationController popViewControllerAnimated:yourAnimationSettings];
}
}
You'll get a callback in AppDelegate's applicationDidEnterBackground
Related
I am using an UIActivityViewController. When the user sends my application to the background on the iPhone (when they press the home button, etc) I need to remove the spawned UIActivityViewController and any children that may have come from it. This is to say that if the user selects the "Mail" or "Message" option on the UIActivityViewController I need to remove the view (view controller?) that spawns as a result of this action.
I have tried the following code by found that it only removes the original UIActivityViewController and none of the additional views it spawned.
[_myActivityController dismissViewControllerAnimated:NO completion:nil];
Try this in your appDelegate applicationDidEnterBackground. Dismiss the top most view controller which is presented. Hope this will help you out.
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIViewController *mytopController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (mytopController.presentedViewController)
{
mytopController = mytopController.presentedViewController;
[mytopController dismissViewControllerAnimated:NO completion:nil];
}
}
In storyboard I have a button on my Main Menu called showCountdownViewControllerPressed.
This button is supposed to show my XIB called TimerViewController.
But when I run the app, it freezes upon button press and then after a little while crashes the app.
I put this action in my CRViewController.m (my main menu) [I also have imported the TimerViewController.h in this file]
- (IBAction)showCountdownViewControllerPressed:(id)sender {
NSLog(#"showTimerViewController");
TimerViewController *timeController = [[TimerViewController alloc]
initWithNibName:#"TimerViewController" bundle:nil];
[self presentViewController:timeController animated:YES completion:nil];
That's not the answer to your problem but it can help. I'm putting it here because I can't add images on the comments. You can put an exception breakpoint at the bottom of the breakpoints tab, normally it will stop just before the crash and you will get more info about it.
Post where the exception breakpoint it's stopping for getting more help :)
Well, if it is LandScape only, you can add this in TimerViewController for iOS 8, which will make the TimerViewController rotate to the landscape mode.
- (BOOL)shouldAutorotate
{
return YES;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationLandscapeLeft;
}
I've tried my app on iOS 7.1 and I found that the tab bar background disappears on a few occasions. I was able to track them down; it happens when:
pushing a view controller placed inside navigation controller (that is inside tab bar controller) with hidesBottomBarWhenPushed = YES
presenting a view controller and then dismissing it (i.e. the MFMailComposeViewController)
I've created a sample app (used the tab bar template + added button to display the view controller, and a mapView to be able to tell if the bar disappeared), and the issue is there.
Here is all the code for the sample app that I changed:
#import "FirstViewController.h"
#import MessageUI;
#interface FirstViewController () <MFMailComposeViewControllerDelegate>
#end
#implementation FirstViewController
- (IBAction)presentVCButtonPressed:(id)sender {
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
[mailer setSubject:#"Feedback for Routie"];
[mailer setToRecipients:#[#"support#routieapp.com"]];
[self presentViewController:mailer animated:YES completion:nil];
}
}
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
Here you can download the whole sample project.
Now, important thing: this seems not to affect iPhone 5, nor the simulator. The problem is on iPhone 4 and iPod Touch (last generation as of writing this post).
Does any of you have the same problem? Were you able to fix it?
Thanks!
Update: I found a workaround. See my answer below.
Fix found!
So after some investigating (and headache), I found out that there is a simple fix. Just toggle the translucent property, like this:
tabBar.translucent = NO;
tabBar.translucent = YES;
Now as for when to do this, there are several places for each case:
1) pushing viewController with hidesBottomBarWhenPushed = YESThe bar background disappears right after the pop animation finishes, so add the fix to the viewDidAppear: method of the viewController that presented it:
- (void)viewDidAppear:(BOOL)animated {
self.navigationController.tabBarController.tabBar.translucent = NO;
self.navigationController.tabBarController.tabBar.translucent = YES;
...
}
2) Presenting a view controller and then dismissing it:In this case, the tab bar background is already gone during the dismiss animation. You can either do it in each viewController that you present separately, or, if you have subclassed UITabBarController (like I have), you can add it into its viewWillAppear method. Just be aware that calling the fix right away won't help (I've tried); that's why I used the dispatch_after GCD function:
- (void)viewWillAppear:(BOOL)animated {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.tabBar.translucent = NO;
self.tabBar.translucent = YES;
});
...
}
I know this is not the cleanest way, but it's clearly bug on Apple's side, and it's likely to stay with us for a while (I assume there won't be any iOS 7.2, so we'll most likely be stuck with this until iOS 8 comes out).
It's been a while, so I'll re-iterate the issue. iOS 7 (on Device) Tab Bar becomes completely see-through on device, but works fine on Simulator. Appears to happen after hitting Back from a detail page that has hidesBottomBarWhenPushed enabled.
Setting the Tab Bar Controller > Tab Bar > Background to White Color in the Storyboard fixed it for me. This fix keeps the translucency intact.
For some reason, toggling tabBar.translucent off and on again in ViewDidAppear did not work for me.
Using Xcode 6.3.1 with Swift.
Go in your Main.storyboard and select your MKMapView to highlighted it (cf. in Navigator area you can select « Map View »). Then look carefully where is the bottom "white square": move it up the bottom bar!
In the size inspector, you can check where you place the « anchor » or view origin for this view (cf. top-left hand side in your project). This explains why it’s ok for iphone 5 which has a bigger height screen.
I'm trying to create an iOS (iPhone specific) app where users have to authenticate before accessing the rest of the app. I'm using a Storyboard for the main application which looks like this (broken up into separate lines):
(1) -> NavigationController
(2) -(o-o)-> OfficesViewController
(3) -[<-]-> OfficeViewController
I also have a separate XIB file called ScanOverlayViewController which gets programmatically pushed by the OfficeViewController when a user presses on a button. Not sure if it's proper to have Storyboards and XIBs mixed in like this, but it's been working so far.
Anyway, back on topic, I want to put an authentication screen infront of the NavigaitonController, but I'm not sure how.
I've tried placing an unlinked view in the Storyboard and setting it as the initial view. I then placed a hidden button and made a segue to the NavigationController. In code I tried having the controller perform the segue but the seque wasn't actually being performed even though the view had appeared properly.
I then tried to make the authentication view it's own separate XIB and initializing the controller in the app delegate and setting its view as a sub view of the app delegate. That just resulted in the app going directly to the OfficesViewController view as if I hadn't done anything.
Is there a specific way of doing this properly so it works with Storyboards?
Thanks in advance!
UPDATE
Here's my current app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
AuthenticationViewController *authenticationViewController = [[AuthenticationViewController alloc] initWithNibName:#"AuthenticationViewController" bundle:nil];
if (authenticationViewController) {
NSLog(#"Should have generated %#", authenticationViewController);
};
[[[application keyWindow] rootViewController] presentModalViewController:authenticationViewController animated:YES];
return YES;
}
The controller does get allocated and initialized, but it's just not showing up.
Have the NavigaitonController as your initial view controller, then present the authentication screen modally if required. You can do this in -application:didFinishLaunchingWithOptions:.
Mixing XIB files and storyboards is fine, storyboards get turned into XIB (or nib) files anyway, they just have some extra meta data. Mix and match as makes sense.
E.g.:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([self needsAuthentication])
{
dispatch_async(dispatch_get_main_queue(), ^{
AuthVC *authVC = [[AuthVC alloc] init];
[[UIWindow keyWindow].rootViewController presentModalViewController:authVC animated:YES];
});
}
// anything else
return YES;
}
I have a login screen and what I want to do is to detect whether the user is already logged in and eventually popup a modal.
I created a custom segue that shown the modal with no animation.
#implementation NonAnimatedSegue
-(void) perform {
[self.sourceViewController presentModalViewController:self.destinationViewController animated:NO];
}
The thing is that calling this segue from viewDidLoad or viewWillAppear takes no effect. If I call it from viewDidAppear, the login screen flicks for a while before the modal opens.
Any idea how to solve this?
The way I got around this problem was to check in the application finished launching and set the root view controller as needed. Like so:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
/*stuff*/
/*get the view controller from storyboard/nib*/
[self.window setRootViewController:CorrectViewController];
}
It wouldn't show a modal view but just show the login on launch.