プログラミング初心者です。Tab Bar Controllerについて質問があります。
私が使っているのはXcode Version 8.1、Swiftです。
カウントダウンタイマーとTo Do Listを別々のプロジェクトで作り終わり、その二つのアプリを一つのアプリにまとめたいと思っています。
新しいプロジェクトを作り、Tab Bar Controllerを使いながら二つのアプリをもう一度作り直していったのですが、シミュレーターを起動させると
Thread 1: signal SIGABRT
という赤いエラーがAppDelegateの
class AppDelegate: UIResponder, UIApplicationDelegate {
に発生し、シミュレーターが止まります。
エラーの説明のようなものには
> 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)
と書かれているのですが、いまいち理解できません。同じような質問をされている方がたくさんいたので、その解決方法(connectionを確認する、再起動する、など)をすべて試してみたのですが、直りませんでした。
問題はなんなのでしょうか?
また、Tab Bar Controllerの使い方や、複数のアプリを一つにまとめる方法は合っていますでしょうか?
AppDelegate.swift
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
} }
PomodoroViewController.swift
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()
}
}
}
ToDoListViewController.swift
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
}
}
}