//date
func sectionName() -> String{
var shortDate: String
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MMM yyyy"
return dateFormatter.stringFromDate(NSDate())
}
//tableView
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchedRequest, managedObjectContext: coreDataStack.managedObjectContext!, sectionNameKeyPath: "sectionName", cacheName: nil)
//错误
is not key value coding-compliant for the key "sectionName".'
我被困在应用程序崩溃的“sectionName”我不知道为什么。
答案 0 :(得分:2)
您可能已将sectionName()
定义为自由函数,
而不是作为托管对象子类的属性或方法
牵强。还将“当前日期”格式化为字符串
没有多大意义,因为您可能想要对对象进行分组
根据您实体的某些日期属性。
Apple的示例项目Custom Section Titles with NSFetchedResultsController演示了如何将表视图分组 基于“timeStamp”属性的月份和年份的部分。
该项目是用 Objective-C 编写的。
这是一个简短的配方,如何在 Swift 中实现同样的目标。
在下面,我假设实体和托管对象
子类称为Event
,并且应该对事件进行分组
根据{{1}}财产的月份和年份。
首先,添加“String”类型的 transient 属性“sectionIdentifier” 到“事件”实体。
接下来,定义timeStamp
类的sectionIdentifier
属性。
这可以直接在Event
定义中完成
或作为扩展名:
class Event { ... }
在表视图控制器中,您必须覆盖
extension Event {
var sectionIdentifier : String? {
// Create and cache the section identifier on demand.
self.willAccessValueForKey("sectionIdentifier")
var tmp = self.primitiveValueForKey("sectionIdentifier") as? String
self.didAccessValueForKey("sectionIdentifier")
if tmp == nil {
if let timeStamp = self.valueForKey("timeStamp") as? NSDate {
/*
Sections are organized by month and year. Create the section
identifier as a string representing the number (year * 1000) + month;
this way they will be correctly ordered chronologically regardless
of the actual name of the month.
*/
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
最后,使用“timeStamp”创建获取的结果控制器
作为第一个排序描述符,“sectionIdentifier”作为override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
/*
* Creating a date formatter is "expensive". Use a static property so that
* this is done only once.
*/
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
}()
}
/*
Section information derives from an event's sectionIdentifier, which is a string
representing the number (year * 1000) + month.
To display the section title, convert the year and month components to a string representation.
*/
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
}
:
sectionNameKeyPath
如果对象的时间戳可以修改,那么事情就会变成 稍微复杂一点。相应的“sectionIdentifier” 必须无效,以便按要求再次计算。 在Objective-C中,通过覆盖getter方法相当简单 仅限“timeStamp”属性(请参阅DateSectionTitles/APLEvent.m)。在Swift看来这似乎 要求你将“timeStamp”定义为普通的计算属性(没有@NSManaged),如https://devforums.apple.com/thread/262118?tstart=0中所述:
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)
更新:从 Swift 4 开始,您必须通过添加为Objective-C运行时显式显示自定义Core Data属性
class Event: NSManagedObject {
//@NSManaged 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")
// If the time stamp changes, the section identifier become invalid.
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
}
}
属性,例如
@objc
有关此更改的详细信息,请参阅