在tableView中使用日期的sectionName

9 浏览
0 Comments

在tableView中使用日期的sectionName

//日期

func sectionName() -> String{

var shortDate: String

let dateFormatter = NSDateFormatter()

dateFormatter.dateFormat = "MMM yyyy"

return dateFormatter.stringFromDate(NSDate())

}

//表格视图

let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchedRequest, managedObjectContext: coreDataStack.managedObjectContext!, sectionNameKeyPath: "sectionName", cacheName: nil)

//错误

不明原因导致应用程序在"sectionName"处崩溃,报错为"is not key value coding-compliant for the key "sectionName"."

0
0 Comments

在使用sectionName()函数时,可能将其定义为一个自由函数,而不是被获取的托管对象子类的属性或方法。此外,将“当前日期”格式化为字符串并没有太多意义,因为您可能想根据实体的某个日期属性对对象进行分组。

Apple的示例项目Custom Section Titles with NSFetchedResultsController演示了如何根据“timeStamp”属性的月份和年份将表视图分组为部分。该项目是用Objective-C编写的。

下面是如何在Swift中实现相同效果的简短步骤。

首先,在“Event”实体中添加一个类型为“String”的“sectionIdentifier”瞬态属性

接下来,定义Event类的sectionIdentifier属性。可以直接在class Event { ... }定义中完成,也可以作为扩展:

extension Event {

var sectionIdentifier : String? {

// 根据需要创建和缓存部分标识符

self.willAccessValueForKey("sectionIdentifier")

var tmp = self.primitiveValueForKey("sectionIdentifier") as? String

self.didAccessValueForKey("sectionIdentifier")

if tmp == nil {

if let timeStamp = self.valueForKey("timeStamp") as? NSDate {

/*

部分按月份和年份组织。创建表示数字(年份 * 1000)+ 月份的字符串作为部分标识符;

这样无论月份的实际名称如何,它们都将按照时间顺序正确排序。

*/

let calendar = NSCalendar.currentCalendar()

let components = calendar.components(.CalendarUnitYear | .CalendarUnitMonth, fromDate: timeStamp)

tmp = String(format: "%ld", components.year * 1000 + components.month)

self.setPrimitiveValue(tmp, forKey: "sectionIdentifier")

}

}

return tmp

}

}

在表视图控制器中,您必须重写titleForHeaderInSection方法,以根据部分标识符计算正确的标题:

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

/*

* 创建一个日期格式化程序是“昂贵”的。使用静态属性,这样只需要执行一次。

*/

struct Formatter {

static let formatter : NSDateFormatter = {

let fmt = NSDateFormatter()

let dateFormat = NSDateFormatter.dateFormatFromTemplate("MMMM yyyy", options: 0,

locale: NSLocale.currentLocale())

fmt.dateFormat = dateFormat

return fmt

}()

}

/*

部分信息来自事件的部分标识符,其是一个表示数字(年份 * 1000)+ 月份的字符串。

为了显示部分标题,将年份和月份组件转换为字符串表示。

*/

if let theSection = fetchedResultsController.sections?[section] as? NSFetchedResultsSectionInfo,

let numericSection = theSection.name?.toInt() {

let components = NSDateComponents()

components.year = numericSection / 1000

components.month = numericSection % 1000

if let date = NSCalendar.currentCalendar().dateFromComponents(components) {

let titleString = Formatter.formatter.stringFromDate(date)

return titleString

}

}

return nil

}

最后,使用“timeStamp”作为第一个排序描述符和“sectionIdentifier”作为sectionNameKeyPath来创建获取结果控制器:

let fetchRequest = NSFetchRequest(entityName: "Event")

let timeStampSort = NSSortDescriptor(key: "timeStamp", ascending: false)

fetchRequest.sortDescriptors = [timeStampSort]

let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest,

managedObjectContext: context,

sectionNameKeyPath: "sectionIdentifier",

cacheName: nil)

如果对象的时间戳可以修改,则情况会稍微复杂一些。相应的“sectionIdentifier”必须无效化,以便按需重新计算。

在Objective-C中,通过仅重写“timeStamp”属性的getter方法很简单(参见DateSectionTitles/APLEvent.m)。在Swift中,似乎需要将“timeStamp”定义为一个普通的计算属性(没有NSManagedObject),如https://devforums.apple.com/thread/262118?tstart=0中讨论的那样:

class Event: NSManagedObject {

// var timeStamp : NSDate

var timeStamp: NSDate? {

get {

self.willAccessValueForKey("timeStamp")

let tmp = self.primitiveValueForKey("timeStamp") as? NSDate

self.didAccessValueForKey("timeStamp")

return tmp

}

set {

self.willChangeValueForKey("timeStamp")

self.setPrimitiveValue(newValue, forKey: "timeStamp")

self.didChangeValueForKey("timeStamp")

// 如果时间戳发生变化,部分标识符将变为无效。

self.setPrimitiveValue(nil, forKey: "sectionIdentifier")

}

}

override class func keyPathsForValuesAffectingValueForKey(key: String) -> Set<NSObject> {

var keyPaths = super.keyPathsForValuesAffectingValueForKey(key)

if key == "sectionIdentifier" {

keyPaths.insert("timeStamp")

}

return keyPaths

}

}

更新:Swift 4开始,您必须通过添加@objc属性,明确将自定义的Core Data属性显示给Objective-C运行时,例如:

var sectionIdentifier : String? { ... }

var timeStamp: NSDate? { ... }

有关此更改的更多信息,请参见:

- Swift 4 "This class is not key value coding compliant"

- How can I deal with inference deprecation with #selector() in Swift 4?

嘿,-r,我按照您的代码在iOS 10上运行正常。但在iOS 11上,该属性无法识别,应用程序崩溃:stackoverflow.com/questions/45610890/…。您有任何想法吗?

:我认为您只需在变量的定义之前添加@objc,就像我在您的其他问题中评论的那样(这将使其成为一个重复问题)。如果有帮助,请告诉我,我将在此处更新代码。谢谢!

添加objc到变量的定义之前解决了该问题。感谢您的评论!

0