我没有收到任何构建错误,但是一旦我进入模拟器并按右上角的 + 添加新 url,程序就会崩溃。这是我得到的错误:
2017-02-21 09:37:48.667 收藏的网站 [2211:128142] -> [Favorite_Websites.MasterViewController addButtonPressed:]:无法识别的选择器发送到实例 0x7ff266408aa0 2017-02-21 09:37:48.672 收藏的网站 [2211:128142] *由于未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:'-[Favorite_Websites.MasterViewController addButtonPressed:]:无法识别的选择器发送到实例0x7ff266408aa0'*第一次抛出调用堆栈:(0 CoreFoundation 0x000000010d0b0d4bexceptionPreprocess + 171 1 libobjc.A.dylib 0x000000010cb1221e objc_exception_throw + 48 2 CoreFoundation 0x000000010d120f04 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132 3 CoreFoundation 0x000000010d036005 ___forwarding_+ 1013 4 CoreFoundation 0x000000010d035b88 _CF_forwarding_prep_0 + 120 5 UIKit 0x000000010d4d68bc -[UIApplication sendAction:to:from:forEvent:] + 83 6 UIKit 0x000000010d9184a1 -[UIBarButtonItem(UIInternal) _sendAction:withEvent:] + 149 7 UIKit 0x000000010d4d68bc -[UIApplication sendAction:to :from:forEvent:] + 83 8 UIKit 0x000000010d65cc38 -[UIControl sendAction:to:forEvent:] + 67 9 UIKit 0x000000010d65cf51 -[UIControl _sendActionsForEvents:withEvent:] + 444 10 UIKit 0x000000010d65d0db -[UIControlsendForEvent:]] + 838 11 UIKIT 0x000000010D65BE4D- [UICONTROL接触:withEvent:] + 668 12 UIKIT 0x000000010D5444545- [UIWINDOW _SENDTOW _SENDTOUCHESFOREVENT:] UIKit 0x000000010dcdf72d] + 371 15 UIKit 0x000000010dcdf72d] + 371 15 UIKit 0x000000010dcdf72ddispatchPreprocessedEventFromEventQueue + 3248 16 UIKit 0x000000010dcd8463 __handleEventQueue + 4879 17 CoreFoundation 0x000000010d055761 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION+ 17 18 CoreFoundation 0x000000010d03a98c __CFRunLoopDoSources0 + 556 19 CoreFoundation 0x000000010d039e76 __CFRunLoopRun + 918 20 CoreFoundation 0x000000010d039884 CFRunLoopRunSpecific + 420 21 GraphicsServices 0x000000011173fa6f GSEventRunModal + 161 22 UIKit 0x000000010d4d4c68 UIApplicationMain + 159 23 Favorite Websites 0x000000010c516e0f main + 111 24 libdyld.dylib 0x00000001107af68d start + 1 ) libc+ +abi.dylib:以 NSException (lldb) 类型的未捕获异常终止
这是错误来自的 MasterViewController.swift 代码。
class MasterViewController: UITableViewController, ModelDelegate {
var detailViewController: DetailViewController? = nil
var model: Model! = nil // manages the app's data
// conform to ModelDelegate protocol; updates view wehn model changes
func modelDataChanged(){
tableView.reloadData() // reload the UITableView
}
// called after the view loads for further UI configuration
override func viewDidLoad() {
super.viewDidLoad()
// set up left and right UIBarButtonItems
self.navigationItem.leftBarButtonItem = self.editButtonItem
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: Selector(("addButtonPressed:")))
self.navigationItem.rightBarButtonItem = addButton
if let split = self.splitViewController {
let controllers = split.viewControllers
self.detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
}
model = Model(delegate: self) // create the Model
model.synchronize() // tell model to sync its data
}
// displays a UIAlertController to obtain new url from user
func addButtonPressed(sender: AnyObject) {
displayAddEditurlSearchAlert(isNew: true, index: nil)
}
// handles long press for editing or sharing a url
func tableViewCellLongPressed(
sender: UILongPressGestureRecognizer){
if sender.state == UIGestureRecognizerState.began &&
!tableView.isEditing {
let cell = sender.view as! UITableViewCell // get cell
if let indexPath = tableView.indexPath(for: cell) {
displayLongPressOptions(row: indexPath.row)
}
}
}
// displays the edit/share options
func displayLongPressOptions(row: Int){
// create UIAlertController for user input
let alertController = UIAlertController(title: "Options",
message: "Edit or Share your url",
preferredStyle: UIAlertControllerStyle.alert)
// create Cancel action
let cancelAction = UIAlertAction(title: "Cancel",
style: UIAlertActionStyle.cancel, handler: nil)
alertController.addAction(cancelAction)
let editAction = UIAlertAction(title: "Edit",
style: UIAlertActionStyle.default,
handler: {(action) in
self.displayAddEditurlSearchAlert(isNew: false, index: row)})
alertController.addAction(editAction)
let shareAction = UIAlertAction(title: "Share",
style: UIAlertActionStyle.default,
handler: {(action) in self.shareurlSearch(index: row)})
alertController.addAction(shareAction)
present(alertController, animated: true,
completion: nil)
}
// displays add/edit dialog
func displayAddEditurlSearchAlert(isNew: Bool, index: Int?){
// create UIAlertController for user input
let alertController = UIAlertController(
title: isNew ? "Add URL" : "Edit URL",
message: isNew ? "" : "Modify your URL",
preferredStyle: UIAlertControllerStyle.alert)
// create UITextFields in which user can enter a new URL
alertController.addTextField(
configurationHandler: {(textField) in
if isNew {
textField.placeholder = "Enter URL"
}else{
textField.text = self.model.queryForTagAtIndex(index: index!)
}
})
alertController.addTextField(
configurationHandler: {(textField) in
if isNew {
textField.placeholder = "Tag your URL"
}else {
textField.text = self.model.tagAtIndex(index: index!)
textField.isEnabled = false
textField.textColor = UIColor.lightGray
}
})
// create Cancel action
let cancelAction = UIAlertAction(title: "Cancel",
style: UIAlertActionStyle.cancel, handler: nil)
alertController.addAction(cancelAction)
let saveAction = UIAlertAction(title: "Save",
style: UIAlertActionStyle.default,
handler: {(action) in
let query =
((alertController.textFields?[0])! as UITextField).text
let tag =
((alertController.textFields?[1])! as UITextField).text
// ensure query and tag are not empty
if !query!.isEmpty && !tag!.isEmpty {
self.model.saveQuery(
query: query!, forTag: tag!, syncToCloud: true)
if isNew {
let indexPath =
IndexPath(row: 0, section: 0)
self.tableView.insertRows(at: [indexPath],
with: .automatic)
}
}
})
alertController.addAction(saveAction)
present(alertController, animated: true,
completion: nil)
}
// displays share sheet
func shareurlSearch(index: Int) {
let message = "Check out this cool Web site"
let urlString = urlEncodeString(string: model.queryForTagAtIndex(index: index)!)
let itemsToShare = [message, urlString]
// create UIActivityViewController so user can share url
let activityViewController = UIActivityViewController(
activityItems: itemsToShare, applicationActivities: nil)
present(activityViewController,
animated: true, completion: nil)
}
// MARK: - Segues
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
// get query String
let query = String(model.queryForTagAtIndex(index: indexPath.row)!)
// create NSURL to perfrom url search
controller.detailItem = NSURL(string: urlEncodeString(string: query!))
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
}
// returns a URL encoded version of the query String
func urlEncodeString(string: String) -> String {
return string.addingPercentEncoding(
withAllowedCharacters: NSCharacterSet.urlQueryAllowed)!
}
// MARK: - Table View
// callback that returns total number of sections in UITableView
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
// callback that returns number of rows in the UITableView
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return model.count
}
// callback that returns a configured cell for the given NSIndexPath
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// get cell
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as UITableViewCell
// set up long press guesture recognier
cell.textLabel!.text = model.tagAtIndex(index: indexPath.row)
// set up long press guesture recognizer
let longPressGestureRecognizer = UILongPressGestureRecognizer(
target: self, action: Selector(("tableViewCellLongPressed:")))
longPressGestureRecognizer.minimumPressDuration = 0.5
cell.addGestureRecognizer(longPressGestureRecognizer)
return cell
}
//callback that return whether a cell is editable
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true // all cells are editable
}
// callback that deletes a row from the UITableView
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
model.deleteurlSearchAtIndex(index: indexPath.row)
// remove UITableView row
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
// callback that returns whether cells can be moved
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
// callback that reorders keys when user moves them in the table
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath,
to destinationIndexPath: IndexPath) {
// tell model to reorder tags based on UITableView order
model.moveTagAtIndex(oldIndex: sourceIndexPath.row,
toDestinationIndex: destinationIndexPath.row)
}
}