插入行

时间:2016-04-18 22:42:11

标签: ios swift uitableview uiimageview

当我将新项目加载到Core data / UITableView时,我发生了一件非常有趣的事件。

有一点需要注意的是,在我没有实施章节之前,我从来没有遇到过这样的事情。但是在我添加了部分之后,它随机开始了。

只有当我在Core data / UITableView中添加(插入)新条目时才会发生这种情况。如果我回到上一个View Controller然后返回到表格,它将自动修复它的自我。

这是我添加新行时目前正在做的图片。 App Image

正如您在左侧看到的那样,一些标签,图像和按钮是分散的,而在右侧则是它们所属的所有标签。

所有内容都受到完全限制,适用于各种手机尺寸。但就像我说的那样,在我添加了部分功能后,这一切都开始发生了。

我假设只需要TableViewController的代码,所以请看下面的内容。

import UIKit
import CoreData

class ListItemsTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {

let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var frc: NSFetchedResultsController = NSFetchedResultsController()
var list: Lists?
var catalog: Catalog?

override func viewDidLoad() {
    super.viewDidLoad()

    self.tableView.reloadData()
    self.title = list?.name

    frc = getFCR()
    frc.delegate = self

    do {
        try frc.performFetch()
    } catch {
        print("Failed to perform inital fetch")
    }

    // Uncomment the following line to preserve selection between presentations
    //self.clearsSelectionOnViewWillAppear = true

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem()
}

override func viewWillAppear(animated: Bool) {

    let imageView = UIImageView(image: UIImage(named: "TableBackground"))
    imageView.contentMode = .ScaleAspectFill
    self.tableView.backgroundView = imageView
    self.tableView.tableFooterView = UIView(frame: CGRectZero)
    self.tableView.reloadData()

}

override func viewDidAppear(animated: Bool) {

    frc = getFCR()
    frc.delegate = self

    do {
        try frc.performFetch()
    } catch {
        fatalError("Failed to perform inital fetch")
    }

    self.tableView.reloadData()

}

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

// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {

    if let sections = frc.sections {
        return sections.count
    }

    return 0

}

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

    if let sections = frc.sections {
        let currentSection = sections[section]
        return currentSection.numberOfObjects
    }

    return 0

}

override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {

    if let sections = frc.sections {
        let currentSection = sections[section]
        return currentSection.name
    }

    return nil

}

override func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {

    let header: UITableViewHeaderFooterView = view as! UITableViewHeaderFooterView
    header.contentView.backgroundColor = UIColor(red: 84/255, green: 200/255, blue: 214/255, alpha: 0.5)
    header.textLabel!.textColor = UIColor.whiteColor()
    //header.alpha = 0.5 //make the header transparent

}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCellWithIdentifier("listContentCell", forIndexPath: indexPath) as! ListItemsTableViewCell
    let item = frc.objectAtIndexPath(indexPath) as! Items

    cell.separatorInset = UIEdgeInsets(top: 0, left: 78, bottom: 0, right: 0)
    cell.itemName.text = item.name
    cell.itemSection.text = item.section
    cell.itemQty.text = "Qty: \(item.qty!)"
    cell.itemSize.text = item.size
    cell.itemPrice.text = floatToCurrency(Float(item.cost!))
    cell.itemImage.image = UIImage(data: item.image!)
    cell.itemID.text = String(item.id!)

    return cell

}

override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {

    cell.backgroundColor = UIColor.clearColor()

}

override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {

    let delete = UITableViewRowAction(style: .Destructive, title: "Delete") { (action, indexPath) in

        let request = self.fetchRequest()
        var fetchResults = [AnyObject]()

        do {
            fetchResults = try self.moc.executeFetchRequest(request)
        } catch {
            fatalError("Fetching Data to Delete Failed")
        }

        self.moc.deleteObject(fetchResults[indexPath.row] as! NSManagedObject)
        fetchResults.removeAtIndex(indexPath.row)

        do {
            try self.moc.save()
        } catch {
            fatalError("Failed to Save after Delete")
        }

    }

    let edit = UITableViewRowAction(style: .Normal, title: "Edit") { (action, indexPath) in

        // Code to come

    }

    let qty = UITableViewRowAction(style: .Normal, title: "Qty") { (action, indexPath) in

        // Code to come

    }

    edit.backgroundColor = UIColor.init(red: 84/255, green: 200/255, blue: 214/255, alpha: 1)

    return [delete, edit, qty]

}

func controllerWillChangeContent(controller: NSFetchedResultsController) {

    tableView.beginUpdates()

}

func controllerDidChangeContent(controller: NSFetchedResultsController) {

    tableView.endUpdates()

}

func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {

    switch type {
    case NSFetchedResultsChangeType.Delete:
        self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic)
    case NSFetchedResultsChangeType.Insert:
        self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic)
    /*case NSFetchedResultsChangeType.Update:
        tableView.reloadSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic)*/
    default:
        print("didChangeSection Default was accessed")
        break
    }

}

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {

    switch type {
    case NSFetchedResultsChangeType.Delete:
        self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
    case NSFetchedResultsChangeType.Insert:
        self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
        self.tableView.reloadData()
    case NSFetchedResultsChangeType.Update:
        let cell = self.tableView.cellForRowAtIndexPath(indexPath!) as! ListItemsTableViewCell
        let item = self.frc.objectAtIndexPath(indexPath!) as! Items

        cell.itemName.text = item.name
        cell.itemSection.text = item.section
        cell.itemQty.text = "Qty: \(item.qty!)"
        cell.itemSize.text = item.size
        cell.itemPrice.text = floatToCurrency(Float(item.cost!))
        cell.itemImage.image = UIImage(data: item.image!)
        cell.itemID.text = String(item.id!)
    case NSFetchedResultsChangeType.Move:
        self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
        self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
    }

}

func fetchRequest() -> NSFetchRequest {

    let fetchRequest = NSFetchRequest(entityName: "Items")
    let sortDesc1 = NSSortDescriptor(key: "section", ascending: true)
    let sortDesc2 = NSSortDescriptor(key: "isChecked", ascending: true)
    let sortDesc3 = NSSortDescriptor(key: "name", ascending: true)
    fetchRequest.sortDescriptors = [sortDesc1, sortDesc2, sortDesc3]

    return fetchRequest

}

func getFCR() -> NSFetchedResultsController {

    frc = NSFetchedResultsController(fetchRequest: fetchRequest(), managedObjectContext: moc, sectionNameKeyPath: "section" , cacheName: nil)

    return frc

}

func getCatalog(id: NSNumber) -> Catalog {

    var cat: Catalog?

    let fetchReq = NSFetchRequest(entityName: "Catalog")
    let pred = NSPredicate(format: "%K == %@", "id", id)
    fetchReq.predicate = pred

    do {
        let check = try moc.executeFetchRequest(fetchReq)
        cat = (check.first as! Catalog)
    } catch {
        fatalError("Failed fetching Catalog Entry matching Item")
    }

    return cat!
}

func floatToCurrency(flt: Float) -> String {

    let formatter = NSNumberFormatter()
    formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
    return String(formatter.stringFromNumber(flt)!)

}

// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    var id: NSNumber

    if (segue.identifier == "listItemView") {
        let cell = sender as! UITableViewCell
        let indexPath = self.tableView.indexPathForCell(cell)

        let itemCont: ViewItemViewController = segue.destinationViewController as! ViewItemViewController
        let item: Items = self.frc.objectAtIndexPath(indexPath!) as! Items
        itemCont.item = item
        id = item.id!
        itemCont.catalog = getCatalog(id)
    } else if (segue.identifier == "listItemViewEdit") {
        let cell = sender as! UITableViewCell
        let indexPath = self.tableView.indexPathForCell(cell)

        let itemCont: AddItemListViewController = segue.destinationViewController as! AddItemListViewController
        let item: Items = self.frc.objectAtIndexPath(indexPath!) as! Items
        itemCont.item = item
        id = item.id!
        itemCont.catalog = getCatalog(id)
        itemCont.list = list
    }

}

}

就像我之前说过的那样,直到我在章节中添加这个问题才出现问题。但是,当我单击后退按钮(< Lists)然后返回到此视图时,它将自动更正为右侧显示的内容。

此外,它并不是每次都这样做。有时它会在我第一次在输入TableView时添加项目时执行此操作。对于在视图外添加的项目,它似乎也不会这样做。即存在于屏幕可视区域下方的行。

编辑和删除似乎也不会导致此问题,只需添加新项目。

如果我猜测的话,不知何故,UIImage的尺寸变小或零,并且它会破坏其他所有东西。但尺寸标签和价格标签(0.00美元)直接链接了数量标签,这似乎永远不会移动。

所以看起来如果UIImage搞砸了,它也会弄乱数量标签。

它不是一个应用程序破坏者,但它看起来真的很麻烦,它必须通过退出ViewController然后重新加载来重新加载。(另外,我已经尝试过放置self.tableView.reloaddata ()在多个不同的地方但似乎没有解决问题。)

编辑: 删除所有约束并再次重新制作它们。它只会让事情变得更糟,见下图。

Contraints Redone

编辑2: 添加了约束图像

enter image description here

编辑3:

我猜这一点,帖子已经死了,我不得不去其他地方找到正在发生的事情的答案,但我能够把它缩小到错误特定的时候到来发挥作用。当我查看我的应用程序的旧备份之一时,我没有遇到此问题,我慢慢编辑它直到我开始解决问题。我的错误来自didChangeObject函数。以前,我有这样的代码

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {

if (type == .delete) {
    self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
}

}

我的单元格格式正确,但只要我将其更新为

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {

switch type {
case NSFetchedResultsChangeType.Delete:
    self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
case NSFetchedResultsChangeType.Insert:
    self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
case NSFetchedResultsChangeType.Update:
    let cell = self.tableView.cellForRowAtIndexPath(indexPath!) as! ListItemsTableViewCell
    let item = self.frc.objectAtIndexPath(indexPath!) as! Items

    cell.itemName.text = item.name
    cell.itemSection.text = item.section
    cell.itemQty.text = "Qty: \(item.qty!)"
    cell.itemSize.text = item.size
    cell.itemPrice.text = floatToCurrency(Float(item.cost!))
    cell.itemImage.image = UIImage(data: item.image!)
    cell.itemID.text = String(item.id!)
case NSFetchedResultsChangeType.Move:
    self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
    self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
}

}

我的手机将无法正确格式化。经过进一步测试,我发现移动类型也创建了相同的格式错误,所以我的问题特别是由self.tableView.insertRowsAtIndexPaths([newIndexPath!],withRowAnimation:UITableViewRowAnimation.Automatic)引起的。我从我所拥有的转换到更长的陈述的主要原因是当我在章节中添加时,我会得到一个错误,说明之前和之后的部分都没有匹配(特别是当一个条目被修改为它所在的位置时)切换到新的部分),从我在网上找到的所有东西,更长的方法是正确的方式...但由于某种原因,它会导致我的应用程序格式化错误。可能是我的代码(很可能是因为我对这一切都很新)或者可能是Xcode的错误。 我不打算放弃这个,但是在我开始放松心情之前,我只能把头撞到墙上很长时间,所以我可能会暂时休息一下。 如果你有任何建议我肯定会感激。希望这篇文章能以某种方式希望别人。

2 个答案:

答案 0 :(得分:1)

我可以猜到你的viewDidLoad()和viewWillAppear()函数可能存在一些问题,你可以了解它们执行的顺序,就像viewDidLoad()只在第一次显示视图时被调用一次比起工作是upWillAppear(),我想你有图像代码的地方,一旦你第二次来到这个视图就会纠正这些事情。我有一些问题,比如你是否正在使用故事板来确定尺寸,价格和数量标签以及你的图像视图是否合适?

尝试使用一些断点来了解代码如何获得正确视图第二点的差异。就像你可以在像viewDidload(),viewDidAppear()和viewWillAppear这样的重要函数中放置断点。

此图片中的约束对我有用。 enter image description here

这是输出。 enter image description here

并在cellForRowAtIndexPath中使用print(cell.itemImage.frame.size.width)给了我宽度61,我也得到了相同的高度61。 您可以向我展示我所展示的约束快照,我可以告诉您错误的原因。

答案 1 :(得分:0)

最后,我最终需要关闭Size Classes。我不完全理解为什么这是一个问题,但它修复了一切。

enter image description here