Don't work with new Xcode 7 version

I download project from BNR site and open with the fresh update of Xcode Version 7.0 (7A220). Run failed with that message :

2015-09-17 16:00:50.679 iTahDoodle[7199] *** Assertion failure in -[UIApplication _runWithMainScene:transitionContext:completion:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3505.16/UIApplication.m:3294 2015-09-17 16:00:50.682 iTahDoodle[7199] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Application windows are expected to have a root view controller at the end of application launch' *** First throw call stack: ( 0 CoreFoundation 0x020a1a94 __exceptionPreprocess + 180 1 libobjc.A.dylib 0x01b62e02 objc_exception_throw + 50 2 CoreFoundation 0x020a192a +[NSException raise:format:arguments:] + 138 3 Foundation 0x017e23e6 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 118 4 UIKit 0x002ee568 -[UIApplication _runWithMainScene:transitionContext:completion:] + 3674 5 UIKit 0x00311905 __84-[UIApplication _handleApplicationActivationWithScene:transitionContext:completion:]_block_invoke3171 + 68 6 UIKit 0x002eabae -[UIApplication workspaceDidEndTransaction:] + 163 7 FrontBoardServices 0x0433bccc __37-[FBSWorkspace clientEndTransaction:]_block_invoke_2 + 71 8 FrontBoardServices 0x0433b7a3 __40-[FBSWorkspace _performDelegateCallOut:]_block_invoke + 54 9 FrontBoardServices 0x043591cb -[FBSSerialQueue _performNext] + 184 10 FrontBoardServices 0x04359602 -[FBSSerialQueue _performNextFromRunLoopSource] + 52 11 FrontBoardServices 0x043588fe FBSSerialQueueRunLoopSourceHandler + 33 12 CoreFoundation 0x01fbbe7f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15 13 CoreFoundation 0x01fb1b0b __CFRunLoopDoSources0 + 523 14 CoreFoundation 0x01fb0f28 __CFRunLoopRun + 1032 15 CoreFoundation 0x01fb0866 CFRunLoopRunSpecific + 470 16 CoreFoundation 0x01fb067b CFRunLoopRunInMode + 123 17 UIKit 0x002ea497 -[UIApplication _run] + 540 18 UIKit 0x002efcc1 UIApplicationMain + 160 19 iTahDoodle 0x0004237a main + 138 20 libdyld.dylib 0x02acba21 start + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException (lldb)

I was able to get the project in this chapter to work under Xcode 7 by making a few changes.

  1. Make your project a Single View Application.

  2. In top level of the project in the “Info” tab, delete the entry “Main Storybord file base name” by hitting the minus sign.

  3. Delete the Main.storyboard and LaunchScreen.storyboard files

AppDelegate.h

#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic) NSMutableArray *tasks;
@end

AppDelegate.m

#import "AppDelegate.h"
#import "ViewController.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    CGRect winFrame = [[UIScreen mainScreen] bounds];
    self.window = [[UIWindow alloc] initWithFrame];
    self.window.rootViewController = [[ViewController alloc] init];    
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];        
    return YES;
}

All else in AppDelegate.m as default

ViewController.h

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (nonatomic) UITableView *taskTable;
@property (nonatomic) UITextField *taskField;
@property (nonatomic) UIButton *insertButton;
- (void)addTask:(id)sender;
@end

ViewController.m

#import "ViewController.h"
@interface ViewController ()
@end

@implementation ViewController

- (void)loadView
{
    CGRect frame = [UIScreen mainScreen].bounds;
    MyView *backgroundView = [[MyView alloc] initWithFrame:frame];
    // Define frame rectangles
    CGRect tableFrame = CGRectMake(0, 80, frame.size.width,
                                   frame.size.height - 100);
    CGRect fieldFrame = CGRectMake(20, 40, 200, 31);
    CGRect buttonFrame = CGRectMake(228, 40, 72, 31);
    
    // Table view
    self.taskTable = [[UITableView alloc] initWithFrame:tableFrame
                                                  style:UITableViewStylePlain];
    self.taskTable.separatorStyle = UITableViewCellSeparatorStyleNone;
    
    // Tell table view which class to instantiate
    // whenever it needs to create a new cell
    [self.taskTable registerClass:[UITableViewCell class]
           forCellReuseIdentifier:@"Cell"];
    
    // Create Task field
    self.taskField = [[UITextField alloc] initWithFrame:fieldFrame];
    self.taskField.borderStyle = UITextBorderStyleRoundedRect;
    self.taskField.placeholder = @"Type a task, tap Insert";
    
    // Create the Button
    self.insertButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    self.insertButton.frame = buttonFrame;
    
    // Give button title
    [self.insertButton setTitle:@"Insert"
                       forState:UIControlStateNormal];
    
    // set target and action
    [self.insertButton addTarget:self
                          action:@selector(addTask:)
                forControlEvents:UIControlEventTouchUpInside];
    
    [backgroundView addSubview:self.taskTable];
    [backgroundView addSubview:self.taskField];
    [backgroundView addSubview:self.insertButton];

    self.view = backgroundView;
    
   }

- (void)addTask:(id)sender
{   
    NSString *text = [self.taskField text];
    
    // Quit here if taskField is empty
    if ([text length] == 0) {
        return;
    }
    
    // Log text to console
    NSLog(@"Task entered: %@", text);
    
    // Clear out the text field
    [self.taskField setText:@""];
    // Dismiss the keyboard
    [self.taskField resignFirstResponder];
}

@end

MyView.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface MyView : UIView
@end

MyView.m

#import "MyView.h"
@implementation MyView
@end

I’m also getting the errors when running in the simulator using Xcode 7. Is there anyway around this without having to create the extra ViewController and MyView classes?

I’ve been doing some research and managed to find two things that have worked out.

Firstly, there is an Empty Application template you can reinstate to Xcode 7. The link was mentioned in another thread but I’m adding it here for ease. Follow the instructions for installing.

https://www.reddit.com/r/iOSProgramming/comments/2a3jyr/xcode_6_beta_3_removes_empty_application_option/

Secondly, after doing this still didn’t work I read a little more about the error that is thrown and it would seem that in Xcode 7, all windows must have a rootViewController, which is obviously not mentioned in the book. A thread over at Stackoverflow (link below) mentioned this requirement providing the following code:

from http://stackoverflow.com/questions/30884896/application-windows-are-expected-to-have-a-root-view-controller-at-the-end-of-a

So between using the Empty Application template with Xcode 7 and manipulating the code setting the rootViewController I got this:

//Create and confirgure the UIWindow instance // A CGRect is a struct with an origin (x,y) and a size (width,height) CGRect winFrame = [[UIScreen mainScreen] bounds]; UIWindow *theWindow = [[UIWindow alloc] initWithFrame]; UIViewController* vc = [[UIViewController alloc]initWithNibName:nil bundle:nil]; theWindow.rootViewController = vc; self.window = theWindow;
Hope this helps someone else and I’m sure I’ll be back on with my next issue shortly!

Looks like I did run into issues and stormville’s solution was the only way to get it working.

stormville - Can you explain what the MyView class is actually doing and where the - (void)loadView method comes from. I don’t see it called anywhere?

johnashmore–
The View Controller needs to have a view attached to it. That’s what the MyView class is there for. It’s attached in this line:

self.view = backgroundView;

The loadView method is a system callback. It’s called by the system when the view is first displayed. For more info on this, see the documentation for UIViewController.

Hi stormville,

This makes a bit more sense now. I thought loadView must be a method from one of the provided classes but didn’t know where. I need to get better at checking through the documentation.

Thanks for your help!

[quote=“stormville”]johnashmore–
The View Controller needs to have a view attached to it. That’s what the MyView class is there for. It’s attached in this line:

self.view = backgroundView;

The loadView method is a system callback. It’s called by the system when the view is first displayed. For more info on this, see the documentation for UIViewController.[/quote]

Is there any reason why you created a new class and just didnt do:

UIView *backgroundView = [[UIView alloc] initWithFrame:frame];

Childs -
No reason, I just did the quickest (for me) thing that would work.

Thank you for sharing . The error is fixed.
I delete MyView.h and MyView.m,“MyView *backgroundView = [[MyView alloc] initWithFrame:frame]” change to “UIView *backgroundView = [[UIView alloc] initWithFrame:frame]”. Because I think MyView class doesn’t work in this example.

But I don’t know why should do like this.Can U explain it。thank you.

I got stuck with a runtime error when I tried to run this app at XCode8.1 and the combination of your post with another one from MikeyWard here on the forum solved it for me. So here’s what I needed to do:

  1. To get the app running I just needed to add the following bold line to the AppDelegate.m file:


UIWindow *theWindow = [[UIWindow alloc] initWithFrame:winFrame];
theWindow.rootViewController = [[UIViewController alloc]init]; // Crucial to make the app run
self.window = theWindow;

This is because apparently now Xcode demands a root view controller instead of just giving a warning.

  1. The app will run, but none of it’s view objects will respond. To get them to respond I used the MikeyWard’s solution:

Now it runs and responds to user events.

Thank you Alex. I did your 2 steps and it worked on Xcode 7.3 for me. Thank you so much.