【问题标题】:CoreData Swift and transient attribute gettersCoreData Swift 和瞬态属性获取器
【发布时间】:2014-11-15 14:53:58
【问题描述】:

关于在 Swift 中使用 Core Data 时实现计算属性有什么建议吗?

使用生成的 ManagedObject 类,我尝试覆盖 getter,但出现错误:

计算属性上不允许“NSManaged”

这意味着您不能覆盖临时(计算)属性的 getter。

在下面的代码示例中,dateDue 在我的模型中被定义为瞬态属性。

请注意,@NSManaged 行是由 Xcode 生成的 - 不是我添加的。

@NSManaged var timeStamp: NSDate
@NSManaged var dateDue: String { 
    get {

        self.willAccessValueForKey("dateDue")
        var ddtmp  = self.primitiveValueForKey("dateDue") as String?
        self.didAccessValueForKey("dateDue")

        if (ddtmp == nil)
        {

            let calendar = NSCalendar.currentCalendar()

            let components = calendar.components((NSCalendarUnit.YearCalendarUnit | NSCalendarUnit.MonthCalendarUnit ) , fromDate: self.timeStamp)
            ddtmp = "\(components.year * 1000 + components.month)"
            self.setPrimitiveValue(ddtmp, forKey: "dateDue")

        }



        return ddtmp!
    }

}

【问题讨论】:

    标签: core-data swift


    【解决方案1】:

    首先,在数据模型中创建一个瞬态属性(section)。因为它是瞬态的,所以它没有物理存储,因此也没有存储在托管对象上下文中。

    section 属性如下所示:

    实体显示在这里:

    类 NSManagedObject 子类应该具有计算的“节”属性。 NSManagedObject 子类演示了如何完成此操作,如下所示:

    class Number: NSManagedObject {
    
        @NSManaged var number: NSNumber
    
        var section: String? {
            return number.intValue >= 60 ? "Pass" : "Fail"
        }
    }
    

    然后您必须在 NSFetchedResultsController 初始化程序中将 sectionForKeyPath 设置为数据模型中的临时属性键和缓存名称(如果需要)。

    override func viewDidLoad() {
            super.viewDidLoad()
    
            fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest(), managedObjectContext: managedObjectContext!, sectionNameKeyPath: "section", cacheName: "Root")
            fetchedResultsController?.delegate = self
            fetchedResultsController?.performFetch(nil)
    
            tableView.reloadData()
    }
    
    func fetchRequest() -> NSFetchRequest {
    
        var fetchRequest = NSFetchRequest(entityName: "Number")
        let sortDescriptor = NSSortDescriptor(key: "number", ascending: false)
    
        fetchRequest.predicate = nil
        fetchRequest.sortDescriptors = [sortDescriptor]
        fetchRequest.fetchBatchSize = 20
    
        return fetchRequest
    }
    

    结果是UITableViewController,成绩按通过或失败动态排序:

    我制作了一个示例项目,可以在 GitHub 上找到。

    【讨论】:

    • 为我工作。 :) 这个解决方案的坏处是您必须编辑自动生成的 Core Data 类。每次重新生成时,都必须重做修改。我将该部分放在扩展类中,但在重新生成类后,我仍然需要从生成的类中删除部分。
    • 这个答案应该被接受!使用日期而不是数字对我来说非常适合。对尝试从“DateSectionTitles”Apple 示例项目开始按日期执行部分分隔的每个人的建议:请改为遵循此答案!非常感谢@Bluehound
    • 我无法让它与 swift 4/ iOS 11 一起使用。有没有人有类似的问题?
    • @webventil 找到了解决方案。需要在属性声明前加上@objc
    • 我认为这个答案没有抓住重点。关键是瞬态 Core Data 属性仍然为您生成了 getter 和 setter。您可以编辑机器生成的核心数据实体文件,使属性只读而不是复制(即读写),然后在用户可编辑的实体生成文件中编写自己的 getter,但任何涉及编辑的内容机器生成的文件不是一个好的解决方案。一个更好的答案可能是:忘记有一个瞬态属性。只需在人工可编辑的 CD 生成文件中创建一个 getter 即可计算值。
    【解决方案2】:

    您所说的“瞬态”和“计算”是不同的东西,并且是相互排斥的。

    瞬态意味着值存储在对象图的内存中。 Computed 表示该值不存储在任何地方,而是在 getter 中计算。两者都不同于存储在对象图上并保存到磁盘的经典非瞬态 属性。

    @NSManaged 只能应用于托管对象模型中具有插槽的属性。

    【讨论】:

    • 托管对象模型中的一个属性。为了扩展,我试图复制其中一个苹果示例程序使用的技术 - 但是苹果示例是用 Objective C 编写的 - 实际上它是在 Xcode 中提供的模板(主细节应用程序)。
    • 是的,但 ObjC 不这样做 @NSManaged -- 如果你试图包装底层属性,你不应该在这里使用 @NSManaged。 @NSManaged 告诉编译器属性实现将在运行时延迟提供。在明确提供实现的同时使用@NSManaged 是矛盾的。
    • 好的,谢谢。我将重新考虑删除 NSManaged。让你知道我的进展:)
    【解决方案3】:

    我已经在 Swift 中通过扩展解决了这个问题,因此无需对 NSManagedObject 进行子类化,也不必为我的模型生成类文件。

    所以对于上面带有类Number的例子,创建一个文件Number+Section.swift你可以像这样在awakeFromFetch中加载瞬态属性值

    import Foundation    
    extension Number {
        public override func awakeFromFetch() {
            super.awakeFromFetch()
            section = number.intValue >= 60 ? "Pass" : "Fail"
        }
    }
    

    我在 Apple 的 Core Data programming guide 中发现了这种加载瞬态字段的方法。

    awakeFromFetch 在对象从 持久存储(在获取期间)。您可以将 awakeFromFetch 覆盖为, 例如,建立瞬态值和其他缓存。

    【讨论】:

    • 如果您已将 Codegen 设置为“类定义”,则此方法有效。感谢您的解决方案核心数据指南清楚地解释了这一点
    • 虽然它基本上可以工作,但在将 NSFetchedResultsController 与表格视图结合使用时,这并不是一个好的解决方案:初始表格部分是正确的,但是当您更新基础数据时,显然不会调用 awakeFromFetch再次。
    • 这是一个很好的答案,特别是因为允许避免类生成只是为了拥有一个瞬态属性!比过去容易多了,谢谢!
    【解决方案4】:

    删除NSManaged 属性。

    【讨论】:

    • 不。对不起,不是这样。这部分代码是由 Xcode 生成的,所以我认为是正确的(或者至少是苹果的意图)。
    • 不要假设 ;) 如果它是暂时的,则不受管理。所以要么申请,要么你犯了一个错误
    • Xcode 生成了代码,但是您正在编写一个隐藏底层属性的方法,您和代码生成器正在考虑不同的事情。
    • 看看你的意思。我会尝试不使用 NSManaged - 我想我必须对 Xcode 生成的内容更加怀疑。
    • @Daij-Djan 是完全正确的。在这种情况下应该删除。
    猜你喜欢
    • 2011-11-23
    • 1970-01-01
    • 2011-09-16
    • 2015-11-08
    • 2018-03-25
    • 2015-02-05
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多