Uitableview IOS Swift Master Detail应用程序,托管对象,tableView:endUpdates()调用configureCell(),但崩溃,reloadData()不调用它
我是Swift的新手,我试着制作我的第一个测试应用程序,但我遇到了一个托管对象问题,我想。。。你知道我做错了什么吗 我开始使用Master Detail应用程序模板制作一个应用程序,并尽可能多地使用XCode的故事板来修改基本模板 我修改了TableView以使用自定义TableViewCells: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:
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,正如您在上面添加的代码中所看到的。仍在寻找我做错了什么以及如何找到崩溃原因的想法。。。