【问题标题】:Should I have used a CoreData predicate to populate my UITableview?我应该使用 CoreData 谓词来填充我的 UITableview 吗?
【发布时间】:2016-05-15 21:22:48
【问题描述】:

我有一个使用 CoreData 和 Swift 2 重建的旧应用程序。这是我第一次使用 Coredata,所以我确信我没有以最有效的方式做所有事情。例如,我在 Coredata 中有 2 个实体,一个 Person 实体和一个 Statement 实体。 person 实体与 Statement 实体具有“对多”关系,Statement 实体与 Person 实体具有“对一”关系。所以基本上我的 Person 对象能够有多个 Statement 对象。这一切正常,我能够成功地将它们添加到 CoreData 中。

接下来我有一个 UIViewController,里面有一个 UITableView。我将表格视图的选择下拉菜单设置为多个部分。我为表格视图分配了 2 个部分。

当我抓取 CoreData 实体时,我将它们放入一个数组中,以便我能够使用该数组并填充 tableview。

 var persons: [Person]!
 persons = try coreDataStack.context.executeFetchRequest(fetchRequest) as! [Person]

在那之后(我认为这可能是更简单的地方)我将该数组分解为 2 个不同的数组,以便表格视图中的每个部分都有自己的数据源。我认为这是我可以使用 CoreData NSPredicate 的地方,但是在查看了一些教程并阅读了我关于 Coredata 的书的几章之后,我仍然不太了解如何使用它们。所以相反,我正在做的是从我从 Coredata 创建的数组中创建 2 个不同的数组。

for(var i = 0; persons?.count > i; i++){
        newNumber = 0.00
        print("\(persons?[i].statements?.count) this is the statements count")

        if(persons?[i].statements?.count > 0){

            print("YES statements")
            //persons[i].statements
            for(var x = 0; persons[i].statements?.count > x; x++){

                //print( "\(persons[i].statements?[x].name) this is the name " )
                let statementNumber = persons[i].statements?[x] as? Statement
                //print(statementNumber?.amount)

                newNumber = newNumber + Double((statementNumber?.amount)!)
                //print(newNumber)
            }
            // check the new number and see if it's positive or negative
            if(newNumber >= 0){
                positiveeArray.append(persons[i])
                //print("\(positiveArray.count) This is the count of the posve array")
            }
            else{
                negativeArray.append(persons[i])
                //print("\(negativeArray.count) This is the count of the negative array")
            }

        }else{

            print("there are no statements add this person to the positive array")
            positiveArray.append(persons[i])
        }
    }

基本上每个 Statement 实体都有一个 amount 属性。我想检查该属性是正数还是负数。这个系统再次工作,但似乎要跳过很多圈才能访问该数据。

在此之后,我采用这 2 个数组(正数和负数)并使用它们来填充我的 UITableView 的不同部分。

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

    let cell = tableView.dequeueReusableCellWithIdentifier("personCell", forIndexPath: indexPath) as! PersonTableViewCell

    //print("\(persons?[indexPath.row].statements?.count) this is the count to use")
    //print("\(indexPath.row) this is the index row")

    var numberForDispay = 0.00

    switch(indexPath.section) {
    case 0:
        if(positiveArray[indexPath.row].statements?.count != 0){

            for(var i = 0; positiveArray[indexPath.row].statements?.count > i; i++){

                let statementNumber = positiveArray[indexPath.row].statements?[i] as? Statement
                //print(statementNumber?.amount)
                numberForDispay = numberForDispay + Double((statementNumber?.amount)!)

                // this will make negative numbers positive
                numberForDispay = fabs(numberForDispay)

                let formatter = NSNumberFormatter()
                formatter.numberStyle = .CurrencyStyle

                cell.statementAmount.text = formatter.stringFromNumber(numberForDispay)
                //print("\(formatter) this is the number to use")
            }
        }else{
            cell.statementAmount.text = "$0.00"
        }
    case 1:
        if(negativeArray[indexPath.row].statements?.count != 0){

            for(var i = 0; negativeArray[indexPath.row].statements?.count > i; i++){

                let statementNumber = negativeArray[indexPath.row].statements?[i] as? Statement
                //print(statementNumber?.amount)
                numberForDispay = numberForDispay + Double((statementNumber?.amount)!)

                // this will make negative numbers positive
                numberForDispay = fabs(numberForDispay)

                let formatter = NSNumberFormatter()
                formatter.numberStyle = .CurrencyStyle

                cell.statementAmount.text = formatter.stringFromNumber(numberForDispay)
                //print("\(formatter) this is the number to use")
            }
        }else{
            cell.statementAmount.text = "$0.00"
        }
    default: ""
    }

    switch(indexPath.section) {
        case 0:
            cell.personName.text = postitiveArray[indexPath.row].name
            cell.backgroundColor = Styles.blueColor();
        case 1:
            cell.personName.text = negativeArray[indexPath.row].name
            cell.backgroundColor = Styles.redColor();

        default: cell.personName.text = "hello"
    }

    cell.personName.textColor = Styles.whiteColor()
    cell.statementAmount.textColor = Styles.whiteColor()

    // will make the divide line full width
    cell.separatorInset = UIEdgeInsetsMake(0, 0, cell.frame.size.width, 0)
    if (cell.respondsToSelector("preservesSuperviewLayoutMargins")){
        cell.layoutMargins = UIEdgeInsetsZero
        cell.preservesSuperviewLayoutMargins = false
    }

    // set the accessory icon color
    cell.tintColor = UIColor.whiteColor()

    return cell
}

这再次有效,但我希望我能够清理我拥有的大量代码并简化此过程。我来自 Flash / AS3 背景。我知道这是一个很长的帖子,所以如果你到了这一步,谢谢!我只是想确保我在开发这些应用程序时不会为自己创造更多的工作。

【问题讨论】:

    标签: xcode swift uitableview core-data nspredicate


    【解决方案1】:

    我建议使用NSFetchedResultsController。你甚至可以使用两个,每个部分一个。您在内存、数据库访问和性能方面得到了很多优化。

    这里有 2 个谓词,您将它们添加到 fetched results 控制器的 fetch 请求中(获取 Statement 对象):

    NSPredicate(format: "amount < 0")
    NSPredicate(format: "amount >= 0")
    

    返回 2 作为部分的数量,并将相应的获取结果控制器的 fetchedObjects.count 作为 numberOfRowsInSection

    您也可以使用单个获取的结果控制器来执行此操作。但是您必须将一个标志硬编码到数据库中,该标志指示每个金额属于哪个部分。因此,无论何时设置金额,您都会自动让实体对象设置其加/减标志。

    顺便说一句,您可以在 Swift 中更简洁(不仅是托管对象,还包括任何类型的对象),而不是遍历项目。例如

    let negative = allStatements.filter { $0.amount < 0 }
    let positive = allStatements.filter { $0.amount >= 0 }
    

    请注意,Core Data 也可以使用聚合函数。一个人的所有声明金额的总和将是

    let sum = person.valueForKeyPath("@sum.amount") as! NSNumber
    

    使用此技术,您可以拥有Personsum 属性,只要您设置Statement 的数量,该属性就会更新。

    所以你的 Person 谓词将是

    NSPredicate(format: "sum < 0")
    NSPredicate(format: "sum >= 0")
    

    【讨论】:

    • NSFetchedResultsController 的另一个优点是它可以更轻松地对更改做出反应。如问题所示,每当Statement 更改时,您都必须重复构建这些集合的过程。
    • @Mundi 难道那些谓词和键路径不需要statements.@sum.amount,因为表格视图显示Persons
    • 正确的谓词基于Statement fetch。我纠正了这一点。不幸的是,您不能在获取结果控制器或获取请求中使用集合运算符。
    猜你喜欢
    • 2020-09-26
    • 2011-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多