tableView.reloadData()导致应用程序崩溃

时间:2015-06-22 19:58:25

标签: swift uitableview core-data ios8

在Swift应用程序中,我提供了一个附加视图,用于向CoreData数据库添加元素。如果我调用tableview.reloadData(),应用程序会在主屏幕上的+按钮上崩溃。如果省略重新加载数据,则会显示添加视图,并将数据添加到CoreData文件中。

主视图,来自configureCell down:

func configureCell(cell: TransectTableViewCell, indexPath:NSIndexPath) {

    let transectEntry = fetchedResultController.objectAtIndexPath(indexPath) as! Transects

    cell.transectNameLabel.text = transectEntry.transectName
    cell.transectNameLabel.textColor = UIColor.blackColor()
    cell.transectNameLabel.shadowColor = UIColor.whiteColor()
    cell.transectNameLabel.shadowOffset = CGSizeMake(1, 1)
}

func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    if editingStyle == .Delete {
        let countEntry = fetchedResultController.objectAtIndexPath(indexPath) as! Transects
        coreDataStack.context.deleteObject(countEntry)
        coreDataStack.saveContext()
    }
}

func tableView(tableView: UITableView,
    heightForRowAtIndexPath indexPath: NSIndexPath)
    -> CGFloat {
        return 50;
}

func didFinishViewController(viewController: AddTransectViewController, didSave: Bool) {

    if didSave {
        var error: NSError? = nil
        let context = viewController.context
        self.coreDataStack.saveContext()
    }

    dismissViewControllerAnimated(true, completion: {})
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    if segue.identifier == "addTransectSegue" {

        let newTransectViewController = segue.destinationViewController as! AddTransectViewController
        let transectEntryEntity = NSEntityDescription.entityForName("Transects", inManagedObjectContext: coreDataStack.context)
        let newTransectEntry = Transects(entity: transectEntryEntity!, insertIntoManagedObjectContext: coreDataStack.context)

        newTransectViewController.transectNewEntry = newTransectEntry
        newTransectViewController.context = newTransectEntry.managedObjectContext
        newTransectViewController.delegate = self
    }

    if segue.identifier == "transectTasksSegue" {

        let indexPath = tableView.indexPathForSelectedRow()!
        let transectSelected = fetchedResultController.objectAtIndexPath(indexPath) as! Transects

        let tasksViewController = segue.destinationViewController as! TransectTasksViewController
        tasksViewController.coreDataStack = coreDataStack

        tasksViewController.selectedTransect = transectSelected

    }
}


func controllerDidChangeContent(controller:
    NSFetchedResultsController) {
        tableView.reloadData()
}

添加视图是:

import UIKit
import CoreData
import Foundation

protocol TransectDelegate {

    func didFinishViewController(ViewController:AddTransectViewController, didSave:Bool)
}

class AddTransectViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var transectNameTextField: UITextField!
    @IBOutlet weak var latitudeTextField: UITextField!
    @IBOutlet weak var longitudeTextField: UITextField!
    @IBOutlet weak var altitudeTextField: UITextField!

    var transectNewEntry: Transects!

    var context: NSManagedObjectContext!
    var delegate:TransectDelegate?

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func prefersStatusBarHidden() -> Bool {
        return true
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func updateTransectEntry() {

        if let entry = transectNewEntry {

            entry.transectName = transectNameTextField.text
            entry.latitude = latitudeTextField.text
            entry.longitude = longitudeTextField.text
            entry.altitude = altitudeTextField.text
        }
    }

    @IBAction func cancelButtonWasTapped(sender: AnyObject) {
        delegate?.didFinishViewController(self, didSave: false)
    }

    @IBAction func saveButtonWasTapped(sender: AnyObject) {
        updateTransectEntry()
        delegate?.didFinishViewController(self, didSave: true)
    }

}

我遗失了什么,却看不出来。我们欢迎您的想法。

应用程序挂起在cell.transectNameLabel.text = transectEntry.transectName

with:Thread 1:EXC_BAD_ACCESS(code = 1,address = 0x0)

我真正的困惑是这完美无缺:

 import UIKit

导入CoreData

类PlantSpeciesViewController:UIViewController,NSFetchedResultsControllerDelegate,PlantSpeciesDelegate,UITableViewDataSource,UITableViewDelegate {

@IBOutlet var tableView:UITableView!

var coreDataStack: CoreDataStack!
lazy var fetchedResultController:
NSFetchedResultsController = self.plantSpeciesFetchedResultsController()

var plantSpecies: PlantSpecies!

var selectedFamily: PlantFamily!

var context: NSManagedObjectContext!

var plantFamilyName: String!

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.backgroundColor = UIColor.clearColor()
    view.backgroundColor = UIColor(patternImage: UIImage (named: "Monitor backdrop.png")!)

    self.title = plantFamilyName
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

func plantSpeciesFetchedResultsController()
    ->NSFetchedResultsController {

        fetchedResultController =
            NSFetchedResultsController(
                fetchRequest: plantSpeciesFetchRequest(),
                managedObjectContext: coreDataStack.context,
                sectionNameKeyPath: nil,
                cacheName: nil)

        fetchedResultController.delegate = self

        var error: NSError? = nil
        if (!fetchedResultController.performFetch(&error)){
            println("Error: \(error?.localizedDescription)")
            abort()
        }

        return fetchedResultController
}

func plantSpeciesFetchRequest() -> NSFetchRequest {

    let fetchRequest = NSFetchRequest(entityName: "PlantSpecies")
    fetchRequest.fetchBatchSize = 20

    let predicate = NSPredicate(format: "familyName == %@", selectedFamily)

    fetchRequest.predicate = predicate

    let sortDescriptor = NSSortDescriptor(key: "plantSpecies", ascending: true)

    fetchRequest.sortDescriptors = [sortDescriptor]

    //var error: NSError?

    return fetchRequest
}

func numberOfSectionsInTableView(tableView: UITableView) -> Int {

    return fetchedResultController.sections!.count
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    return fetchedResultController.sections![section].numberOfObjects
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("plantSpeciesCell", forIndexPath: indexPath) as! PlantSpeciesTableViewCell

    cell.backgroundColor = UIColor.clearColor()

    configureCell(cell, indexPath: indexPath)

    return cell
}

func configureCell(cell: PlantSpeciesTableViewCell, indexPath:NSIndexPath) {

    let plantEntry = fetchedResultController.objectAtIndexPath(indexPath) as! PlantSpecies

    cell.speciesNameLabel.text = plantEntry.plantSpecies
    cell.speciesNameLabel.textColor = UIColor.blackColor()
    cell.speciesNameLabel.shadowColor = UIColor.whiteColor()
    cell.speciesNameLabel.shadowOffset = CGSizeMake(1, 1)

    cell.speciesImageView.image = UIImage (data: plantEntry.plantImage)
}


func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    if editingStyle == .Delete {
        let countEntry = fetchedResultController.objectAtIndexPath(indexPath) as! PlantFamily
        coreDataStack.context.deleteObject(countEntry)
        coreDataStack.saveContext()
    }
}

func tableView(tableView: UITableView,
    heightForRowAtIndexPath indexPath: NSIndexPath)
    -> CGFloat {
        return 90;
}

func didFinishViewController(viewController: AddPlantSpeciesViewController, didSave: Bool) {

    if didSave {
        var error: NSError? = nil
        let context = viewController.context
        self.coreDataStack.saveContext()
    }

    dismissViewControllerAnimated(true, completion: {})
}

// MARK: - Navigation

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    if segue.identifier == "addSpeciesSegue" {

        let newPlantViewController = segue.destinationViewController as! AddPlantSpeciesViewController
        let plantEntryEntity = NSEntityDescription.entityForName("PlantSpecies", inManagedObjectContext: coreDataStack.context)
        let newSpeciesEntry = PlantSpecies(entity: plantEntryEntity!, insertIntoManagedObjectContext: coreDataStack.context)

        newPlantViewController.selectedFamily = selectedFamily

        newPlantViewController.plantNameEntry = newSpeciesEntry
        newPlantViewController.context = newSpeciesEntry.managedObjectContext
        newPlantViewController.delegate = self
    }
}

func controllerDidChangeContent(controller:
    NSFetchedResultsController) {

        tableView.reloadData()
}

}

加上:

导入UIKit 导入CoreData 进口基金会

协议PlantSpeciesDelegate {

func didFinishViewController(ViewController:AddPlantSpeciesViewController, didSave:Bool)

}

类AddPlantSpeciesViewController:UIViewController,UITextFieldDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate {

@IBOutlet weak var plantNameTextField: UITextField!
@IBOutlet weak var plantImageView: UIImageView!

@IBOutlet weak var imageSwitch: UISwitch!

@IBOutlet weak var imageFromFileButton: UIButton!
@IBOutlet weak var imageFromCameraButton: UIButton!

let imagePicker = UIImagePickerController()

var plantNameEntry: PlantSpecies!
var selectedFamily: PlantFamily!

var passedPlantFamily: String!

var newPlantName: String!
var newImageData: NSData!

var context: NSManagedObjectContext!
var delegate:PlantSpeciesDelegate?

override func viewDidLoad() {
    super.viewDidLoad()

    plantImageView.image = UIImage(named: "placeholder image.jpg")

    imagePicker.delegate = self

}

override func prefersStatusBarHidden() -> Bool {
    return true
}

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

@IBAction func imageSourceSwitch(sender: AnyObject) {

    if imageSwitch.on == true
    {
        self.imageFromFileButton.enabled = true
        self.imageFromCameraButton.enabled = false
    }

    else
    {
        self.imageFromCameraButton.enabled = true
        self.imageFromFileButton.enabled = false
    }
}


@IBAction func imageFromFile(sender: AnyObject) {
    imagePicker.sourceType = .PhotoLibrary
    presentViewController(imagePicker, animated: true, completion: nil)
}


@IBAction func imageFromCamera(sender: AnyObject) {
    imagePicker.sourceType = .Camera
    presentViewController(imagePicker, animated: true, completion: nil)
}

func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
    self.plantImageView.image = image
    dismissViewControllerAnimated(true, completion: nil)
}

@IBAction func getPlantName() {

    newPlantName = plantNameTextField.text
    plantNameTextField.resignFirstResponder()
}

func updateSpeciesEntry() {

    if let entry = plantNameEntry {

        entry.plantSpecies = newPlantName
        entry.plantImage = UIImageJPEGRepresentation(plantImageView.image, 1.0)
        entry.familyName = selectedFamily
    }
}

@IBAction func cancelButtonWasTapped(sender: AnyObject) {
    delegate?.didFinishViewController(self, didSave: false)
}


@IBAction func saveButtonWasTapped(sender: AnyObject) {
    updateSpeciesEntry()
    delegate?.didFinishViewController(self, didSave: true)
}

}   那么,有什么区别?

3 个答案:

答案 0 :(得分:2)

这也发生在我身上,修复它:

dispatch_async(dispatch_get_main_queue(), ^{
    [self.tableView reloadData];
});

而不仅仅是tableView.reloadData() ,因为它似乎是从错误的线程调用。

答案 1 :(得分:1)

崩溃的原因很可能是表格无法加载数据,例如某个值不存在且正在强制解包。因此,当您尝试收集数据时,只会发生崩溃。检查所有值以确定。

答案 2 :(得分:0)

我想扩展一下GJZ答案以及什么使我来到这里。我有具有文本字段的UITableViewCells。我试图获取用户从字段中输入的值。

let companyNameCell:  TextEntryCell = self.tableView.cellForRow(at: IndexPath(row: 0, section: 0)) as! TextEntryCell   

我意识到的是,当我使用tableview.reloadrows方法通过更改单元格高度来动态隐藏和显示行时,如果该应用程序尝试读取用户在屏幕上看不到的单元格,则该应用程序将崩溃。那是因为我认为细胞已被释放。