Xcode 4 - viewDidLoad issue - iphone

Is anyone else having issues with Xcode 4 where viewDidLoad is being called twice? I have run the same project in both Xcode 3.2 and Xcode 4 and it only acts up in Xcode 4.

After researching this on the Apple Developer forums, it seems that in some cases Xcode 4 creates bugged Interface Builder NIBs. The effect is that the application's rootViewController gets loaded in twice, which really screws things up. The same project loaded in Xcode 3 won't exhibit the problem.
In my universal app, it only affected the iPad NIB. The iPhone was fine.
I was able to solve this issue by:
Removing the rootViewController connection in Interface Builder (this causes the app to load with window.rootViewController = nil)
In viewDidLoad for the main controller (the one that was being loaded twice), I then manually assign appDelegate.window.rootViewController = self
So far this seems to have the desired effect.

Xcode is just the IDE -- it shouldn't have any bearing on what happens when your app is executing. If there's a difference, it seems more likely that you're building for different iOS versions.

Did you set the view of the view controller? I had the same issue and I realized that I didn't set the view property.
- (void)viewDidLoad {
UIView *contentView = [[UIView alloc] initWithFrame: [[UIScreen mainScreen] applicationFrame];
//add some stuff to contentView here
self.view = contentView;
[contentView release];
}

I had same issue. And i resolved it. It happens when your app memory did get memory warning.
Put a breakpoint to memoryDidReceiveWarning. It get's called, and clear your class object memory. So your viewDidLoad Get called twice, because it has no memory at that time.

Related

Works on iOS Simulator but not on iPhone

The line of code works fine on the iOS Simulator 6.0, but is crashing when I try to run it on my iPhone, also running iOS6.
[menuView addSubview:mvc.view];
Why is this happening, and how can I fix it?
This is the more complete version of the code:
SDMenuViewController *mvc = [[SDMenuViewController alloc] init];
[menuView addSubview:mvc.view];
And this is what it is crashing with:
2012-10-08 21:32:32.423 CrunchCalculator1-2[21019:907] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle </var/mobile/Applications/EDD23933-CE20-4AFD-A2B1-CDD56AD658E8/CrunchCalculator1-2.app> (loaded)' with name 'SDNestedTableView''
*** First throw call stack:
(0x39cd03e7 0x35ece963 0x39cd0307 0x39ee0fd1 0x39ee05ff 0x39dd9031 0x39e0786d 0x39d63419 0xb20d9 0x39d63541 0x39da3d29 0x39d9fac5 0x39de1199 0xb17c5 0x39da4a71 0x39da45f5 0x39d9c803 0x39d44ce7 0x39d44775 0x39d441b7 0x31e145f7 0x31e14227 0x39ca53e7 0x39ca538b 0x39ca420f 0x39c1723d 0x39c170c9 0x39d9b43d 0x39d98289 0xb1523 0x3792fb20)
libc++abi.dylib: terminate called throwing an exception
Thanks!
I'm not quite sure how it worked on your simulator (when I tried it on mine, I got the crash you list in your original question). Anyway, you can fix it by looking at the following items:
The main problem is that the NIB was not included in the bundle. Add it to the project target's "Copy Bundle Resources", e.g.:
While you're looking at your "Copy Bundle Resources", you'll also want to include SDSubCell.xib, SDGroupCell.xib, and add all of those PNG files, too.
As an aside, while it doesn't apparently cause the crash, the "File Owner" base class in SDNestedTableView NIB refers to a class that doesn't exist anywhere in this project. That can't be good. Anyway, you probably want to change that to SDMenuViewController or SDNestedTableViewController;
It's a little unrelated to your crash, but as I look at the project, I see a worrying construct:
SDMenuViewController *mvc = [[SDMenuViewController alloc] initWithNibName:#"SDNestedTableView" bundle:nil];
[menuView addSubview:mvc.view];
You're creating a controller, grabbing its view, and either letting the view controller fall out of scope and be released (if you were using ARC) or leaking it (if not ARC).
I wasn't entirely sure from the original question whether you were doing addSubview as a way of transitioning to a new view (which is really bad practice) or whether you were doing view controller containment. As I look at the code, it appears you're doing the latter, though you're missing a few calls in your code. You might want to read up on view controller containment. And also check out that WWDC 2011 session 102.
Anyway, those two lines of code above with the view controller alloc/init and the subsequent addSubview will leak in your non-ARC project (and would crash it if you ever went to ARC) and your view hierarchy is out of sync with your view controller hierarchy. I'd suggest you might want:
SDMenuViewController *mvc = [[[SDMenuViewController alloc] initWithNibName:#"SDNestedTableView" bundle:nil] autorelease];
[self addChildViewController:mvc];
[mvc didMoveToParentViewController:self];
[menuView addSubview:mvc.view];
Note the autorelease on that first line.
View controller containment can be powerful, but you want to make sure you do some of this basic housekeeping.
One final update:
I notice that there are some bugs that are in this code. First, your use of currentSection in item:setSubItem:forRowAtIndexPath won't work. You're setting that based upon the last expandingItem. So, if you click on one of the main items before expanding either one, the program will crash. Probably best is to eliminate the currentSection variable altogether and in item:setSubItem:forRowAtIndexPath, use item.cellIndexPath.row rather than your variable currentSection.
Unfortunately, this fix leads to a more serious problem, there appears to be an iOS 6 bug in the SDNestedTable class, itself. If you run this on iOS 6 and you expand your all of your items, scroll to the bottom and then scroll back to the top, the program will crash because the cellIndexPath property of the SDGroupItem *item returned by item:setSubItem:forRowAtIndexPath can be deallocated! If you turn on zombies in iOS 6, you'll see cellIndexPath has been released. I went and downloaded the original version and see the same problem there. The problem appears to be that cellIndexPath in SDGroupCell is defined as an assign property (which means that if iOS determines it no longer needed the indexPath it created for its own purposes, it will be released even though SDGroupCell maintains an assign reference to this released object). Just change the cellIndexPath property of SDGroupCell from assign to retain, and this iOS 6 bug goes away. I've informed the developer of SDNestedTable of this issue, but this change to retain will fix the problem of the code crashing in iOS 6.
[Edit: The author of SDNestedTable agreed with my assessment of the issue, and he reports that this issue has been fixed the latest version. - Rob]
Best wishes.
You should probably use initWithNibName: insead of just init in the first line. Not sure regarding your specific issue, but certainly something to try.
It looks like you're trying to instantiate a nib called SDNestedTableView.nib and it isn't present. Is the nib included as a project member?

Root View Controller Error

I'm working along with the book Beginning iPhone 3 Development, and am running into some issues on the "Pickers" app. I'm using Xcode 4.2, and I set it up exactly like they have it set up in their source code. All the code is the same, and all the outlet connections are the same. But, when I run my version, it launches a black screen, and the debugger says "Applications are expected to have a root view controller at the end of application launch."
There version in the source code runs just fine, and mine looks identical to it, but for some reason mine just won't run. I've Googled this issue and people have a bunch of workarounds, but I feel like there is something really simple in IB that I'm not seeing.
Any help would be great, thanks.
The iPhone 3 book is probably having you add the view of your view controller as a subview of the window, correct? Well, since iOS 4, UIWindow now has a rootViewController property and setting this property to your initial view controller is now the preferred way to get your first view controller on screen.
Basically replace something like this in -application:didFinishLaunchingWithOptions: in your application delegate...
[self.window addSubview:viewController.view];
with this...
self.window.rootViewController = viewController;
Quite a bit has changed since iPhone OS 3; beware as you proceed through the book.
Do you have the RootViewControllers XIB-file? And is it connected to the RootViewController Class (in designer)

iOS: different addSubview behavior between iOS 4.3 and 5.0

while coding in iOS 4.3 before, I found while add a view controller's view to another view with [superview addSubView:controller.view], the controller instance will not receive the -viewWillAppear/viewDidAppear message, than I found same issue in some thread in stack overflow. After that, I manually call -viewWillAppear/-viewDidAppear as needed.
but, after upgrade to iOS 5.0, some frisky UIView behavior happened. Finally I found that in iOS 5, the [superview addSubView:controller.view] , will send a -viewWillAppear/-viewDidAppear message to the controller instance automatically, plus my manually calls, there are two duplicated message each time the controller action its behavior.
and I also found a similar issue: iOS 5 : -viewWillAppear is not called after dismissing the modal in iPad
Now, the problem is, after search apple's documents, I didn't find any explicitly doc for diff about these issues. I even wonder if this is a guaranteed view life cycle behavior in iOS 5.0 .
Does anyone fix similar issues or find some guidelines about these difference. cause I want to run my app both in 4.x & 5.x iOS.
In iOS 4 you had to manually call -viewWillAppear, -viewWillDisappear, etc. when adding or removing a view from your view hierarchy. These are called automatically in iOS 5 if the view is being added or removed from the window hierarchy. Fortunately, iOS 5 has a method in UIViewController that you can override to revert the behaviour back to how it worked with iOS 4. Just add this to your UIViewController:
-(BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers {
return NO;
}
This is probably the easiest solution as long as you're supporting both iOS 4 and iOS 5. Once you drop support for iOS 4 you might consider modifying your code to use the newer approach when swapping views.
Edit 5 February 2012
Apparently this function requires the child view controller be added to the main view controller using the addChildViewController: method. This method doesn't exist in iOS4, so you need to do something like this:
if ([self respondsToSelector:#selector(addChildViewController:)] ) {
[self addChildViewController:childViewController];
}
Thanks to everyone who corrected me on this.
This may not be an answer what you want, but I had same kind of problem.
In my case, when I added a view controller's view to another view controller's view as a subview, the subview was received viewWillAppear only in iOS 5.0 not iOS 4.X.
So I added a nasty condition.
[self.view addSubview:self.viewController.view];
if ([[[UIDevice currentDevice] systemVersion] compare:#"5.0"] == NSOrderedAscending) {
[self.viewController viewWillAppear:animated];
}
From iOS 5.0, Apple provides a way to implement custom container view controllers like UINavigationController or UITabController. I think this change affects when viewWillAppear is called.
This problem may be solvable if we use -[UIViewController addChildViewController:].
The answers above a slightly incomplete.
Let's presume you have 2 view controllers, ControllerA, and ControllerB.
ControllerA.view is already added to the window(it is the parent), and you want to add ControllerB.view as a subview of ControllerA.
If you do not add ControllerB as a child of ControllerA first, the automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers will be ignored, and you will still be called by iOS5, meaning that you'll call your view controller callbacks twice.
Example in ControllerA:
- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers {
return NO;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.controllerB = [[ControllerB alloc] initWithNibName:#"ControllerB" bundle:nil];
[self.view addSubview:self.controllerB.view];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.controllerB viewWillAppear:animated];
}
In ControllerB NSLogging in viewWillAppear:
- (void)viewWillAppear:(BOOL)animated
{
NSLog("#ControllerB will appear");
}
This will result in iOS5 only displaying that NSLog message twice. i.e. You're automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers has been ignored.
In order to fix this, you need to add controllerB as a child of controller a.
Back in ControllerA's class:
- (void)viewDidLoad
{
[super viewDidLoad];
self.controllerB = [[ControllerB alloc] initWithNibName:#"ControllerB" bundle:nil];
if ([self respondsToSelector:#selector(addChildViewController:)])
[self addChildViewController:self.controllerB];
[self.view addSubview:self.controllerB.view];
}
This will now work as expected in both iOS4 and iOS5 without resorting to the horrible hack of checking iOS version strings, but instead checking on if the function we're after is available.
Hope this helps.
It is iOS5 behavior:
viewWillAppear, viewDidAppear, ... are executed automatically after addSubView: for iOS5.
So for iOS5 no need to execute manually those methods as need for iOS<5.0.
The fix may be:
if ([[UIDevice currentDevice].systemVersion doubleValue] < 5.0) {
...execute viewWillAppear or other
}
By this method u know which os u use and put condition if is less then 5.0 or other one
[[UIDevice currentDevice] systemVersion]
view{Will,Did}Appear, view{Will,Did}Disappear are functions on View Controllers and not views. These functions are called by SDK provided view controllers that are supposed to manage other view controllers e.g. UITabBarController, UINavigationBarController.
If you are managing sub-view controllers yourself, you have to call these explicitly (and in proper order - though you should have a very good reason to do this). A modal view not getting these calls upon dismissal of a modal view is simply because there is no one there to call it. Encapsulate the root view controller in a UINavigationController (and hide the navigation bar if you like) and then open a modal view controller. Upon its dismissal, or pop, viewWillAppear will get called.
After reviewing all the evidence, I think the best thing to do is NOT use viewDidAppear etc for views that are affected by this ios 4 / ios 5 bug. Instead make a custom class (like viewDidAppearCustom) and call it yourself. this way you can guarantee that apple won't change the sdk again and mess you up. There is a great blog covering this issue here:
http://gamesfromwithin.com/view-controller-notification-changes-on-ios5

performSelector throws UIViewControllerHierarchyInconsistency exception

I was developing my application on XCode 4.1, for iOs 4.3, but yesterday I've updated it to XCode 4.2 with iOs 5.0 SDK.
When I run my application in iphone 4.3 simulator, it works great.
I decided to test it on iphone 5.0 simulator, and following problems appeared:
I've got a view controller f.e "MyViewController", and a custom class which implements some custom component "MyCustomComponent" which is added to "MyViewController". There is a button in MyCustomComponent, and when its touched it peformSelector from MyViewController, and it leads to crash with EXC_BAD something. Same code works on iPhone 4.3 simulator just perfectly. Any ideas?
Custom navigation bar - doesn't work at all. I'm trying to set custom background implementing UINavigationBar, and overriding drawRect, but it doesn't shows in ios 5.
OK, so i guess I figrued it out. My console was off, when i reinstalled xcode, so didn't see any error messages. Turned it on now, and got an error
Terminating app due to uncaught exception
'UIViewControllerHierarchyInconsistency'
Problem was that I was adding MyCustomComponent to MyViewController using
self.view=myCustomComponent.view
when I should be doing
[self.view addSubview:myCustomCoponent.view]
it wasn't an issue in ios 4.3, but seems its a big deal in ios 5.
I struggled with the same problem.
When you create a new Master-Detail Application(without story board), you can see this codes below from AppDelegate.m.
MasterViewController *masterViewController = [[MasterViewController alloc] initWithNibName:#"MasterViewController" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:masterViewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
"BE NOT DEPENDENT ON MainWindow"
Just start from your own ViewController and set it to delegate.
And don't forget to unlink view from MainWindow.xib else the view will called 2 times.
EXC_BAD_ACCESS implies that the object doesn't exist. Try NSLog-ging the object on which you are performing the performSelector-method.
EDIT: If it crashes when you try logging it, it has been dealloced. Check if you retain the object correctly!
If it is a valid object, try:
if(![obj respondsToSelector:#selector(mySelector:)]){NSLog(#"no such method!");}

Xcode 4: nib files not loading when run

So, I just downloaded Xcode 4 and installed it. I was actually quite looking forward to the single window and integrated IB...
-
However, when I open and run one of my projects, the nib files that the project uses don't seem to load. Instead I'm left looking at a blank white screen (iPhone). This project ran well and fine on Xcode 3.2.
If I background and un-background the app, the view loads fine. But this happens every time I build, on both iPhone and iOS simulator, i.e. the app doesn't work properly until it's been backgrounded. All the code for loading the view follows from
- (void)applicationDidFinishLaunching:(UIApplication *)application.
-
Did anyone else have the same nib file problems - is there a fix (or something stupidly simple that I'm forgetting about)?
Ok after a lot of messing around, I figured out the nib problem.
I had a stray line of code in the appDelegate class:
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
This line of code doesn't affect anything when compiling with Xcode 3.2, but with Xcode 4 causes the loading problem. Just remove it (I don't even remember why it was there...) and it's fixed :)
I'm not sure what's going on with your nibs, but this XCode 4 transition guide should be of some help for finding missing panels, menus etc...
I had the same problem. In my case, for some reason Xcode had decided to hide the view in question. It cleared up when I put the following into the viewDidAppear method of the view controller:
self.view.hidden = NO;
For anyone with the same error. If upper won't help - check if you did not overwrite the view attribute of your ViewController.