IOS Swift Master Detail Application, managed object, tableView: endUpdates() 调用configureCell() 但崩溃,r
Posted
技术标签:
【中文标题】IOS Swift Master Detail Application, managed object, tableView: endUpdates() 调用configureCell() 但崩溃,reloadData() 不调用【英文标题】:IOS Swift Master Detail Application, managed object, tableView: endUpdates() calls configureCell() but crash, reloadData() does not call it 【发布时间】:2014-12-04 15:59:59 【问题描述】:我是 Swift 的新手,我尝试制作我的第一个测试应用程序,但我陷入了一个托管对象问题,我认为......知道我做错了什么吗?
我开始使用Master Detail Application模板制作应用程序,并尽可能使用XCode的storyboard修改基本模板。
我修改了 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
我使用托管对象:
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 either 时,我调用了一个函数来创建一个 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)
或来自 MasterViewController 的 unwindToSegue():
@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()
如果我调用 self.tableView.reloadData(),configureCell() 不会被调用,并且表格视图会在单元格应位于的位置显示一个完全空白的空间,但应用程序不会崩溃
如果我调用 self.tableView.endUpdates(),configureCell() 会被调用,但我会收到 EXC_BAD_ACCESS(code=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)
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/***/myExpenseBook.zip
【问题讨论】:
仍在寻找有关我做错了什么以及如何找到崩溃原因的想法... 【参考方案1】:通过在 Xcode 中设置异常断点来开始调试。然后你会确切地知道什么是崩溃。很可能不是表格视图本身,而是涉及您的核心数据堆栈或其他数据源的东西。
【讨论】:
我设置了一个异常断点,但是除了我所有的 println 消息之外我没有收到任何消息...我没有收到异常消息【参考方案2】:只需在 prepareForSegue
消息中从 DestinationViewController 调用 insertExpenseItem
。您可以将其更改为期望 ExpenseItem 而不是所有参数。
【讨论】:
你的意思是在 DetailViewController 中创建 ExpenseItem 可以解决崩溃问题?因为我尝试在 prepareForSegue() 中从 DestinationViewController 调用 insertExpenseItem(),正如您在上面添加的代码中看到的那样。以上是关于IOS Swift Master Detail Application, managed object, tableView: endUpdates() 调用configureCell() 但崩溃,r的主要内容,如果未能解决你的问题,请参考以下文章
Swift 中的 Master Detail 应用程序 - 如何将字符串转换为 URL
UITableView 在使用 Swift 中的 Master Detail App 滚动之前不会重新加载
iOS 上的 Xamarin.Forms Master/Detail 边缘滑动