Swift CoreData:无法使用带自定义函数的sectionNameKeyPath来分割tableView

时间:2018-03-24 07:45:49

标签: swift core-data

我是CoreData的极端新手,我正在尝试使用自定义函数使用fetchedResultsController对我的tableView进行分区。我当前的实现没有设法分区tableView,我仍然只给了1节。

我在实施中引用了以下帖子:herehere。我也采用了瞬态属性。

我首先使用Xcode创建NSManagedObject子类(Editor - > Create NSMangedObject Subclass)并添加var sectionIdentifier以返回自定义字符串。不幸的是,我的frc只返回1个部分。

// from the Conversation+CoreDataProperties.swift file automatically generated by Xcode
import Foundation
import CoreData


extension Conversation {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Conversation> {
        return NSFetchRequest<Conversation>(entityName: "Conversation")
    }

    @NSManaged public var conversationStartTime: Double
    @NSManaged public var profileImage: NSData?
    @NSManaged public var recipientID: String?
    @NSManaged public var recipientUsername: String?
    @NSManaged public var shoutoutID: String?
    @NSManaged public var unreadMessagesCount: Int32

    var sectionIdentifier: String? {
        let presentTimestamp = NSDate().timeIntervalSince1970

        if conversationStartTime < presentTimestamp - Double(Constants.PermissibleDurationInMinutes * 60) {
            return "Expired Conversations"
        } else {
            return "Active Conversations"
        }
    }
}

//at VC
lazy var fetchedResultsController: NSFetchedResultsController<Conversation> = {
    let context = CoreDataManager.shared.persistentContainer.viewContext

    let request: NSFetchRequest<Conversation> = Conversation.fetchRequest()
    request.sortDescriptors = [NSSortDescriptor(key: "conversationStartTime", ascending: true)]

    let frc = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: "sectionIdentifier", cacheName: nil)
    frc.delegate = self

    do {
        try frc.performFetch()
    } catch let err {
        print(err)
    }

    return frc
}()

在控制台中打印出对话实体会返回此

<Conversation: 0x604000e93100> (entity: Conversation; id: 0xd000000003e00000 <x-coredata://91BC90B2-9A0C-45A7-9B82-844BE88BAFE0/Conversation/p248> ; data: {
    conversationStartTime = "1521359598.88445";
    profileImage = <ffd8ffe0 00104a46 49460001 02000001 00010000 ffed009c 50686f74 6f73686f 7020332e 30003842 494d0404 00000000 0080>;
    recipientID = "-L7rvH71i-KUXvLQVDOh";
    recipientUsername = Angemon;
    sectionIdentifier = nil;
    shoutoutID = "-L7rvH71i-KUXvLQVDOh";
    unreadMessagesCount = 0; })

不知何故,sectionIdentifier总是为零。任何建议为什么会发生这种情况?在一天结束时,我想将我的会话列表分为两部分,第一部分是“主动对话”,第二部分是“过期对话”,具体取决于会话的持续时间。

更新代码:

// At Conversation+CoreDataProperties.swift
import Foundation
import CoreData


extension Conversation {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Conversation> {
        return NSFetchRequest<Conversation>(entityName: "Conversation")
    }

    @NSManaged public var conversationStartTime: Double
    @NSManaged public var profileImage: NSData?
    @NSManaged public var recipientID: String?
    @NSManaged public var recipientUsername: String?
    @NSManaged public var shoutoutID: String?
    @NSManaged public var unreadMessagesCount: Int32

    @objc var sectionIdentifier: String {
        willAccessValue(forKey: "sectionIdentifier")

        let presentTimestamp = NSDate().timeIntervalSince1970
        var text = ""
        if conversationStartTime < presentTimestamp - Double(Constants.PermissibleDurationInMinutes * 60) {
            text = "Expired Conversations"
        } else {
            text = "Active Conversations"
        }

        didAccessValue(forKey: "sectionIdentifier")
        return text
    }
}

//At VC
lazy var fetchedResultsController: NSFetchedResultsController<Conversation> = {
    let context = CoreDataManager.shared.persistentContainer.viewContext

    let request: NSFetchRequest<Conversation> = Conversation.fetchRequest()
    request.sortDescriptors = [
                               NSSortDescriptor(key: "conversationStartTime", ascending: false)
                                    ]

    let frc = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: "sectionIdentifier", cacheName: nil)
    frc.delegate = self

    do {
        try frc.performFetch()
    } catch let err {
        print(err)
    }

    return frc
}()

在我的CoreData模型屏幕上: enter image description here

1 个答案:

答案 0 :(得分:0)

这是@Sandeep答案的延续,因为我想看看是否有可能通过一个瞬态属性进行分组而没有排序描述符,因为你的一个链接暗示它应该可以这样做。 / p>

经过一些实验,我设法得出结论,如果你满足两个条件是可能的:

  • 您需要在用于计算瞬态属性的持久属性上使用排序描述符(并且它必须是第一个)
  • 排序描述符的排序顺序需要与瞬态属性匹配。

(我假设这适用于您访问多个持久属性以及您的瞬态属性,所有这些属性的排序描述符以及排序顺序需要匹配但我还没有经过测试)

我认为你实现了第一个而不是第二个,因为你的排序描述符有升序=真但是因为&#34;活跃&#34;来之前&#34;已过期&#34;你有sectionIdentifier的隐式降序排序。

这是我用一些现有代码制作的一个愚蠢的例子,因为我有一些可用的测试数据。正如你所看到的,我把这个月的日子分为三个部分,以便按时间倒序显示。

@objc var silly: String {
    willAccessValue(forKey: #keyPath(silly))
    var result: String = "In between"

    let component = Calendar.current.component(Calendar.Component.day, from: date)
    if component <= 13 {
        result = "Last"
    } else if component > 20 {
        result = "At the Top"
    }
    didAccessValue(forKey: #keyPath(silly))
    return result
}

在设置我的提取结果控制器时,我做了

...
fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(Location.date), ascending: false)]  

let fetchedResultController = NSFetchedResultsController(fetchRequest: fetchRequest,
                                                             managedObjectContext: managedObjectContext,
                                                             sectionNameKeyPath: #keyPath(Location.silly),
                                                             cacheName: "Locations")

在第一次执行请求后,必须使用will / didAccessValue(...)来处理新对象的插入和更新,否则该属性将设置为nil。