Tab Bar Controller - エラー Thread 1: signal SIGABRT


プログラミング初心者です。Tab Bar Controllerについて質問があります。

私が使っているのはXcode Version 8.1、Swiftです。

カウントダウンタイマーとTo Do Listを別々のプロジェクトで作り終わり、その二つのアプリを一つのアプリにまとめたいと思っています。  
新しいプロジェクトを作り、Tab Bar Controllerを使いながら二つのアプリをもう一度作り直していったのですが、シミュレーターを起動させると

> Thread 1: signal SIGABRT

という赤いエラーがAppDelegateの

[code]

    class AppDelegate: UIResponder, UIApplicationDelegate {
    
[/code]

に発生し、シミュレーターが止まります。  
エラーの説明のようなものには

[code]

    > 2017-01-06 19:55:12.188 PP Final Product[60637:3223775] Unknown class PomodoroViewController in Interface Builder file.
    2017-01-06 19:55:12.571 PP Final Product[60637:3223775] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<UIViewController 0x7fddcff03760> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key lbTimer.'
    *** First throw call stack:
    (
        0   CoreFoundation                      0x000000010242734b __exceptionPreprocess + 171
        1   libobjc.A.dylib                     0x0000000101e8821e objc_exception_throw + 48
        2   CoreFoundation                      0x0000000102427299 -[NSException raise] + 9
        3   Foundation                          0x000000010199826f -[NSObject(NSKeyValueCoding) setValue:forKey:] + 291
        4   UIKit                               0x00000001029e44ef -[UIViewController setValue:forKey:] + 88
        5   UIKit                               0x0000000102c5879e -[UIRuntimeOutletConnection connect] + 109
        6   CoreFoundation                      0x00000001023cc590 -[NSArray makeObjectsPerformSelector:] + 256
        7   UIKit                               0x0000000102c57122 -[UINib instantiateWithOwner:options:] + 1867
        8   UIKit                               0x00000001029eac21 -[UIViewController _loadViewFromNibNamed:bundle:] + 386
        9   UIKit                               0x00000001029eb543 -[UIViewController loadView] + 177
        10  UIKit                               0x00000001029eb878 -[UIViewController loadViewIfRequired] + 201
        11  UIKit                               0x00000001029ec0cc -[UIViewController view] + 27
        12  UIKit                               0x0000000102a4a2df -[UITabBarController transitionFromViewController:toViewController:transition:shouldSetSelected:] + 483
        13  UIKit                               0x0000000102a49721 -[UITabBarController transitionFromViewController:toViewController:] + 59
        14  UIKit                               0x0000000102a455e2 -[UITabBarController _setSelectedViewController:] + 365
        15  UIKit                               0x0000000102a45464 -[UITabBarController setSelectedViewController:] + 234
        16  UIKit                               0x00000001029036e6 +[UIView(Animation) performWithoutAnimation:] + 90
        17  UIKit                               0x0000000102a3fa00 -[UITabBarController _selectDefaultViewControllerIfNecessaryWithAppearanceTransitions:] + 354
        18  UIKit                               0x0000000102a40b7a -[UITabBarController viewWillAppear:] + 206
        19  UIKit                               0x00000001029f1a0f -[UIViewController _setViewAppearState:isAnimating:] + 692
        20  UIKit                               0x00000001029f211f -[UIViewController __viewWillAppear:] + 147
        21  UIKit                               0x00000001029f3913 -[UIViewController viewWillMoveToWindow:] + 507
        22  UIKit                               0x00000001028fa151 -[UIView(Hierarchy) _willMoveToWindow:withAncestorView:] + 621
        23  UIKit                               0x000000010290acf0 -[UIView(Internal) _addSubview:positioned:relativeTo:] + 451
        24  UIKit                               0x00000001028f97a1 -[UIView(Hierarchy) addSubview:] + 838
        25  UIKit                               0x00000001028b5f5b -[UIWindow addRootViewControllerViewIfPossible] + 849
        26  UIKit                               0x00000001028b63a2 -[UIWindow _setHidden:forced:] + 293
        27  UIKit                               0x00000001028c9cb5 -[UIWindow makeKeyAndVisible] + 42
        28  UIKit                               0x0000000102842c89 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4818
        29  UIKit                               0x0000000102848de9 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1731
        30  UIKit                               0x0000000102845f69 -[UIApplication workspaceDidEndTransaction:] + 188
        31  FrontBoardServices                  0x0000000106238723 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 24
        32  FrontBoardServices                  0x000000010623859c -[FBSSerialQueue _performNext] + 189
        33  FrontBoardServices                  0x0000000106238925 -[FBSSerialQueue _performNextFromRunLoopSource] + 45
        34  CoreFoundation                      0x00000001023cc311 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
        35  CoreFoundation                      0x00000001023b159c __CFRunLoopDoSources0 + 556
        36  CoreFoundation                      0x00000001023b0a86 __CFRunLoopRun + 918
        37  CoreFoundation                      0x00000001023b0494 CFRunLoopRunSpecific + 420
        38  UIKit                               0x00000001028447e6 -[UIApplication _run] + 434
        39  UIKit                               0x000000010284a964 UIApplicationMain + 159
        40  PP Final Product                    0x000000010189782f main + 111
        41  libdyld.dylib                       0x0000000105aa168d start + 1
        42  ???                                 0x0000000000000001 0x0 + 1
    )
    libc++abi.dylib: terminating with uncaught exception of type NSException
    (lldb) 
    
[/code]

と書かれているのですが、いまいち理解できません。同じような質問をされている方がたくさんいたので、その解決方法（connectionを確認する、再起動する、など）をすべて試してみたのですが、直りませんでした。

問題はなんなのでしょうか？  
また、Tab Bar Controllerの使い方や、複数のアプリを一つにまとめる方法は合っていますでしょうか？

AppDelegate.swift

[code]

    import UIKit
    
    @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate {
    
        internal var window: UIWindow?
    
        private var myTabBarController: UITabBarController!
    
        private func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?)
    -> Bool {
    
            window = UIWindow(frame: UIScreen.main.bounds)
    
            let myFirstTab: UIViewController = PomodoroViewController()
            let mySecondTab: UIViewController = ToDoListViewController()
    
            let myTabs = NSArray(objects: myFirstTab, mySecondTab)
    
            myTabBarController = UITabBarController()
    
            myTabBarController?.setViewControllers(myTabs as? [UIViewController], animated: false)
    
            self.window!.rootViewController = myTabBarController
    
            self.window!.makeKeyAndVisible()
    
            return true
        } }
    
[/code]

PomodoroViewController.swift

[code]

    import UIKit
    
    class PomodoroViewController: UIViewController {
    
        init() {
            super.init(nibName: nil, bundle: nil)
    
            self.tabBarItem = UITabBarItem(tabBarSystemItem: UITabBarSystemItem.featured, tag: 1)
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
        }
    
        required override init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: Bundle!) {
            super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        }
    
        @IBOutlet weak var lbTimer: UILabel!
    
        let pomodoroTime: TimeInterval = 60 * 25
    
        let formatter = DateFormatter()
    
        var theTime: TimeInterval = 0.0
    
        override func viewDidLoad(){
            super.viewDidLoad()
    
            formatter.dateFormat = "mm:ss"
    
            let startTime = Date(timeIntervalSinceReferenceDate: pomodoroTime)
            lbTimer.text = formatter.string(from: startTime)
        }
    
        override func didReceiveMemoryWarning(){
            super.didReceiveMemoryWarning()
        }
    
        @IBAction func countDown(_ sender: UIButton) {
    
            theTime = pomodoroTime
            Timer.scheduledTimer(timeInterval: 1.0,
                                 target: self,
                                 selector: #selector(PomodoroViewController.tickTimer(timer:)),
                                 userInfo: nil,
                                 repeats: true)
        }
    
        func tickTimer(timer: Timer){
    
            theTime -= 1.0
            let newTime = Date(timeIntervalSinceReferenceDate: theTime)
            lbTimer.text = formatter.string(from: newTime)
    
            if theTime < 0.1 {
                timer.invalidate()
            }
        }
         }
    
[/code]

ToDoListViewController.swift

[code]

    import UIKit
    
    class ToDoListViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, AddToDoItemControllerDelegate {
    
        init() {
            super.init(nibName: nil, bundle: nil)
    
            self.tabBarItem = UITabBarItem(tabBarSystemItem: UITabBarSystemItem.featured, tag: 2)
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
        }
    
        required override init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: Bundle!) {
            super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        }
    
        @IBOutlet weak var tableView: UITableView!
    
        var toDoList: NSMutableArray = ["Go get groceries", "Walk the dog", "Watch a movie", "Do your homework"]
    
        var completedToDoList: [Int:String] = [:]
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            tableView.delegate = self
            tableView.dataSource = self
        }
    
        override func viewWillAppear(_ animated: Bool) {
            resetAccessoryType()
            tableView.reloadData()
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return toDoList.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "ToDoCell", for: indexPath)
            cell.textLabel?.text = toDoList[indexPath.row] as? String
    
            return cell
        }
    
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
    
        func resetAccessoryType() {
            for row in 0..<toDoList.count {
                if let cell = tableView.cellForRow(at: IndexPath(row: row, section: 0)) {
                    cell.accessoryType = .none
                }
            }
        }
    
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            tableView.deselectRow(at: indexPath, animated: true)
    
            if let cell = tableView.cellForRow(at: indexPath) {
                if cell.accessoryType == .none {
                    cell.accessoryType = .checkmark
                    completedToDoList[completedToDoList.count] = toDoList[indexPath.row] as? String
                    toDoList.removeObject(at: indexPath.row)
                } else {
                    cell.accessoryType = .none
                }
            }
        }
    
        func addToDoItemToList(_ text:String) {
            toDoList[toDoList.count] = text
    
            tableView.reloadData()
        }
    
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if(segue.identifier == "AddToDoItemSegue") {
                let navigationController = segue.destination as! UINavigationController
                let addToDoItemViewController = navigationController.topViewController as! AddToDoItemController
    
                addToDoItemViewController.delegate = self
            } else if(segue.identifier == "CompletedToDoItemsSegue") {
                let completedToDoItemsController = segue.destination as! CompletedToDoItemsController
                completedToDoItemsController.completedToDoList = completedToDoList
            }
        }
         }
    
[/code]




AppDelegate.swiftに記述しているコードは、Storyboardなしでプロジェクトを構成するときのもので、Storyboardを使ったプロジェクトでは記述しません。プロジェクト作成時に戻しましょう。  
アプリケーション起動時、Storyboardはどうやってロードされるのか説明します。プロジェクト設定のGeneralを開くと、次の箇所があります。  
[![画像の説明をここに入力](https://i.stack.imgur.com/VlHLu.png)](https://i.stack.imgur.com/VlHLu.png)  
このMain
Interfaceに入力した名称のStoryboardが、起動時ロードされます。デフォルトでは、Main.storyboardがロードされます。余談ですが、Storyboardなしのプロジェクトにするときは、ここを空にします。

* * *

次に、Storyboardに`UITabBarController`を導入する方法を説明します。手っ取り早いのは、プロジェクト作成時に、Tabbed
Applicationのテンプレートから作成することです。

[![画像の説明をここに入力](https://i.stack.imgur.com/NFr9Y.png)](https://i.stack.imgur.com/NFr9Y.png)

そうでない場合は、Object LibraryからTab Bar Controllerをドラッグ＆ドロップします。

[![画像の説明をここに入力](https://i.stack.imgur.com/T2crB.png)](https://i.stack.imgur.com/T2crB.png)

Storyboardの編集では、Storyboardで最初にロードされるView
Controllerが何かを、まず意識することです。最初にロードするView Controllerを、Storyboardでは、 **Initial
View Controller** と呼びます。

[![画像の説明をここに入力](https://i.stack.imgur.com/SxZQO.png)](https://i.stack.imgur.com/SxZQO.png)

View Controllerの左側に、矢印がついて、それがInitial View Controllerであることを示しています。View
ControllerのAttributes Inspectorの「Is Initial View
Controller」にチェックをつけることで、Initial View
Controllerを変更することができます。現時点で、`UITabBarController`がInitial View
Controllerになっていなければ、変更してください。

* * *

`UITabBarController`のタブに、View Controllerを追加するには、右ボタン＋ドラッグ（Controlキー＋ドラッグ）で、Tab
Bar ControllerとView Controllerを結びます。ダイアログで、Relationship Segue、view
controllersを選びます。

[![画像の説明をここに入力](https://i.stack.imgur.com/wb3Dx.png)](https://i.stack.imgur.com/wb3Dx.png)

ここで注意してもらいたいことは、ToDoListのように、`UINavigationController`によって画面遷移する一連のView
Controllerは、Tab Bar Controllerと、Navigation Controllerをつなぐという点です。

[![画像の説明をここに入力](https://i.stack.imgur.com/DZev0.png)](https://i.stack.imgur.com/DZev0.png)

そうしないと、画面遷移が機能しなくなります。

* * *

_この回答は、質問者さんのレスポンスによって、内容を更新していく予定にしています。_




AppDelegate.swiftに記述しているコードは、Storyboardなしでプロジェクトを構成するときのもので、Storyboardを使ったプロジェクトでは記述しません。プロジェクト作成時に戻しましょう。  
アプリケーション起動時、Storyboardはどうやってロードされるのか説明します。プロジェクト設定のGeneralを開くと、次の箇所があります。  
[![画像の説明をここに入力](https://i.stack.imgur.com/VlHLu.png)](https://i.stack.imgur.com/VlHLu.png)  
このMain
Interfaceに入力した名称のStoryboardが、起動時ロードされます。デフォルトでは、Main.storyboardがロードされます。余談ですが、Storyboardなしのプロジェクトにするときは、ここを空にします。

* * *

次に、Storyboardに`UITabBarController`を導入する方法を説明します。手っ取り早いのは、プロジェクト作成時に、Tabbed
Applicationのテンプレートから作成することです。

[![画像の説明をここに入力](https://i.stack.imgur.com/NFr9Y.png)](https://i.stack.imgur.com/NFr9Y.png)

そうでない場合は、Object LibraryからTab Bar Controllerをドラッグ＆ドロップします。

[![画像の説明をここに入力](https://i.stack.imgur.com/T2crB.png)](https://i.stack.imgur.com/T2crB.png)

Storyboardの編集では、Storyboardで最初にロードされるView
Controllerが何かを、まず意識することです。最初にロードするView Controllerを、Storyboardでは、 **Initial
View Controller** と呼びます。

[![画像の説明をここに入力](https://i.stack.imgur.com/SxZQO.png)](https://i.stack.imgur.com/SxZQO.png)

View Controllerの左側に、矢印がついて、それがInitial View Controllerであることを示しています。View
ControllerのAttributes Inspectorの「Is Initial View
Controller」にチェックをつけることで、Initial View
Controllerを変更することができます。現時点で、`UITabBarController`がInitial View
Controllerになっていなければ、変更してください。

* * *

`UITabBarController`のタブに、View Controllerを追加するには、右ボタン＋ドラッグ（Controlキー＋ドラッグ）で、Tab
Bar ControllerとView Controllerを結びます。ダイアログで、Relationship Segue、view
controllersを選びます。

[![画像の説明をここに入力](https://i.stack.imgur.com/wb3Dx.png)](https://i.stack.imgur.com/wb3Dx.png)

ここで注意してもらいたいことは、ToDoListのように、`UINavigationController`によって画面遷移する一連のView
Controllerは、Tab Bar Controllerと、Navigation Controllerをつなぐという点です。

[![画像の説明をここに入力](https://i.stack.imgur.com/DZev0.png)](https://i.stack.imgur.com/DZev0.png)

そうしないと、画面遷移が機能しなくなります。

* * *

_この回答は、質問者さんのレスポンスによって、内容を更新していく予定にしています。_

