Custom UIViewController add issue - ios

I Created a UIViewController that I want to add on the top of all of my views, the problem is that it's visible for only 1 sec and then disappears from the screen and deallocated. Why this is happening?
This is my code:
- (void)show
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.windowLevel = UIWindowLevelAlert;
self.window.screen = [UIScreen mainScreen];
[self.window makeKeyAndVisible];
UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
[mainWindow setUserInteractionEnabled:NO];
[self.window addSubview:self.view];
self.view.alpha = 0.0f;
self.backgroundImage.image = [self takeSnapshot];
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.view.transform = CGAffineTransformIdentity;
self.view.alpha = 1.0f;
} completion:nil];
}
- (void)dealloc
{
NSLog(#"Screen deallocated.");
}

Looking at the graph of your objects,I assume self is some view controller.
your self.view is subview of Appdelegates UIWindow. When you do
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
your Appdelegate window gets released subsequently your view controller(self) will also be released.
So I would suggest you to retain UIWindow instance before actually releasing it.

You must save variable for your UIViewController in that place from where "show" method was called. For example - just create property…
#property (nonatomic, strong) CustomViewController *cvc;
Otherwise instance of your UIViewController will be released at the end of that method. Because your object won't have any strong references…

If you work with XIB, you can use this code: You have to create an UIView class, for example HeaderView. In your UIViewController [ I will call it BaseViewController] .h you have to add a property:
#property (nonatomic, strong) HeaderView *headerView;
and in .m you have to add this code:
- (id)init {
self = [super init];
if (self) {
[self configureMenuView:self];
}
return self;
}
- (void)configureMenuView:(UIViewController *)vc {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"HeaderView" owner:self options:nil];
for( id currentObject in topLevelObjects)
{
if([currentObject isKindOfClass:[HeaderView class]]) {
self.headerView = (BannerView *)currentObject;
self.headerView.frame = CGRectMake(0, 0, 768, 1024);
self.headerView.backgroundColor = [UIColor clearColor];
[vc.view addSubview:self.headerView];
break;
}
}
[self.bannerView.closeHeaderButton addTarget:self action:#selector(closeHeaderrView) forControlEvents:UIControlEventTouchUpInside]; // it's only an example if you want add some button in your header.
So, in every view controller you have to import this class: BaseViewContoller and to add it like parent:
#interface TestViewController : HeaderViewController
Hope it works for you :)

Related

UINavigationBar with UISegmentedControl partially covers childViews

I have read many other threads on this and the Apple docs, but haven't found a solution yet for my particular problem.
My app uses a UITabBarController as the rootViewController, and in one of the tabs I have a UISegmentedControl in the navigationBar to switch between three child UITableViewControllers.
(In the real app two of the childVCs are a custom UIViewController, I'm just using three UITableViewControllers for the sample app).
The segmentedControl setup and the switching all works fine. The thing that goes wrong is that only the first UITableViewController is shown correctly. For the second and third one, part of the first cell is hidden under the navigationBar. When I click through all three, the first one is still ok.
I have made a little sample app to show what's going on, using very bright colors for demonstration purposes: https://www.dropbox.com/s/7pfutvn5jba6rva/SegmentedControlVC.zip?dl=0
Here is also some code (I'm not using storyboards):
// AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
FirstViewController *fvc = [[FirstViewController alloc] init];
UINavigationController *firstNavigationController = [[UINavigationController alloc] initWithRootViewController: fvc];
SecondViewController *svc = [[SecondViewController alloc] init];
UINavigationController *secondNavigationController = [[UINavigationController alloc] initWithRootViewController: svc];
// Initialize tab bar controller, add tabs controllers
UITabBarController *tabBarController = [[UITabBarController alloc] init];
tabBarController.viewControllers = #[firstNavigationController, secondNavigationController];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
// FirstViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.title = #"One";
self.view.backgroundColor = [UIColor orangeColor];
UITableViewController *vc1 = [[UITableViewController alloc] init];
UITableViewController *vc2 = [[UITableViewController alloc] init];
UITableViewController *vc3 = [[UITableViewController alloc] init];
vc1.view.backgroundColor = [UIColor redColor];
vc2.view.backgroundColor = [UIColor blueColor];
vc3.view.backgroundColor = [UIColor greenColor];
self.viewControllers = #[vc1, vc2, vc3];
self.segmentTitles = #[#"Red", #"Blue", #"Green"];
self.segmentedControl = [[UISegmentedControl alloc] initWithItems: self.segmentTitles];
[self.segmentedControl addTarget: self
action: #selector(segmentClicked:)
forControlEvents: UIControlEventValueChanged];
self.navigationItem.titleView = self.segmentedControl;
self.segmentedControl.selectedSegmentIndex = 0;
// set the first child vc:
UIViewController *vc = self.viewControllers[0];
[self addChildViewController: vc];
vc.view.frame = self.view.bounds;
[self.view addSubview: vc.view];
self.currentVC = vc;
}
- (void)segmentClicked:(id)sender
{
if (sender == self.segmentedControl)
{
NSUInteger index = self.segmentedControl.selectedSegmentIndex;
[self loadViewController: self.viewControllers[index]];
}
}
- (void)loadViewController:(UIViewController *)vc
{
[self addChildViewController: vc];
[self transitionFromViewController: self.currentVC
toViewController: vc
duration: 1.0
options: UIViewAnimationOptionTransitionFlipFromBottom
animations: ^{
[self.currentVC.view removeFromSuperview];
vc.view.frame = self.view.bounds;
[self.view addSubview: vc.view];
} completion: ^(BOOL finished) {
[vc didMoveToParentViewController: self];
[self.currentVC removeFromParentViewController];
self.currentVC = vc;
}
];
}
So obviously my question is, why does this happen, and what can I do to fix it?
Edit: adding screenshots.
EDIT: Based on the answer below I changed the code in the animation block to:
[self.currentVC.view removeFromSuperview];
if ([vc.view isKindOfClass: [UIScrollView class]])
{
UIEdgeInsets edgeInsets = UIEdgeInsetsMake(self.topLayoutGuide.length, 0, self.bottomLayoutGuide.length, 0);
[UIView performWithoutAnimation: ^{
vc.view.frame = self.view.bounds;
((UIScrollView *)vc.view).contentInset = edgeInsets;
((UIScrollView *)vc.view).scrollIndicatorInsets = edgeInsets;
}];
}
else
{
vc.view.frame = self.view.bounds;
}
[self.view addSubview: vc.view];
Now it works. I'm going to try this with a custom UIViewController as well.
The issue is that you do not set the correct content inset to each table view. The system attempts to do it for you, but I guess your setup is too complex for it, and it only does it for the first tableview that is loaded in viewDidLoad. In your loadViewController: method, when replacing the currently displayed view, make sure to set both the contentInset and scrollIndicatorInsets to the values of the previous view. I think the system will manage to set the correct insets later, in case you rotate to landscape. Try it. If it doesn't, you will need to do it on your own in viewDidLayoutSubviews.

The right way for creating a custom popup / alert UIView / UIViewController

I've been developing for iOS for quite a while now, but I always got problems with custom alerts / popups, I just don't know what is the right way to add a custom view as a popup on top of all other views in app.
I've checked online and there are several ways to do it, but what is the best way for creating those custom alerts / popups?
There is a CustomViewController class and this is how I've created it and add it as a popup:
Create a new UIViewController
Add a UIView inside the UIViewController's XIB file as a child of self.view (This will hold the popup elements inside)
Add this method inside the UIViewController for presenting the view:
- (void)presentViewController
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.windowLevel = UIWindowLevelStatusBar;
self.window.screen = [UIScreen mainScreen];
[self.window makeKeyAndVisible];
UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
[mainWindow setUserInteractionEnabled:NO];
[self.window addSubview:self.view];
self.view.alpha = 0.0f;
self.backgroundImage.image = [self takeSnapshot];
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.view.transform = CGAffineTransformIdentity;
self.view.alpha = 1.0f;
} completion:nil];
}
Add this method inside the UIViewController for removing the view:
- (void)dismissShareViewController
{
[UIView animateWithDuration:DEFAULT_ANIMATION_DURATION
animations:^{
self.view.alpha = 0.0f;
} completion:^(BOOL finished) {
[self.view removeFromSuperview];
self.window = nil;
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
[mainWindow setUserInteractionEnabled:YES];
}];
}
Usage:
Creating a property for the UIViewController
#property (strong, nonatomic) CustomViewController *viewController;
Initialize and present
- (void)showCustomViewController
{
self.viewController = [[CustomViewController alloc] init];
[self.viewController presentViewController];
}
The problem is that I always get a Received Memory Warning. Also I've added a - (void)dealloc method inside the CustomViewController to know if the UIViewController is releasing properly, but for some reason the dealloc method is getting called right after the presentViewController and not after the dismissShareViewController as it should.
Another thing that I want to achieve: This CustomViewController has no UIStatusBar and when I try to present MFMailComposeViewController, I always get the MFMailComposeViewController to show without a UIStatusBar or with white status bar, but I can't change it to default back again. I've tried several question here on StackOverflow but without any luck, it just won't change.
Putting a UIView or UIWindow above Statusbar
Please, for once and for all, someone will help me with it.
UIAlertView is a subclass of UIView. If you wanted to create a custom alert view, I would also subclass UIView so that it is easy to swap out your existing UIAlertView's with your new custom view.
You can place your custom alert view atop your topmost UIWindow to cover everything.
#interface MyAlertView : UIView
- (void)duplicateAllTheFunctionsOfUIAlertViewHere;
#end
#implementation MyAlertView : UIView
- (id)initWithFrame:(CGRectMake)frame {
// add your custom subviews here
// An example of a custom background color:
self.backgroundColor = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.5];
}
- (void)duplicateAllTheFunctionsOfUIAlertViewHere {
//re-implement all the functionality in your custom ways
}
- (void)show
{
UIView* superview = [UIApplication sharedApplication].keyWindow;
self.frame = superview.bounds;
[superview addSubview:self];
// Do an animation if you want to get fancy
}
#end
Usage in a view controller:
- (void)showAlertView
{
UIView* alertView = [[MyAlertView alloc] initWithTextAndButtons:#"blah"];
[alertView show];
}

Main.storyboard does not load

I'm new to iOS and I'm making some exercises I'm stuck at the begining. I'd like to use standard Main.storyBoard which looks like this:
And the AppDelegate.m file looks like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// CGRect bounds = [[UIScreen mainScreen] bounds];
// self.window = [[UIWindow alloc] initWithFrame:bounds];
//
// self.controler = [[ViewController alloc] init];
//
// self.window.rootViewController = self.controler;
//
// [self.window makeKeyAndVisible];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:[NSBundle mainBundle]];
UIViewController *vc = [storyboard instantiateInitialViewController];
// Set root view controller and make windows visible
self.window.rootViewController = vc;
[self.window makeKeyAndVisible];
return YES;
}
And ViewControler if it will be usefull:
#interface ViewController ()
#property UIView *viewM;
#end
#implementation ViewController
-(void) loadView
{
CGRect bounds = [[UIScreen mainScreen] bounds];
self.viewM = [[UIView alloc] initWithFrame: bounds];
self.view = self.viewM;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"AHAHH DOTKNIETO EKRANU");
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
self.view.backgroundColor = [UIColor blueColor];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 200, 200, 50)];
//SET TEXT FOR THIS LABEL
label.text = #"TEXTTTTTT";
[self.view addSubview:label];
// Do any additional setup after loading the view, typically from a nib.
}
Everytime I run this sample it loads me View which is white instead of the image above. What's not right with it? I'm using Xcode 5.1.1 version.
In the project - General page you should see a setting for "Main Interface".
Remove all the code in the applicationDidFinishLaunching except return YES; and make sure this is set to Main.

"addChildViewController:" crashes on iPad but not iPhone

I have an iPhone app that works great when running on the phone however crashes at launch when running on compatibility mode on the iPad. I use iAd in my project, specifically i'm using
Bannerviewcontroller.h and .m
from the iAd suite to present the banner programmatically.
in my App Delegate I wrap some view controllers as follows.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UIViewController *viewController1, *viewController2, *catVC3, *otherVC4;
UINavigationController *navController, *dognav, *catnav, *othernav;
viewController1 = [[FirstViewController alloc] initWithNibName:#"FirstViewController_iPhone" bundle:nil];
viewController2 = [[SecondViewController alloc] initWithNibName:#"SecondViewController_iPhone" bundle:nil];
catVC3 = [[catViewController alloc]initWithNibName:#"catViewController_iPhone" bundle:nil];
otherVC4 = [[otherViewController alloc]initWithNibName:#"otherViewController_iPhone" bundle:nil];
navController = [[UINavigationController alloc]initWithRootViewController:viewController1];
dognav = [[UINavigationController alloc]initWithRootViewController:viewController2];
catnav = [[UINavigationController alloc]initWithRootViewController:catVC3];
othernav = [[UINavigationController alloc]initWithRootViewController:otherVC4];
_tabBarController = [[UITabBarController alloc] init];
NSArray *controllers = [NSArray arrayWithObjects:navController,dognav,catnav,othernav,nil];
_tabBarController.viewControllers = controllers;
//wrap tabbar controller in adbanner controller
_bannerViewController = [[BannerViewController alloc] initWithContentViewController:_tabBarController];
self.window.rootViewController = _bannerViewController;
[self.window makeKeyAndVisible];
return YES;
Then the crash happens here in my
Bannerviewcontroller.m
#import "BannerViewController.h"
#implementation BannerViewController
{
ADBannerView *_bannerView;
UIViewController *_contentController;
}
- (id)initWithContentViewController:(UIViewController *)contentController
{
self = [super init];
if (self != nil) {
_bannerView = [[ADBannerView alloc] init];
_bannerView.delegate = self;
_contentController = contentController;
}
return self;
}
- (void)loadView
{
UIView *contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[contentView addSubview:_bannerView];
[self addChildViewController:_contentController];
[contentView addSubview:_contentController.view];
[_contentController didMoveToParentViewController:self];
self.view = contentView;
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return [_contentController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}
- (void)viewDidLayoutSubviews
{
if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
_bannerView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
} else {
_bannerView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierLandscape;
}
CGRect contentFrame = self.view.bounds;
CGRect bannerFrame = _bannerView.frame;
if (_bannerView.bannerLoaded) {
contentFrame.size.height -= _bannerView.frame.size.height;
contentFrame.origin.y = _bannerView.frame.size.height;
bannerFrame.origin.y = contentFrame.size.height - contentFrame.size.height;
} else {
bannerFrame.origin.y = contentFrame.size.height;
}
_contentController.view.frame = contentFrame;
_bannerView.frame = bannerFrame;
}
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
[UIView animateWithDuration:0.35 animations:^{
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
}];
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
[UIView animateWithDuration:0.35 animations:^{
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
}];
}
#end
and throws this exception:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
Whats going on here? Thanks in advance!
The error tells, that _contentController is not initialized. Where / how do you assign it? I can't see it in the AppDelegate code.

Is it right to switch in between UIViewController that way?

I want to use my own controller for navigating in between uiviewcontrollers. So like that I can have custom transitions in between my views.
I did something which is working but I'm not sure if it is the right way? Could there be problems related to memory later?...I'm not sure everything is deallocated the right way.
Thanks for your help!
Here is my code:
In my AppDelegate, when it starts:
self.rootVC = [[[MenuView alloc] initWithNibName:#"MenuView" bundle:nil] autorelease];
[self.window addSubview:self.rootVC.view];
In my AppDelegate, the method for switching in between UIViewController:
-(void) changeRootController: (NSString*) ctrlName{
UIViewController *oldVC = self.curVC;
UIViewController *newVC;
if(ctrlName == #"Studio"){
newVC = [[StudioView alloc] initWithNibName:#"StudioView" bundle:nil];
}
else if(ctrlName == #"Menu"){
newVC = [[MenuView alloc] initWithNibName:#"MenuView" bundle:nil];
}
self.curVC = newVC;
[UIView transitionWithView:self.window
duration:1.0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
newVC.view.transform = CGAffineTransformConcat(newVC.view.transform, CGAffineTransformMakeTranslation(-1024, 0));
[self.rootVC.view addSubview:newVC.view];
newVC.view.transform = CGAffineTransformConcat(newVC.view.transform, CGAffineTransformMakeTranslation(1024, 0));
oldVC.view.transform = CGAffineTransformConcat(oldVC.view.transform, CGAffineTransformMakeTranslation(1024, 0));
}
completion:^(BOOL finished){
if(finished){
[oldVC release];
}
}
];
}
And I switch views in my UIViewController as follow:
AppDelegate *ad = (AppDelegate*)[[UIApplication sharedApplication] delegate];
[ad changeRootController:#"Studio"];
newVC isn't released.
The block should retain the newVc so after your transitionWithView
you should call. (last line of function)
[newVC autorelease];
Thats assuming that the self.curVC property is strong OR retained

Resources