I am getting EXE_BAD_ACCESS exception when I hit "back" button on NavigationBar of my CreateViewController which is pushed on UINavigationController
When I enable following line in CreateViewController.m (full code at the bottom)
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.navigationBar.hidden = NO;
//[self.textField becomeFirstResponder];
}
I start getting Thread1:EXE_BAD_ACCESS(code=1, address=...)
int main(int argc, char * argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
If I keep the above line of code disabled, then hitting back button takes me to MainViewController as expected.
I am a newbie to iOS. What I am doing wrong? Please see my code below.
Appdelegate.h
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
Appdelegate.m
import "AppDelegate.h"
import "MainViewController.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
id controller = [[MainViewController alloc] initWithNibName:#"MainView" bundle:nil];
id navController = [[UINavigationController alloc] initWithRootViewController:controller];
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
return YES;
}
#end
MainViewController.h
#interface MainViewController : UIViewController
- (IBAction)create:(id)sender;
#end
MainViewController.m
import "MainViewController.h"
import "CreateViewController.h"
#implementation MainViewController
#pragma mark - View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (void)viewWillAppear:(BOOL)animated {
self.navigationController.navigationBar.hidden = YES;
}
- (IBAction)create:(id)sender {
id controller = [[CreateViewController alloc] initWithNibName:#"CreateView" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
}
#end
CreateView.h
#interface CreateViewController : UIViewController <UITextFieldDelegate>
#end
CreateView.m
- (void)viewDidLoad {
[super viewDidLoad];
[self.navigationController.navigationBar setTintColor:[UIColor purpleColor]];
self.textField=[[UITextField alloc] initWithFrame:CGRectMake(80, 10, 160, 30)];
[self.textField setBorderStyle:UITextBorderStyleRoundedRect];
self.textField.placeholder = #"Name";
[self.textField setBackgroundColor:[UIColor clearColor]];
self.textField.delegate = self;
[self.navigationController.navigationBar addSubview:self.textField];
self.navigationController.navigationBar.hidden = NO;
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.navigationBar.hidden = NO;
//[self.textField becomeFirstResponder];
}
Go to breakpoint navigator and add exceptions breakpoint as shown below , 1st option :
Instead of adding self.textField as subview to navigation bar, set the textField as titleView of navigation item of the view controller.
[self.navigationItem setTitleView:self.textField];
This must help...
Related
I have set my self.navigationItem.title = #"Hello"; in ViewController.m but it's not showing:
AppDelegate.m
#import "AppDelegate.h"
#import "ViewController.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
ViewController *viewController = [[ViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
return YES;
}
#pragma mark - UISceneSession lifecycle
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options API_AVAILABLE(ios(13.0)) {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return [[UISceneConfiguration alloc] initWithName:#"Default Configuration" sessionRole:connectingSceneSession.role];
}
- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions API_AVAILABLE(ios(13.0)) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
#end
ViewController.m
#import "ViewController.h"
#import <UIKit/UIKit.h>
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = #"Hello";
self.view.backgroundColor = [UIColor systemBlueColor];
}
#end
Thanks in advance!
I'm considering that you're not using storyboard.
In your case, you have to do everything programmatically, including allocating the navbar.
- (void)viewDidLoad {
[super viewDidLoad];
UINavigationBar *navbar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 20, self.view.frame.size.width, 44)];
UINavigationItem *title = [[UINavigationItem alloc] initWithTitle:#"Hello"];
self.view.backgroundColor = [UIColor systemBlueColor];
[navbar setItems:#[title]];
[self.view addSubview:navbar];
}
If you were using storyboard, this simple command would be working, without needing anything in the appDelegate.
self.navigationItem.title = #"Hello";
It is enough to say: viewController.title = #“Hello”;
https://developer.apple.com/documentation/uikit/uiviewcontroller/1621364-title
My Problem
I am using a UITabBarController inside a UINavigationController. And there are three tableviews inside the UITabBarController. As shown in the picture, the first table view shows correctly while the other two tableviews are partially hidden behind the navigation bar. How can I fix this?
My hierarchy:
Root: UINavigationController
UITabBarController
UITableViewController (table1,table2,table3)
Here is my code:
AppDelegate.m
#import "AppDelegate.h"
#import "TableViewController.h"
#interface AppDelegate()
#property UINavigationController* nav;
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
TableViewController* table1 = [[TableViewController alloc]init];
TableViewController* table2 = [[TableViewController alloc]init];
TableViewController* table3 = [[TableViewController alloc]init];
table1.title = #"table1";
table2.title = #"table2";
table3.title = #"table3";
UITabBarController* t = [[UITabBarController alloc] init];
[t setViewControllers:#[table1,table2,table3]];
self.nav = [[UINavigationController alloc] initWithRootViewController:t];
[self.window setRootViewController:self.nav];
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application{}
- (void)applicationDidEnterBackground:(UIApplication *)application{}
- (void)applicationWillEnterForeground:(UIApplication *)application{}
- (void)applicationDidBecomeActive:(UIApplication *)application{}
- (void)applicationWillTerminate:(UIApplication *)application{}
#end
TableViewController.m
#import "TableViewController.h"
#implementation TableViewController
- (id)initWithStyle:(UITableViewStyle)style{
self = [super initWithStyle:style];
if (self) {}
return self;
}
- (void)viewDidLoad{
[super viewDidLoad];
[self.tabBarController.view layoutSubviews];
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell* c = [[UITableViewCell alloc] init];
[c.textLabel setText:[NSString stringWithFormat:#"%d", indexPath.row]];
return c;
}
#end
Typically, the hierarchy is
UITabBarController
- UINavigationController
- UITableViewController
Why are you trying to put the Navigation Controller on top? Try reorganizing using a tab bar full of navigation controllers instead.
I hit this same problem yesterday, and decided to work around it. It's just one class that gets in the way, so here's the rewrite:
DRTabBarController.h
//
// Created by Dan Rosenstark on 2/28/15.
// Copyright (c) 2015 Confusion Studios LLC. All rights reserved.
//
#import <UIKit/UIKit.h>
#interface DRTabBarController : UIViewController <UITabBarDelegate>;
#property (nonatomic, strong) NSArray *viewControllers;
#property (nonatomic, strong) UITabBar *tabBar;
#property (nonatomic, strong) UIView *mainView;
#end
DRTabBarController.m
//
// Created by dr2050 on 2/28/15.
// Copyright (c) 2015 Confusion Studios LLC. All rights reserved.
//
#import "DRTabBarController.h"
#implementation DRTabBarController {
}
- (instancetype)init {
self = [super init];
if (self) {
self.tabBar = [[UITabBar alloc] init];
self.tabBar.delegate = self;
self.tabBar.tintColor = [UIColor whiteColor];
self.tabBar.barStyle = UIBarStyleBlack;
self.tabBar.backgroundColor = [UIColor blackColor];
self.mainView = [[UIView alloc] init];
}
return self;
}
- (void)viewDidLoad {
[self.view addSubview:self.tabBar];
[self.view addSubview:self.mainView];
}
- (void)setViewControllers:(NSArray *)viewControllers {
_viewControllers = viewControllers;
NSMutableArray *tabBarItems = [NSMutableArray array];
for (UIViewController *controller in viewControllers) {
UITabBarItem *item = controller.tabBarItem;
[tabBarItems addObject:item];
}
self.tabBar.items = tabBarItems;
}
- (void)viewWillAppear:(BOOL)animated {
[self.tabBar setSelectedItem:self.tabBar.items.firstObject];
[self tabBar:self.tabBar didSelectItem:self.tabBar.items.firstObject];
}
- (void)viewDidAppear:(BOOL)animated {
}
-(void)viewDidLayoutSubviews {
CGRect frame = self.view.bounds;
UITabBarController *throwaway = [[UITabBarController alloc] init];
frame.size.height = throwaway.tabBar.frame.size.height;
frame.origin.y = self.view.bounds.size.height - frame.size.height;
self.tabBar.frame = frame;
self.tabBar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
frame = self.view.bounds;
frame.size.height -= self.tabBar.frame.size.height;
float navbarHeight = self.navigationController.navigationBar.frame.size.height;
// cannot use UIApplication.sharedApplication.statusBarFrame.size.height because
// reports are not right with in-call status bar
float statusBarHeight = UIApplication.sharedApplication.statusBarHidden ? 0 : 20;
float topBarHeight = navbarHeight + statusBarHeight;
frame.origin.y += topBarHeight;
frame.size.height -= topBarHeight;
self.mainView.frame = frame;
self.mainView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
}
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {
int index = [self.tabBar.items indexOfObject:item];
NSArray *subviews = self.mainView.subviews;
for (UIView *view in subviews) {
[view removeFromSuperview];
}
UIView *view = [[self.viewControllers objectAtIndex:index] view];
view.frame = self.mainView.bounds;
view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.mainView addSubview:view];
}
#end
Note: There's one magic variable in there -- 20 -- for the in-call status bar, which has a totally different relationship to the surrounding nav...
Any help with this would be appreciated, but does work.
i have created a tabbed application and created another file, called LogInScreen,
I want to change the usual view which comes up at the application launch to this new LogInFile, but everything I tried didn't work.
This is the AppDelegate.h file:
#import <UIKit/UIKit.h>
#import "LogInScreen.h"
#interface LogInScreen : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) LogInScreen *logInView;
#end
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
At the first #implementation appears an error message: Duplicate interface definition for class 'LogInScreen', I guess because of the LogInScreen.h file. I don't know how to get it to work properly.
And this the start of the AppDelegate.m:
#import "AppDelegate.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
[self.logInView addSubview:_logInView.view];
[self.logInView makeKeyAndVisible];
[self.logInView setRootViewController:_logInView];
// Override point for customization after application launch.
return YES;
}
I found this code on this website, but it didn't work...
Here's the LogInScreen.h file:
#import <UIKit/UIKit.h>
#interface LogInScreen : UIViewController{
NSString *password;
IBOutlet UITextField *passwordField;
}
- (IBAction)enterPassword;
- (IBAction)savepassword:(id)sender;
- (IBAction)returnKey:(id)sender;
- (IBAction)switchView:(id)sender;
#end
and the LogInScreen.m:
#import "LogInScreen.h"
#import "FirstViewController.h"
/* #import "AppDelegate.h"
int main(int argc, char * argv[])
{
#autoreleasepool {
return UIApplicationMain()(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
*/
#interface LogInScreen ()
#end
#implementation LogInScreen
- (IBAction)enterPassword
{
NSString *passwordString = [NSString stringWithFormat:#"12345"];
if ([passwordField.text isEqualToString:passwordString]) {
/*[self switchView:nil]; */
}
else {
UIAlertView *incorrectPassword = [[UIAlertView alloc] initWithTitle:#"Falsches Passwort" message:#"Dieses Passwort ist falsch! Geben Sie bitte das korrekte Passwort ein!" delegate:self cancelButtonTitle:#"Zurück" otherButtonTitles:nil, nil];
[incorrectPassword show];
}
}
- (IBAction)savepassword:(id)sender {
password = [[NSString alloc] initWithFormat:passwordField.text];
[passwordField setText:password];
NSUserDefaults *stringDefault = [NSUserDefaults standardUserDefaults];
[stringDefault setObject:password forKey:#"stringKey"];
}
- (IBAction)returnKey:(id)sender {
[sender resignFirstResponder];
}
- (IBAction)switchView:(id)sender {
FirstViewController *main = [[FirstViewController alloc] initWithNibName:nil bundle:nil];
[self presentViewController:main animated:YES completion:NULL];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[passwordField setText:[[NSUserDefaults standardUserDefaults] objectForKey:#"stringKey"]];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Would be cool if someone could help me
Following my comment, you can use this code to show a modal login view before your main tabbed view:
// Main menu view controller
MainViewController *mainViewController = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
UINavigationController *mainNavigationController = [[UINavigationController alloc] initWithRootViewController:mainViewController];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.delegate = self;
self.tabBarController.viewControllers = [NSArray arrayWithObjects:mainNavigationController, nil];
self.window.rootViewController = self.tabBarController;
[self.window.rootViewController.view setOpaque:NO];
self.window.rootViewController.view.backgroundColor = [UIColor clearColor];
self.tabBarController.selectedIndex = 0;
[self.window setRootViewController:self.tabBarController];
[self.window makeKeyAndVisible];
// Login modal view controller
LoginViewController *loginController = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
[self.tabBarController presentViewController:loginController animated:NO completion:nil];
Place your login screen as intial view in MainStoryBoard .Drag a drop a uitabbarcontroller connect a segue from loginscreen to uitabbar and present modal that tabbar from a button in the login screen .
Having a bit of a problem, here's the breakdown:
My AppDelegate uses as it's rootViewController a view controller. This view controller's purpose is to swap a couple of other view controllers in and out, call it login and main screens. For the sake of simplicity I've removed any swapping code from the code that I will post and am having the rootViewController simply show it's first content view controller, say login.
The issue I'm having is that the content view controller seems to be pushed down a little bit inside the rootViewController. I've given the rootViewController a blue background and the content view controller an orange background. Here's my code:
AppDelegate.h
#import <UIKit/UIKit.h>
#class MainViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) MainViewController *main;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "MainViewController.h"
#implementation AppDelegate
#synthesize main;
- (void)dealloc
{
[_window release];
[main release];
[super dealloc];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
MainViewController *mainVC = [[MainViewController alloc] init];
self.main = mainVC;
self.window.rootViewController = self.main;
[self.window makeKeyAndVisible];
return YES;
}
MainViewController.h
#import <UIKit/UIKit.h>
#class ContentViewController;
#interface MainViewController : UIViewController
#property (nonatomic, retain) ContentViewController *content;
#end
MainViewController.m
#import "MainViewController.h"
#import "ContentViewController.h"
#implementation MainViewController
#synthesize content;
- (id)init
{
self = [super init];
if (self ) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor blueColor];
ContentViewController *viewController = [[ContentViewController alloc] init];
self.content = viewController;
[self.view insertSubview:self.content.view atIndex:0];
}
- (void)dealloc {
[content release];
[super dealloc];
}
#end
ContentViewController.h
#import <UIKit/UIKit.h>
#interface LoginVC : UIViewController
#end
ContentViewController.m
#import "ContentViewController.h"
#implementation ContentViewController
- (id)init
{
self = [super init];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor orangeColor];
}
- (void)dealloc {
[super dealloc];
}
#end
The above codes gives me a status bar with a blue strip (approximately the height of the status bar) under it (which is the main view controller) followed by the orange content view controller taking up the rest of the screen. For some reason that main view controller seems to be pushing the content view controller down a little.
Strangely, if I create a view controller and use a XIB for drawing the view, it looks just fine and the content view it right up against the top of the main view.
If anybody could shed some light on this issue I'd very much appreciate it.
Cheers
I suppose that you shouldn't be doing
ContentViewController *viewController = [[ContentViewController alloc] init];
self.content = viewController;
[self.view insertSubview:self.content.view atIndex:0];
but rather:
ContentViewController *viewController = [[ContentViewController alloc] init];
self.content = viewController;
[self presentViewController:self.content animated:YES completion:nil];
I am using the standard tab bar application as a basis for a test app.
I am also trying to use the ELCAlbumPickerController class found at github.
The button to launch the photo picker and the uiscrollview are located in the Secondview.xib
The following is the code in the SecondViewController.h
#import <UIKit/UIKit.h>
#import "ELCImagePickerController.h"
#interface SecondViewController : UIViewController <ELCImagePickerControllerDelegate,UINavigationControllerDelegate, UIScrollViewDelegate>{
UIWindow *window;
SecondViewController *viewController;
IBOutlet UIScrollView *scrollview;
}
#property (nonatomic,retain) IBOutlet UIWindow *window;
#property (nonatomic,retain) IBOutlet SecondViewController *viewController;
#property (nonatomic,retain) IBOutlet UIScrollView *scrollview;
-(IBAction)launchController;
#end
And the following is in SecondViewController.m
#import "myappAppDelegate.h"
#import "SecondViewController.h"
#import "ELCImagePickerController.h"
#import "ELCAlbumPickerController.h"
#implementation SecondViewController
#synthesize window;
#synthesize viewController;
#synthesize scrollview;
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.*/
- (void)viewDidLoad
{
//[self launchController:self];
[super viewDidLoad];
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
-(IBAction)launchController {
ELCAlbumPickerController *albumController = [[ELCAlbumPickerController alloc] initWithNibName:#"ELCAlbumPickerController" bundle:[NSBundle mainBundle]];
ELCImagePickerController *elcPicker = [[ELCImagePickerController alloc] initWithRootViewController:albumController];
[albumController setParent:elcPicker];
[elcPicker setDelegate:self];
//myappAppDelegate *app = (myappAppDelegate *)[[UIApplication sharedApplication] delegate];
SecondViewController *app = (SecondViewController *)[[UIApplication sharedApplication] delegate];
[app.viewController presentModalViewController:elcPicker animated:YES];
[elcPicker release];
[albumController release];
}
#pragma mark ELCImagePickerControllerDelegate Methods
- (void)elcImagePickerController:(ELCImagePickerController *)picker didFinishPickingMediaWithInfo:(NSArray *)info {
[self dismissModalViewControllerAnimated:YES];
for (UIView *v in [scrollview subviews]) {
[v removeFromSuperview];
}
CGRect workingFrame = scrollview.frame;
workingFrame.origin.x = 0;
for(NSDictionary *dict in info) {
UIImageView *imageview = [[UIImageView alloc] initWithImage:[dict objectForKey:UIImagePickerControllerOriginalImage]];
[imageview setContentMode:UIViewContentModeScaleAspectFit];
imageview.frame = workingFrame;
[scrollview addSubview:imageview];
[imageview release];
workingFrame.origin.x = workingFrame.origin.x + workingFrame.size.width;
}
[scrollview setPagingEnabled:YES];
[scrollview setContentSize:CGSizeMake(workingFrame.origin.x, workingFrame.size.height)];
}
- (void)elcImagePickerControllerDidCancel:(ELCImagePickerController *)picker {
[self dismissModalViewControllerAnimated:YES];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc
{
[super dealloc];
}
#end
When you click the button you get a message "deallocing ELCImagePickerController" so it is calling the ELCImagePickerController class but it just does not show the image picker. Any ideas would be appreciated.
Thanks
In the launchController() method, you were casting an appDelegate into a viewController, which is logically wrong. You need to use an actual viewController to presentModalViewController. Try:
[self presentModalViewController:elcPicker animated:YES];