Uitableview IOS Swift Master Detail应用程序,托管对象,tableView:endUpdates()调用configureCell(),但崩溃,reloadData()不调用它

Uitableview IOS Swift Master Detail应用程序,托管对象,tableView:endUpdates()调用configureCell(),但崩溃,reloadData()不调用它,uitableview,swift,exc-bad-access,nsmanagedobject,reloaddata,Uitableview,Swift,Exc Bad Access,Nsmanagedobject,Reloaddata,我是Swift的新手,我试着制作我的第一个测试应用程序,但我遇到了一个托管对象问题,我想。。。你知道我做错了什么吗 我开始使用Master Detail应用程序模板制作一个应用程序,并尽可能多地使用XCode的故事板来修改基本模板 我修改了TableView以使用自定义TableViewCells: import UIKit class ExpenseItemTableViewCell: UITableViewCell { @IBOutlet weak var whenLabel:

我是Swift的新手,我试着制作我的第一个测试应用程序,但我遇到了一个托管对象问题,我想。。。你知道我做错了什么吗

我开始使用Master Detail应用程序模板制作一个应用程序,并尽可能多地使用XCode的故事板来修改基本模板

我修改了TableView以使用自定义TableViewCells:

import UIKit

class ExpenseItemTableViewCell: UITableViewCell {

    @IBOutlet weak var whenLabel: UILabel!

    @IBOutlet weak var whatLabel: UILabel!

    @IBOutlet weak var locationLabel: UILabel!

    @IBOutlet weak var priceLabel: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        // Configure the view for the selected state
    }
}
我使用ManagedObjects:

import Foundation
import CoreData

@objc(ExpenseItem)
class ExpenseItem: NSManagedObject {

    @NSManaged var when: NSDate
    @NSManaged var location: String
    @NSManaged var what: String
    @NSManaged var howMuch: NSDecimalNumber

}
当从DetailViewController的prepareForSegue展开segue时,我调用一个函数来创建NSManagedObject:

import UIKit

protocol ExpenseItemManagementDelegate {
    func insertExpenseItem(something: String, somePrice: String, somewhere: String, sometime: NSDate)
}

class DetailViewController: UIViewController {

    var delegate: ExpenseItemManagementDelegate!

    @IBOutlet weak var whenInput: UIDatePicker!

    @IBOutlet weak var whatInput: UITextField!

    @IBOutlet weak var locationInput: UITextField!

    @IBOutlet weak var priceInput: UITextField!

    var expenseItem: ExpenseItem? {
        didSet {
            // Update the view.
            self.configureView()
        }
    }

    func configureView() {
        // Update the user interface for the detail item.
        if let item: AnyObject = self.expenseItem {
            if let input = self.whenInput {
                input.date = item.valueForKey("when")! as NSDate
            }
            if let input = self.whatInput {
                input.text = item.valueForKey("what")! as String
            }
            if let input = self.locationInput {
                input.text = item.valueForKey("location")! as String
            }
            if let input = self.priceInput {
                input.text = item.valueForKey("howMuch")! as String
            }
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.configureView()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
        delegate.insertExpenseItem(self.whatInput!.text,somePrice:self.priceInput!.text,somewhere:self.locationInput!.text,sometime:self.whenInput!.date)
    }
}
@IBAction func unwindToSegue (segue : UIStoryboardSegue) {
    if let dvc: DetailViewController = segue.sourceViewController as? DetailViewController
    {
        self.insertExpenseItem(dvc.whatInput!.text,somePrice:dvc.priceInput!.text,somewhere:dvc.locationInput!.text,sometime:dvc.whenInput!.date)
    }
}
或从MasterViewController的unwindToSegue:

import UIKit

protocol ExpenseItemManagementDelegate {
    func insertExpenseItem(something: String, somePrice: String, somewhere: String, sometime: NSDate)
}

class DetailViewController: UIViewController {

    var delegate: ExpenseItemManagementDelegate!

    @IBOutlet weak var whenInput: UIDatePicker!

    @IBOutlet weak var whatInput: UITextField!

    @IBOutlet weak var locationInput: UITextField!

    @IBOutlet weak var priceInput: UITextField!

    var expenseItem: ExpenseItem? {
        didSet {
            // Update the view.
            self.configureView()
        }
    }

    func configureView() {
        // Update the user interface for the detail item.
        if let item: AnyObject = self.expenseItem {
            if let input = self.whenInput {
                input.date = item.valueForKey("when")! as NSDate
            }
            if let input = self.whatInput {
                input.text = item.valueForKey("what")! as String
            }
            if let input = self.locationInput {
                input.text = item.valueForKey("location")! as String
            }
            if let input = self.priceInput {
                input.text = item.valueForKey("howMuch")! as String
            }
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.configureView()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
        delegate.insertExpenseItem(self.whatInput!.text,somePrice:self.priceInput!.text,somewhere:self.locationInput!.text,sometime:self.whenInput!.date)
    }
}
@IBAction func unwindToSegue (segue : UIStoryboardSegue) {
    if let dvc: DetailViewController = segue.sourceViewController as? DetailViewController
    {
        self.insertExpenseItem(dvc.whatInput!.text,somePrice:dvc.priceInput!.text,somewhere:dvc.locationInput!.text,sometime:dvc.whenInput!.date)
    }
}
显然,我使用的函数不是同时从两个位置调用函数

通过单击DetailViewController导航栏中的Cancel或Save展开segue,调用insertExpenseItem函数,并且输入的数据不用于创建NSManagedObject

func insertExpenseItem(something: String, somePrice: String, somewhere: String, sometime: NSDate) {
    let context = self.fetchedResultsController.managedObjectContext
    let entity = self.fetchedResultsController.fetchRequest.entity!
    let expenseManagedObject = NSEntityDescription.insertNewObjectForEntityForName("ExpenseItem", inManagedObjectContext: context) as ExpenseItem
    expenseManagedObject.what = "big mac" // you can now use dot syntax instead of setValue
    expenseManagedObject.howMuch = 500
    expenseManagedObject.location = "macdo"
    expenseManagedObject.when = NSDate()

    // Save the context.
    var error: NSError? = nil
    if !context.save(&error) {
        // Replace this implementation with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        //println("Unresolved error \(error), \(error.userInfo)")
        abort()
    }
}
我尝试在configureCell中的自定义单元格标签中设置值:

func configureCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) {
    let object = self.fetchedResultsController.objectAtIndexPath(indexPath) as ExpenseItem
    let expenseItem = cell as ExpenseItemTableViewCell
    expenseItem.whenLabel.text = object.when.description
    expenseItem.whatLabel.text = object.what
    expenseItem.locationLabel.text = object.location
    expenseItem.priceLabel.text = object.howMuch.description
    expenseItem.backgroundColor = UIColor.orangeColor()
}
我遇到的问题是controllerDidChangeContent:

func controllerDidChangeContent(controller: NSFetchedResultsController) {
    self.tableView.endUpdates()
    // * or *
    //self.tableView.reloadData()
}
func controllerDidChangeContent(controller: NSFetchedResultsController) {
    let context = self.fetchedResultsController.managedObjectContext
    let objects = context.registeredObjects
    println("l=\(objects.count)")
    for o in objects {
        let e = o as ExpenseItem
        println("o when=\(e.when) what=\(e.what) location=\(e.location) price=\(e.howMuch)")
    }
    self.tableView.endUpdates()
}
如果我调用self.tableView.reloadData,则不会调用configureCell,并且表视图在单元格应位于的位置显示一个完全空白的空间,但应用程序不会崩溃 如果我调用self.tableView.endUpdates,则会调用configureCell,但会得到EXC\u BAD\u ACCESScode=2,address=。。。错误 更新日期2014/12/08 以下是堆栈跟踪:

Thread 1
Queue : com.apple.main-thread (serial)
#0  0x000000010a3c6324 in CA::Layer::ensure_transaction_recursively(CA::Transaction*) ()
[...]
#50 0x000000010a3c639a in CA::Layer::ensure_transaction_recursively(CA::Transaction*) ()
#130390 0x000000010a3c639a in CA::Layer::ensure_transaction_recursively(CA::Transaction*) ()
[...]
#130540 0x000000010a3c639a in CA::Layer::ensure_transaction_recursively(CA::Transaction*) ()
#130541 0x000000010a3cdd63 in CA::Layer::insert_sublayer(CA::Transaction*, CALayer*, unsigned long) ()
#130542 0x000000010a3ce14a in -[CALayer addSublayer:] ()
#130543 0x00000001064d2e30 in -[UIView(Internal) _addSubview:positioned:relativeTo:] ()
#130544 0x00000001067d9e01 in -[UITableViewCellLayoutManager layoutSubviewsOfCell:] ()
#130545 0x00000001066ec1d0 in -[UITableViewCell layoutSubviews] ()
#130546 0x00000001064d5973 in -[UIView(CALayerDelegate) layoutSublayersOfLayer:] ()
#130547 0x000000010a3d3de8 in -[CALayer layoutSublayers] ()
#130548 0x000000010a3c8a0e in CA::Layer::layout_if_needed(CA::Transaction*) ()
#130549 0x00000001064c9847 in -[UIView(Hierarchy) layoutBelowIfNeeded] ()
#130550 0x00000001064cd5ce in +[UIView(Animation) performWithoutAnimation:] ()
#130551 0x00000001065378de in __46-[UITableView _updateWithItems:updateSupport:]_block_invoke919 ()
#130552 0x00000001064ce362 in +[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] ()
#130553 0x00000001064ce5b7 in +[UIView(UIViewAnimationWithBlocks) animateWithDuration:delay:options:animations:completion:] ()
#130554 0x0000000106536c71 in -[UITableView _updateWithItems:updateSupport:] ()
#130555 0x0000000106530ce7 in -[UITableView _endCellAnimationsWithContext:] ()
#130556 0x0000000105621c3b in myExpenseBook.MasterViewController.controllerDidChangeContent (myExpenseBook.MasterViewController)(ObjectiveC.NSFetchedResultsController) -> () at /Users/Ailete619/Desktop/myExpenseBook/myExpenseBook/MasterViewController.swift:241
#130557 0x0000000105621e2a in @objc myExpenseBook.MasterViewController.controllerDidChangeContent (myExpenseBook.MasterViewController)(ObjectiveC.NSFetchedResultsController) -> () ()
#130558 0x0000000105816241 in __77-[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:]_block_invoke ()
#130559 0x00000001058150b2 in -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:] ()
#130560 0x0000000105ba0cec in __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ ()
#130561 0x0000000105aa08a4 in _CFXNotificationPost ()
#130562 0x0000000105fa96b8 in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
#130563 0x000000010572cc96 in -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] ()
#130564 0x00000001057b5d1e in -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:] ()
#130565 0x00000001057283d1 in -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] ()
#130566 0x000000010572b8f3 in -[NSManagedObjectContext save:] ()
#130567 0x000000010561709d in myExpenseBook.MasterViewController.insertExpenseItem (myExpenseBook.MasterViewController)(Swift.String, somePrice : Swift.String, somewhere : Swift.String, sometime : ObjectiveC.NSDate) -> () at /Users/Ailete619/Desktop/myExpenseBook/myExpenseBook/MasterViewController.swift:48
#130568 0x00000001056193af in myExpenseBook.MasterViewController.unwindToSegue (myExpenseBook.MasterViewController)(ObjectiveC.UIStoryboardSegue) -> () at /Users/Ailete619/Desktop/myExpenseBook/myExpenseBook/MasterViewController.swift:95
#130569 0x000000010561948a in @objc myExpenseBook.MasterViewController.unwindToSegue (myExpenseBook.MasterViewController)(ObjectiveC.UIStoryboardSegue) -> () ()
#130570 0x0000000106b28c2f in -[UIStoryboardUnwindSegueTemplate _perform:] ()
#130571 0x000000010645d8be in -[UIApplication sendAction:to:from:forEvent:] ()
#130572 0x000000010645d8be in -[UIApplication sendAction:to:from:forEvent:] ()
#130573 0x0000000106564410 in -[UIControl _sendActionsForEvents:withEvent:] ()
#130574 0x00000001065637df in -[UIControl touchesEnded:withEvent:] ()
#130575 0x00000001064a3308 in -[UIWindow _sendTouchesForEvent:] ()
#130576 0x00000001064a3c33 in -[UIWindow sendEvent:] ()
#130577 0x00000001064709b1 in -[UIApplication sendEvent:] ()
#130578 0x000000010647da7d in _UIApplicationHandleEventFromQueueEvent ()
#130579 0x0000000106459103 in _UIApplicationHandleEventQueue ()
#130580 0x0000000105b06551 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ ()
#130581 0x0000000105afc41d in __CFRunLoopDoSources0 ()
#130582 0x0000000105afba54 in __CFRunLoopRun ()
#130583 0x0000000105afb486 in CFRunLoopRunSpecific ()
#130584 0x0000000109cc79f0 in GSEventRunModal ()
#130585 0x000000010645c420 in UIApplicationMain ()
#130586 0x000000010561280e in top_level_code at /Users/Ailete619/Desktop/myExpenseBook/myExpenseBook/AppDelegate.swift:13
#130587 0x000000010561284a in main ()
#130588 0x0000000107eee145 in start ()
#130589 0x0000000107eee145 in start ()
我检查了我的托管对象是通过修改controllerDidChangeContent创建的:

func controllerDidChangeContent(controller: NSFetchedResultsController) {
    self.tableView.endUpdates()
    // * or *
    //self.tableView.reloadData()
}
func controllerDidChangeContent(controller: NSFetchedResultsController) {
    let context = self.fetchedResultsController.managedObjectContext
    let objects = context.registeredObjects
    println("l=\(objects.count)")
    for o in objects {
        let e = o as ExpenseItem
        println("o when=\(e.when) what=\(e.what) location=\(e.location) price=\(e.howMuch)")
    }
    self.tableView.endUpdates()
}
得到了这个输出:

l=1
o when=2014-12-08 13:20:49 +0000 what=big mac location=macdo price=500

我的测试项目可在以下位置下载:ailete619com.appspot.com/stackoverflow/myExpenseBook.zip

通过在Xcode中设置异常断点开始调试。然后你就会知道什么是崩溃。很可能不是表视图本身,而是涉及核心数据堆栈或其他数据源的内容。

只需在prepareForSegue消息中从DestinationViewController调用insertExpenseItem即可。您可以将其更改为ExpenseItem,而不是所有参数。

我设置了一个异常断点,但除了我的所有println消息外,我没有收到任何消息。。。我没有收到异常消息您的意思是在DetailViewController中创建ExpenseItem可以解决崩溃问题?因为我尝试在prepareForSegue中从DestinationViewController调用insertExpenseItem,正如您在上面添加的代码中所看到的。仍在寻找我做错了什么以及如何找到崩溃原因的想法。。。