使用 Swift 中的核心数据在 Table 视图中分节显示数据
Displaying data in sections in a Table View using Core Data in Swift
我在使用 Swift 中的核心数据在 table 视图中显示按部分分组的数据时遇到了一些问题。
我会用一个例子来说明这个问题。让我们假设三个 类:订单、产品和服务。 Class 订单具有属性 "date" 以及与产品和服务的多对多关系。
对于每个订单,应创建一个部分来显示在特定日期订购的所有产品和服务。
使用 NSFetchedResultsController,所有订单都根据属性日期获取。这提供了正确数量的部分。
但是,我遇到了在每个部分的单独行中显示所有产品和服务的问题,因为 "numberOfRowsInSection" 基于订单数量而不是产品和服务数量。
下面是说明我的问题的代码。希望有人能帮助我找到正确的方向。
提前致谢,
杰拉德
import UIKit
import CoreData
class ExampleViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate {
@IBOutlet weak var tableView: UITableView!
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var fetchedResultController: NSFetchedResultsController = NSFetchedResultsController()
var orders = [Order]()
override func viewDidLoad() {
super.viewDidLoad()
fetchedResultController.delegate = self
tableView.dataSource = self
tableView.delegate = self
fetchData()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return fetchedResultController.sections?.count ?? 0
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionInfo = fetchedResultController.sections![section] as NSFetchedResultsSectionInfo
return sectionInfo.numberOfObjects
// Unfortunatelly, this provides not the total number of products and services per section
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let textCellIdentifier = "ExampleTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as! ExampleTableViewCell
let order = orders[indexPath.row] // Data fetched using NSFetchedResultsController
let products = order.products!.allObjects as! [Product] // Swift Array
let services = order.services!.allObjects as! [Service] // Swift Array
// Each product and each service should be displayed in separate rows.
// Instead, all products and services are displayed in a single row as below
var displaytext = ""
for product in products {
displaytext += product.name! + "\n"
}
for service in services {
displaytext += service.name! + "\n"
}
cell.orderLabel.text = displaytext // display text in ExampleTableViewCell
return cell
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if let sections = fetchedResultController.sections {
let currentSection = sections[section]
return currentSection.name
}
return nil
}
func orderFetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "Order")
let sortDescriptor = NSSortDescriptor(key: "date", ascending: true)
let predicate = NSPredicate(format: "date >= %@ AND date <= %@", startDate, endDate) // startDate and endData are defined elsewhere
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.predicate = predicate
return fetchRequest
}
func fetchData() {
let fetchRequest = orderFetchRequest()
fetchedResultController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: "date", cacheName: nil)
do {
orders = try managedObjectContext.executeFetchRequest(fetchRequest) as! [Order]
}
catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
do {
try fetchedResultController.performFetch()
}
catch _ {
}
}
}
正如 Wain 所说,FRC 并没有多大帮助。 FRC 有两个主要优点,超越普通的获取:它可以为您管理这些部分,并且它可以通过其委托方法自动处理 inserts/deletes/updates。第一个对你的情况没有用,因为你想要每个订单一个部分。第二个帮助不大,因为 FRC 只会监视一个实体的变化,但您的 table 视图是由三个实体构建的。
尽管如此,我认为您可以使用 FRC 来达到某种效果。首先,不要理会 sectionNameKeyPath
:您在 Orders
和 table 视图部分之间有一个一对一的映射,因此您可以使用 table 视图的 section
作为 FRC fetchedObjects
上的索引来标识每个部分的顺序。然后可以通过将相关 Order
的 products
和 services
的计数相加来找到 numberOrRowsInSection
。混乱(并且可能很慢)位正在将 table 视图的行映射到 products
或 services
.
的正确元素
import UIKit
import CoreData
class ExampleViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate {
@IBOutlet weak var tableView: UITableView!
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!
var fetchedResultController: NSFetchedResultsController = NSFetchedResultsController()
var orders = [Order]()
var startDate : NSDate = NSDate()
var endDate : NSDate = NSDate()
override func viewDidLoad() {
super.viewDidLoad()
fetchedResultController.delegate = self
tableView.dataSource = self
tableView.delegate = self
fetchData()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return fetchedResultController.fetchedObjects!.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let order = fetchedResultController.fetchedObjects![section] as! Order
return ((order.products?.count ?? 0) + (order.services?.count ?? 0))
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let textCellIdentifier = "ExampleTableViewCell"
let row = indexPath.row
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as! ExampleTableViewCell
let order = fetchedResultController.fetchedObjects![indexPath.section] as! Order // Data fetched using NSFetchedResultsController
let products = (order.products?.allObjects ?? [Product]()) as! [Product] // Swift Array
let services = (order.services?.allObjects ?? [Service]()) as! [Service] // Swift Array
if (row < products.count) { // this is a Product row
cell.orderLabel.text = products[row].name!
} else { // this is a Service row
cell.orderLabel.text = services[row-products.count].name!
}
return cell
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let order = fetchedResultController.fetchedObjects![section] as! Order
return "\(order.date)"
}
func orderFetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "Order")
let sortDescriptor = NSSortDescriptor(key: "date", ascending: true)
let predicate = NSPredicate(format: "date >= %@ AND date <= %@", startDate, endDate) // startDate and endData are defined elsewhere
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.predicate = predicate
return fetchRequest
}
func fetchData() {
let fetchRequest = orderFetchRequest()
fetchedResultController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath:nil, cacheName: nil)
do {
try fetchedResultController.performFetch()
}
catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
}
可能有更简洁的编码方式;我不是 Swift 爱好者。
如果您使用 FRC 委托方法,您至少可以根据需要在电视上观看 new/deleted 订单和 add/delete 部分,并且您可以使用更新来重新加载相关部分。
我在使用 Swift 中的核心数据在 table 视图中显示按部分分组的数据时遇到了一些问题。
我会用一个例子来说明这个问题。让我们假设三个 类:订单、产品和服务。 Class 订单具有属性 "date" 以及与产品和服务的多对多关系。
对于每个订单,应创建一个部分来显示在特定日期订购的所有产品和服务。
使用 NSFetchedResultsController,所有订单都根据属性日期获取。这提供了正确数量的部分。 但是,我遇到了在每个部分的单独行中显示所有产品和服务的问题,因为 "numberOfRowsInSection" 基于订单数量而不是产品和服务数量。
下面是说明我的问题的代码。希望有人能帮助我找到正确的方向。
提前致谢,
杰拉德
import UIKit
import CoreData
class ExampleViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate {
@IBOutlet weak var tableView: UITableView!
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var fetchedResultController: NSFetchedResultsController = NSFetchedResultsController()
var orders = [Order]()
override func viewDidLoad() {
super.viewDidLoad()
fetchedResultController.delegate = self
tableView.dataSource = self
tableView.delegate = self
fetchData()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return fetchedResultController.sections?.count ?? 0
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionInfo = fetchedResultController.sections![section] as NSFetchedResultsSectionInfo
return sectionInfo.numberOfObjects
// Unfortunatelly, this provides not the total number of products and services per section
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let textCellIdentifier = "ExampleTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as! ExampleTableViewCell
let order = orders[indexPath.row] // Data fetched using NSFetchedResultsController
let products = order.products!.allObjects as! [Product] // Swift Array
let services = order.services!.allObjects as! [Service] // Swift Array
// Each product and each service should be displayed in separate rows.
// Instead, all products and services are displayed in a single row as below
var displaytext = ""
for product in products {
displaytext += product.name! + "\n"
}
for service in services {
displaytext += service.name! + "\n"
}
cell.orderLabel.text = displaytext // display text in ExampleTableViewCell
return cell
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if let sections = fetchedResultController.sections {
let currentSection = sections[section]
return currentSection.name
}
return nil
}
func orderFetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "Order")
let sortDescriptor = NSSortDescriptor(key: "date", ascending: true)
let predicate = NSPredicate(format: "date >= %@ AND date <= %@", startDate, endDate) // startDate and endData are defined elsewhere
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.predicate = predicate
return fetchRequest
}
func fetchData() {
let fetchRequest = orderFetchRequest()
fetchedResultController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: "date", cacheName: nil)
do {
orders = try managedObjectContext.executeFetchRequest(fetchRequest) as! [Order]
}
catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
do {
try fetchedResultController.performFetch()
}
catch _ {
}
}
}
正如 Wain 所说,FRC 并没有多大帮助。 FRC 有两个主要优点,超越普通的获取:它可以为您管理这些部分,并且它可以通过其委托方法自动处理 inserts/deletes/updates。第一个对你的情况没有用,因为你想要每个订单一个部分。第二个帮助不大,因为 FRC 只会监视一个实体的变化,但您的 table 视图是由三个实体构建的。
尽管如此,我认为您可以使用 FRC 来达到某种效果。首先,不要理会 sectionNameKeyPath
:您在 Orders
和 table 视图部分之间有一个一对一的映射,因此您可以使用 table 视图的 section
作为 FRC fetchedObjects
上的索引来标识每个部分的顺序。然后可以通过将相关 Order
的 products
和 services
的计数相加来找到 numberOrRowsInSection
。混乱(并且可能很慢)位正在将 table 视图的行映射到 products
或 services
.
import UIKit
import CoreData
class ExampleViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate {
@IBOutlet weak var tableView: UITableView!
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!
var fetchedResultController: NSFetchedResultsController = NSFetchedResultsController()
var orders = [Order]()
var startDate : NSDate = NSDate()
var endDate : NSDate = NSDate()
override func viewDidLoad() {
super.viewDidLoad()
fetchedResultController.delegate = self
tableView.dataSource = self
tableView.delegate = self
fetchData()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return fetchedResultController.fetchedObjects!.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let order = fetchedResultController.fetchedObjects![section] as! Order
return ((order.products?.count ?? 0) + (order.services?.count ?? 0))
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let textCellIdentifier = "ExampleTableViewCell"
let row = indexPath.row
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as! ExampleTableViewCell
let order = fetchedResultController.fetchedObjects![indexPath.section] as! Order // Data fetched using NSFetchedResultsController
let products = (order.products?.allObjects ?? [Product]()) as! [Product] // Swift Array
let services = (order.services?.allObjects ?? [Service]()) as! [Service] // Swift Array
if (row < products.count) { // this is a Product row
cell.orderLabel.text = products[row].name!
} else { // this is a Service row
cell.orderLabel.text = services[row-products.count].name!
}
return cell
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let order = fetchedResultController.fetchedObjects![section] as! Order
return "\(order.date)"
}
func orderFetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "Order")
let sortDescriptor = NSSortDescriptor(key: "date", ascending: true)
let predicate = NSPredicate(format: "date >= %@ AND date <= %@", startDate, endDate) // startDate and endData are defined elsewhere
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.predicate = predicate
return fetchRequest
}
func fetchData() {
let fetchRequest = orderFetchRequest()
fetchedResultController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath:nil, cacheName: nil)
do {
try fetchedResultController.performFetch()
}
catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
}
可能有更简洁的编码方式;我不是 Swift 爱好者。
如果您使用 FRC 委托方法,您至少可以根据需要在电视上观看 new/deleted 订单和 add/delete 部分,并且您可以使用更新来重新加载相关部分。