I have a Navigation based Application named as diffView and in it I want to open new view on button click. For this a have created a view as file-new file-cocoa touch class-UIViewControllerSubclass named next1.
In diffViewAppDelegate.h I wrote as
IBOutlet UIButton *btn1;
#property (nonatomic,retain) UIButton *btn1;
-(IBAction)buttonPressed:(id)sender;
and in diffViewAppDelegate.m-
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
CGRect bounds=window.bounds;
UIView* view=[[UIView alloc]initWithFrame:bounds];
[view setBackgroundColor:[UIColor redColor]];
[window addSubview:view];
CGRect buttonFrame= CGRectMake(80, 240, 200, 30);
btn1=[[UIButton alloc] initWithFrame:buttonFrame];
[btn1 setTitle:#"space" forState:UIControlStateNormal];
[btn1.titleLabel setFont:[UIFont fontWithName:#"Verdana" size:20]];
[btn1 addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchDown];
[view addSubview:btn1];
[self.window makeKeyAndVisible];
return YES;
}
-(IBAction)buttonPressed:(id)sender
{
next1 * nxt=[[next1 alloc] initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:nxt animated:YES];
[nxt release];
}
I am not getting any error but when I click on the button nothing happens.
Please suggest me any solution.
Yes I have created the button in RootViewController but its not working.Even the button is not visible now. My code is like this-
CGRect buttonFrame= CGRectMake(80, 240, 200, 30);
btn1=[[UIButton alloc] initWithFrame:buttonFrame];
[btn1 setTitle:#"space" forState:UIControlStateNormal];
[btn1.titleLabel setFont:[UIFont fontWithName:#"Verdana" size:20]];
[btn1 addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchDown];
[self.view addSubview:btn1];
How i imagine it:
In your delegate you load - alloc/init the UINaviagationController and set its rootViewController property or just using initWithRootViewController: method when you init the NavigationController. Something like that.
viewController = [RootViewController alloc] init];
nvc = [[UINavigationController alloc] initWithRootViewController:viewController];
nvc.navigationBarHidden = YES;
[self.window setRootViewController:nvc];
[window makeKeyAndVisible];
In your RootViewController, from 'viewDidLoad:' method you create the button and add it to 'self.view' after that you implement the target selector and everything will be fine.
EDIT 1:
That is my application:didFinishLaunchingWithOptions: method in my AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.viewController = [[[ViewController alloc] init] autorelease];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
That is my RootViewController
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CGRect buttonFrame= CGRectMake(80, 240, 200, 30);
UIButton *btn1=[[UIButton alloc] initWithFrame:buttonFrame];
btn1.backgroundColor = [UIColor greenColor];
[btn1 setTitle:#"space" forState:UIControlStateNormal];
[btn1.titleLabel setFont:[UIFont fontWithName:#"Verdana" size:20]];
[btn1 addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn1];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)buttonPressed:(id)sender
{
NSLog(#"sender: %#", sender);
}
#end
I have two UITextViews, self.instructions and self.textView, that are supposed to alternate depending on what the user selects.
I create a self.textView like so:
-(void)createSpaceToWrite
{
[self.instructions removeFromSuperview];
[self.bar removeFromSuperview];
[self createNavigationBar:#"Compose" selector:#"displayScreen" withDone:NO]; //This adds a UINavigationBar to the view.
if (!self.textView)
{
self.textView = [[UITextView alloc] initWithFrame:CGRectMake(20, 60, 280, 150)];
}
self.textView.backgroundColor = [UIColor whiteColor];
self.textView.font = [UIFont fontWithName:#"Helvetica Neue" size:14];
self.textView.text = #"";
[self.view addSubview:self.textView];
self.textView.delegate = self;
}
Then I create self.instructions like so:
-(void)haikuInstructions
{
[self.textView removeFromSuperview];
[self.bar removeFromSuperview];
[self createNavigationBar:#"Compose" selector:#"displayScreen" withDone:NO];
if (!self.instructions)
{
self.instructions = [[UITextView alloc] initWithFrame:CGRectMake(10, 125, [[UIScreen mainScreen] bounds].size.width - 10, [[UIScreen mainScreen] bounds].size.height)];
}
self.instructions.backgroundColor=[UIColor clearColor];
self.instructions.text = #"Text of instructions";
self.instructions.editable=NO;
[self.view addSubview:self.instructions];
[self resignFirstResponder];
}
The user starts with self.instructions displayed against the background image. Fine.
The user switches. The instruction text disappears, to be replaced by the editable self.textView, a white box. Fine.
The user switches back. The instruction text appears--but the white box is still there, even thought I've removed it from the superview. And not only that, it's still editable and still brings up the keyboard when the user goes to edit it!
What am I doing wrong?
EDIT: Well, I basically scrapped all the code and started the class over from scratch, trying to be cleaner about everything, and I'm no longer having this problem, so it must have been something in some other method that was affecting it. Lesson: haphazard coding is bad!
Why do you need to remove your text views interchangeably? Wouldn't it be better to just "hide" them interchangeably by setting the setHidden property like for example:
[self.textView setHidden: YES];
and additionally try the following also:
[self.textView resignFirstResponder];
[self.textView setEditable: NO];
[self.textView setBackgroundColor: [UIColor clearColor]];
[self.textView setAlpha: 0.0];
I try to create a view without IB and make it separated with its controller. The view is MediaPlayerView contains two buttons and the controller is MediaPlayerViewController. I called the view in controller and adding a Movie Player view in it. The buttons is showing but the movie view just dark screen. What's wrong with my code?
Here is my code:
MediaPlayerView.m
-(id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code
UIButton *audioFileButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
UIButton *shortSoundButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[audioFileButton setFrame:CGRectMake(0, 40, 150, 40)];
[shortSoundButton setFrame:CGRectMake(0, 100, 200, 40)];
[audioFileButton setTitle:#"Play Audio File" forState:UIControlStateNormal];
[shortSoundButton setTitle:#"Play Short Sound" forState:UIControlStateNormal];
_viewController = [[MediaPlayerViewController alloc] init];
[audioFileButton addTarget:[self viewController]
action:#selector(playAudioFile:)
forControlEvents:UIControlEventTouchUpInside];
[shortSoundButton addTarget:[self viewController]
action:#selector(playShortSound:)
forControlEvents:UIControlEventTouchUpInside];
[self addSubview:audioFileButton];
[self addSubview:shortSoundButton];
}
return self;
}
In MediaPlayerViewController.m, here is my loadView and viewDidLoad:
loadView:
MediaPlayerView *mPlayer = [[MediaPlayerView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[mPlayer setBackgroundColor:[UIColor clearColor]];
[self setView:mPlayer];
[mPlayer release];
viewDidLoad:
[super viewDidLoad];
float halfHeight = [[self view] bounds].size.height / 2.0;
float width = [[self view] bounds].size.width;
[[[self moviePlayer] view] setFrame:CGRectMake(0, halfHeight, width, halfHeight)];
[[self view] addSubview:[[self moviePlayer] view]];
Forgive for my bad writing, cause I am a newbie either in here, Objective-C or english.
I have this case where I am using a custom UITabBar in my application.
It is working great in ios4 on both device and simulator.
But running the same code using xcode 4.2 and ios5 sdk wont work, as the app is crashing when I am setting the view controllers of my custom tabBarController on this line:
tabBarController.viewControllers = [NSArray arrayWithObjects:nc1, nc2, nc3, nil];
Here is how I am creating the tabBar:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
tabBarController = [[MBCustomTabBarController alloc] init];
home=[[Home alloc] initWithNibName:#"Home" bundle:nil];
UINavigationController *nc1=[[UINavigationController alloc] initWithRootViewController:home];
live=[[Live alloc] initWithNibName:#"Live" bundle:nil];
UINavigationController *nc2=[[UINavigationController alloc] initWithRootViewController:live];
report=[[Report alloc] initWithNibName:#"Report" bundle:nil];
UINavigationController *nc3=[[UINavigationController alloc] initWithRootViewController:report];
//custom tabbar items
MBCustomTabBarItem *firstItem = [[MBCustomTabBarItem alloc] initWithTitle:#"headlines" image:[UIImage imageNamed:#"HOME-.png"] tag:0];
MBCustomTabBarItem *secondItem = [[MBCustomTabBarItem alloc] initWithTitle:#"live" image:[UIImage imageNamed:#"NEWS-.png"] tag:1];
MBCustomTabBarItem *thirdItem = [[MBCustomTabBarItem alloc] initWithTitle:#"report" image:[UIImage imageNamed:#"REPORT-.png"] tag:2];
[firstItem setImage:[UIImage imageNamed:#"HOME.png"] forState:UIControlStateSelected];
[secondItem setImage:[UIImage imageNamed:#"NEWS.png"] forState:UIControlStateSelected];
[thirdItem setImage:[UIImage imageNamed:#"REPORT.png"] forState:UIControlStateSelected];
nc1.tabBarItem=firstItem;
nc2.tabBarItem=secondItem;
nc3.tabBarItem=thirdItem;
[firstItem release];
[secondItem release];
[thirdItem release];
tabBarController.viewControllers = [NSArray arrayWithObjects:nc1, nc2, nc3, nil];
[nc1 release];
[nc2 release];
[nc3 release];
tabBarController.customTabBar.frame = CGRectMake(0, 480 - 49, 320, 49);
tabBarController.customTabBar.backgroundColor = [UIColor clearColor];
tabBarController.customTabBar.itemWidth = 320 / [self.tabBarController.viewControllers count];
[self.window addSubview:tabBarController.view];
[self.window makeKeyAndVisible];
return YES;
}
And here is a small working example.
Your help is highly appreciated.
Never mind, I've totally changed my approach and used this answer to build my custom tabBar. And it is working fine under ios5.
So I think I'm going crazy.
I've updated to XCode 4.2 so I'd have the IOS 5 SDK.
I have an app that's been working great until the upgrade. Now, I have a strange problem. It does not work on my IOS 5 iPad 2, nor will it work in the IOS 5 simulator. Works fine in the 4.3 simulator.
For the purposes of this question, I have two classes based on UIViewController. They do not use NIB files. One, called HistoryBrowser, works great. The other, NoteBrowseViewController, constructed along the same lines, does not.
From NoteBrowseView.Controller.h:
#interface NoteBrowseViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate, UIActionSheetDelegate, UISearchDisplayDelegate, UITabBarDelegate, MKMapViewDelegate> {
UITableView* tableView;
... buncha other vars ...
}
#property (retain, nonatomic) UITableView* tableView;
... buncha other properties ...
From NoteBrowseViewController.m:
#synthesize tableView
- (id)initWithEditing:(BOOL)inEditingMode inserting:(BOOL)inserting {
self=[super init];
if (self) {
self.isInserting=inserting;
self.isEditing=inEditingMode;
self.viewIsMap=NO;
self.insertType=defInsertTypeLink;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:0],#"viewSortOrder",
[NSNumber numberWithInt:1],#"priorityView",
[NSNumber numberWithBool:NO],#"simpleView",
nil];
[defaults registerDefaults:appDefaults];
self.viewIsSimple=[[NSUserDefaults standardUserDefaults]boolForKey:#"simpleView"];
}
return self;
}
-(void)loadView {
self.view=[[UIView alloc]initWithFrame:[[UIScreen mainScreen] applicationFrame]];
UIButton* aButton;
UIImage* buttonImage;
UIBarButtonItem* spacer=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UISegmentedControl* sc=[[UISegmentedControl alloc]initWithItems:[NSArray arrayWithObjects:#"Alpha",#"Edit", #"View", nil]];
[sc addTarget:self action:#selector(segmentedControlValueChanged:) forControlEvents:UIControlEventValueChanged];
[sc setWidth:55.0 forSegmentAtIndex:0];
[sc setWidth:55.0 forSegmentAtIndex:1];
[sc setWidth:55.0 forSegmentAtIndex:2];
sc.selectedSegmentIndex=[[NSUserDefaults standardUserDefaults] integerForKey:#"viewSortOrder"];
sc.segmentedControlStyle=UISegmentedControlStyleBar;
UISegmentedControl* prisc=[[UISegmentedControl alloc]initWithItems:[NSArray arrayWithObjects:#"Open",#"All", nil]];
[prisc addTarget:self action:#selector(prioritySegmentedControlValueChanged:) forControlEvents:UIControlEventValueChanged];
[prisc setWidth:55.0 forSegmentAtIndex:0];
[prisc setWidth:55.0 forSegmentAtIndex:1];
prisc.selectedSegmentIndex=[[NSUserDefaults standardUserDefaults] integerForKey:#"priorityView"];
prisc.segmentedControlStyle=UISegmentedControlStyleBar;
UIBarButtonItem* segmentedButton=[[UIBarButtonItem alloc]initWithCustomView:sc];
UIBarButtonItem* prioritySegmentedButton=[[UIBarButtonItem alloc]initWithCustomView:prisc];
buttonImage=[UIImage imageNamed:#"13-plus.png"];
aButton=[UIButton buttonWithType:UIButtonTypeCustom];
[aButton setImage:buttonImage forState:UIControlStateNormal];
aButton.frame=CGRectMake(0.0, 0.0, buttonImage.size.width, buttonImage.size.height);
UIBarButtonItem* addButton=[[UIBarButtonItem alloc]initWithCustomView:aButton];
[aButton addTarget:self action:#selector(addButton:) forControlEvents:UIControlEventTouchUpInside];
buttonImage=[UIImage imageNamed:#"187-pencil.png"];
aButton=[UIButton buttonWithType:UIButtonTypeCustom];
[aButton setImage:buttonImage forState:UIControlStateNormal];
aButton.frame=CGRectMake(0.0, 0.0, buttonImage.size.width, buttonImage.size.height);
UIBarButtonItem* editButton=[[UIBarButtonItem alloc]initWithCustomView:aButton];
[aButton addTarget:self action:#selector(editButton:) forControlEvents:UIControlEventTouchUpInside];
buttonImage=[UIImage imageNamed:#"21-circle-east.png"];
aButton=[UIButton buttonWithType:UIButtonTypeCustom];
[aButton setImage:buttonImage forState:UIControlStateNormal];
aButton.frame=CGRectMake(0.0, 0.0, buttonImage.size.width, buttonImage.size.height);
UIBarButtonItem* simplify=[[UIBarButtonItem alloc]initWithCustomView:aButton];
[aButton addTarget:self action:#selector(simplify:) forControlEvents:UIControlEventTouchUpInside];
buttonImage=[UIImage imageNamed:#"25-circle-west.png"];
aButton=[UIButton buttonWithType:UIButtonTypeCustom];
[aButton setImage:buttonImage forState:UIControlStateNormal];
aButton.frame=CGRectMake(0.0, 0.0, buttonImage.size.width, buttonImage.size.height);
UIBarButtonItem* complexify=[[UIBarButtonItem alloc]initWithCustomView:aButton];
[aButton addTarget:self action:#selector(complexify:) forControlEvents:UIControlEventTouchUpInside];
buttonImage=[UIImage imageNamed:#"243-globe.png"];
aButton=[UIButton buttonWithType:UIButtonTypeCustom];
[aButton setImage:buttonImage forState:UIControlStateNormal];
aButton.frame=CGRectMake(0.0, 0.0, buttonImage.size.width, buttonImage.size.height);
UIBarButtonItem* map=[[UIBarButtonItem alloc]initWithCustomView:aButton];
[aButton addTarget:self action:#selector(mapify:) forControlEvents:UIControlEventTouchUpInside];
buttonImage=[UIImage imageNamed:#"162-receipt.png"];
aButton=[UIButton buttonWithType:UIButtonTypeCustom];
[aButton setImage:buttonImage forState:UIControlStateNormal];
aButton.frame=CGRectMake(0.0, 0.0, buttonImage.size.width, buttonImage.size.height);
UIBarButtonItem* notes=[[UIBarButtonItem alloc]initWithCustomView:aButton];
[aButton addTarget:self action:#selector(showNotes:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem* cancelButton=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(cancelButtonPressed:)];
self.doneToolbar=[NSArray arrayWithObjects:spacer, cancelButton, nil];
self.toolbar=[[[UIToolbar alloc]init]autorelease];
if(self.isEditing) {
self.complexToolbar=[NSArray arrayWithObjects:simplify, spacer, segmentedButton, prioritySegmentedButton, spacer, cancelButton, nil];
self.simpleToolbar=[NSArray arrayWithObjects:complexify, spacer, cancelButton, nil];
}
else {
self.complexToolbar=[NSArray arrayWithObjects:simplify, map, spacer, segmentedButton, prioritySegmentedButton, spacer, addButton, editButton, cancelButton, nil];
self.simpleToolbar=[NSArray arrayWithObjects:complexify, map, spacer, addButton, editButton, cancelButton, nil];
}
self.mapToolbar=[NSArray arrayWithObjects:notes, spacer, prioritySegmentedButton, spacer, cancelButton, nil];
if (self.viewIsSimple) {
[self.toolbar setItems:self.simpleToolbar animated:YES];
}
else {
[self.toolbar setItems:self.complexToolbar animated:YES];
}
self.toolbar.autoresizingMask=UIViewAutoresizingFlexibleWidth;
[self.toolbar sizeToFit];
CGFloat toolbarHeight = [self.toolbar frame].size.height;
CGRect rootViewBounds=self.view.bounds;
CGFloat rootViewHeight = CGRectGetHeight(rootViewBounds);
CGFloat rootViewWidth = CGRectGetWidth(rootViewBounds);
[self.toolbar setFrame:CGRectMake(0,0, rootViewWidth, toolbarHeight)];
self.mapView=[[[MKMapView alloc]initWithFrame:CGRectMake(0, toolbarHeight, rootViewWidth, rootViewHeight-(self.isInserting?49:0)-toolbarHeight)]autorelease];
self.mapView.delegate=self;
self.mapView.zoomEnabled=YES;
self.mapView.scrollEnabled=YES;
self.mapView.autoresizingMask=UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
self.tableView=[[UITableView alloc]initWithFrame:CGRectMake(0, toolbarHeight, rootViewWidth, rootViewHeight-(self.isInserting?49:0)-toolbarHeight)
style:UITableViewStylePlain];
self.tableView.delegate=self;
self.tableView.dataSource=self;
self.tableView.autoresizingMask=UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
self.view.autoresizesSubviews = YES;
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
UISearchBar* searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 44, rootViewWidth, 44.0)];
searchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
self.tableView.tableHeaderView = searchBar;
self.searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
self.searchDisplayController.delegate = self;
self.searchDisplayController.searchResultsDataSource = self;
self.searchDisplayController.searchResultsDelegate = self;
[self.view addSubview:self.tableView];
[self.view addSubview:self.toolbar];
if (self.isInserting) {
UITabBarItem* item1=[[[UITabBarItem alloc]initWithTitle:#"Link" image:nil tag:defInsertTypeLink]autorelease];
UITabBarItem* item2=[[[UITabBarItem alloc]initWithTitle:#"Contents Later" image:nil tag:defInsertTypeContentsLater]autorelease];
UITabBarItem* item3=[[[UITabBarItem alloc]initWithTitle:#"Contents Now" image:nil tag:defInsertTypeContentsNow]autorelease];
UITabBar* tabbar=[[UITabBar alloc]initWithFrame:CGRectMake(0, rootViewHeight-49, rootViewWidth, 49)];
tabbar.autoresizingMask=UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin;
[tabbar setDelegate:self];
[tabbar setItems:[NSArray arrayWithObjects:item1, item2, item3, nil] animated:YES];
[tabbar setSelectedItem:item1];
[self.view addSubview:tabbar];
}
if(self.viewIsSimple) {
self.contentSizeForViewInPopover = CGSizeMake(200.0, 625.0);
}
else {
self.contentSizeForViewInPopover = CGSizeMake(450.0, 625.0);
}
self.view.autoresizesSubviews = YES;
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.note=nil;
[sc release];
[prisc release];
[addButton release];
[prioritySegmentedButton release];
[cancelButton release];
[segmentedButton release];
[spacer release];
[editButton release];
[map release];
[simplify release];
[complexify release];
}
And finally, the a NoteBrowseViewController is instantiated thusly from another view controller:
self.noteBrowseViewController=[[NoteBrowseViewController alloc]initWithEditing:NO inserting:NO];
self.noteBrowseViewController.delegate=self;
self.popoverController = [[UIPopoverController alloc]initWithContentViewController:self.noteBrowseViewController];
self.popoverController.delegate = self;
[self.popoverController presentPopoverFromRect:((UIButton*)sender).frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
So this is what happens. If I run this in debug, and follow along, as soon as execution gets to this line:
CGRect rootViewBounds=self.view.bounds;
The program crashes with the following errors:
2011-10-20 11:42:02.703 ActionNote3[12332:15803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
*** First throw call stack:
(0x1eb0052 0x2a60d0a 0x1e9d36e 0x1e9e220 0x1968cb6 0x5153b 0x50e11 0x50879 0x52e4a 0xdcc64e 0x4bcb3 0x72d1 0x1eb1ec9 0xd095c2 0xd0955a 0xdaeb76 0xdaf03f 0xdae2fe 0xd2ea30 0xd2ec56 0xd15384 0xd08aa9 0x20c7fa9 0x1e841c5 0x1de9022 0x1de790a 0x1de6db4 0x1de6ccb 0x20c6879 0x20c693e 0xd06a9b 0x2dbd 0x2d35)
terminate called throwing an exception
By watching things during the debug, I know self.view is being set up properly, and that loadView is being called when it should be. And it's not this line that makes it fail - it's anything that refers to self.view! what???
What really makes me crazy is that I have another subclassed view controller, HistoryBrowser, that is loaded in exactly the same manner... and it works fine.
So, aside from being upset that I cannot figure this out, i'd like to understand:
What's changed in XCode 4.2 (from 4.1) that would cause this, or is
this an IOS 5 issue?
What does this error mean, and what can I do
about it?
EDIT:
So based on suggestions from Abberant's answer below, I:
changed the initwithnib to just be init
removed the loadView method
added the full error message
added more relevant code to the init method
And now, referencing self.view works properly. But things have just gotten stranger.
Execution makes it past the first reference to self.view without error. However, it now halts at:
self.tableView.tableHeaderView = searchBar;
in the init method.
The error message received is eerily similar to the one I was receiving before:
2011-10-20 12:34:04.818 ActionNote3[13487:15803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
*** First throw call stack:
(0x1eaf052 0x2a5fd0a 0x1e9c36e 0x1e9d220 0x1967cb6 0x50b4b 0x50421 0x4fe89 0x4d757 0x6641 0x1eb0ec9 0xd085c2 0xd0855a 0xdadb76 0xdae03f 0xdad2fe 0xd2da30 0xd2dc56 0xd14384 0xd07aa9 0x20c6fa9 0x1e831c5 0x1de8022 0x1de690a 0x1de5db4 0x1de5ccb 0x20c5879 0x20c593e 0xd05a9b 0x212d 0x20a5)
terminate called throwing an exception
So, if I comment that line out, execution procedes until it reaches this group of lines, where it fails when it attempts to do the performFetch.
NSError *error = nil;
if (![[self currentFetchedResultsController] performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
Debugging into the code for [self currentFetchedResultsController] shows that the fetched results controller is being set up properly and without issue.
The error received here is the same as above. The numbers in the first throw call stack change, but otherwise the error is the same.
So I'm left thinking that I have a larger problem going on here. I just have no idea how to track it down. As I said way up there somewhere, I have another view, constructed in the same manner, that loads fine.
Edit:
So NJones in his answer below suggested following Apple's guidelines by placing the appropriate code in loadView and viewDidLoad. So I did. I moved all view construction out of init and into loadView, and fired up the fetchedResultsController in viewDidLoad.
The app still crashes in the same spot:
self.tableView.tableHeaderView = searchBar
With the same error as noted above.
Thanks!
I would say you should use the loading model apple suggests. This is some of the code generated in xCode when you create a new UIViewController subclass (abridged to fit):
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
-(void)loadView{
}
*/
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
-(void)viewDidLoad{
[super viewDidLoad];
}
*/
Based on just this, Since you are creating your view programmatically, I would say that most of what you have in your init method belongs in the loadView method.
So I found the answer, and it's not something anyone would have guessed without seeing a lot more code. But, hopefully this answer will help other people who might run into the same thing.
In what has become my loadView method (but was originally in my init method, and still is in the code above), I had the following lines:
UISegmentedControl* sc=[[UISegmentedControl alloc]initWithItems:[NSArray arrayWithObjects:#"Alpha",#"Edit", #"View", nil]];
[sc addTarget:self action:#selector(segmentedControlValueChanged:) forControlEvents:UIControlEventValueChanged];
[sc setWidth:55.0 forSegmentAtIndex:0];
[sc setWidth:55.0 forSegmentAtIndex:1];
[sc setWidth:55.0 forSegmentAtIndex:2];
sc.selectedSegmentIndex=[[NSUserDefaults standardUserDefaults] integerForKey:#"viewSortOrder"];
sc.segmentedControlStyle=UISegmentedControlStyleBar;
segmentedControlValueChanged: would set a string var (and store the index of the selected button in user defaults). The string var was later used to determine sort order when firing up my fetchedresultscontroller.
Prior to IOS 5, when I set sc.selectedSegmentIndex, the method identified in the selector would get fired, and everything would get set up properly. In IOS 5, this is no longer the case, and the string var (setting a sort order) would not get set.
What's interesting is that upon execution this line:
self.tableView.tableHeaderView = searchBar;
would cause the fetchedReultsController to be accessed and, by accessing it, it would be initialized. When it went to be initialized, it would set the sort order and include a null value for the field name, hence the error message, which now makes sense.
So the root cause of the problem was that prior to IOS 5, setting the selectedSegmentIndex on a UISegmentedControl would fire the action associated with the control. Starting with IOS 5, this is no longer the case.
The original cause of the problem, which several people helped me resolve, was that I was not following the viewController load process properly. I am not using NIB files. Apple says that if you dont use a nib file, you have to define loadView to set up the view. If loadView is not defined, self.view is set internally, and viewDidLoad is called. The reason the app crashed at the first reference of self.view, then, is that I had logic in viewDidLoad to set up the fetchedResultsController. When I moved the view setup logic into loadView, references to self.view no longer started up the fetchedresultscontroller.
Been thinking about and looking for information on this for a while, but it might be any number of things. Perhaps the self.view gets called before the loadView somewhere, maybe it's because initWithNibName triggers something you don't want, maybe it's because your view is smaller than the screen/window, which is not advised, maybe the new iOS has a bug in it... With so little of your code, no way to debug and an incomplete error message, I can't see what causes it.
However, I might have a workaround:
How about removing that loadView override so that the viewController makes its own view, then add your mainView to that default view?
The exception says you are adding a nil to an array. I'm think tableViewHeader could be considered an objectAtIndex:0 since it's the first of an array of rows. Try putting this line above it :
NSLog(#"searchBar = %#",searchBar;
self.tableView.tableHeaderView = searchBar;
Edit(1):
Then try these:
NSLog(#"self = %#",self);
NSLog(#"self.tableView = %#",self.tableView);
NSLog(#"self.tableView.tableHeaderView = %#",self.tableView.tableHeaderView);
self.tableView.tableHeaderView = searchBar;
Edit(2):
if ([self.tableView respondsToSelector:#selector(setTableHeaderView:)]){
NSLog(#"tableView does respond");
[self.tableView setTableHeaderView:nil];
}
I don't think this will fix the problem, but it should help hunt down the problem.