Swift 使用NSFetchRequest从CoreData填充TableView
我需要用核心数据中的数据填充表视图。 我可以显示我的行,但我不能填充我的tableview! 我使用Swift 3和Xcode 8。 这是我的代码,在这个控制器中我必须显示列表Swift 使用NSFetchRequest从CoreData填充TableView,swift,xcode,uitableview,core-data,nsfetchrequest,Swift,Xcode,Uitableview,Core Data,Nsfetchrequest,我需要用核心数据中的数据填充表视图。 我可以显示我的行,但我不能填充我的tableview! 我使用Swift 3和Xcode 8。 这是我的代码,在这个控制器中我必须显示列表 class iTableViewController: UITableViewController, NSFetchedResultsControllerDelegate{ @IBOutlet var iTableView: UITableView! override func viewDidLoad(){
class iTableViewController: UITableViewController, NSFetchedResultsControllerDelegate{
@IBOutlet var iTableView: UITableView!
override func viewDidLoad(){
super.viewDidLoad()
iTableView.dataSource = self
iTableView.delegate = self
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managerContext = appDelegate.persistentContainer.viewContext
let interventsFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "Intervento")
do{
//results
let fetchedIntervents = try managerContext.fetch(interventsFetch) as! [Intervento]
for interv in fetchedIntervents{
print(interv.stampRow())
}
NSLog(String(fetchedIntervents.count))
}catch{
fatalError("Failed to fetch employees: \(error)")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//number of sections
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
//numer of rows
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
//cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "cell")
cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
//print the example cell
cell.textLabel?.text = "title"
cell.detailTextLabel?.text = "subtitle"
return cell
}
//swipe and delete
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath){
if(editingStyle == UITableViewCellEditingStyle.delete){
//TODO
}
}
// click cell
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
performSegue(withIdentifier: "segueDetail", sender: self)
}
override func viewDidAppear(_ animated: Bool){
//iTableView.reloadData()
}
override func viewWillDisappear(_ animated: Bool) {
//iTableView.reloadData()
//fetchData()
}
}
首先,您的类应该实现以下协议:
UIViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate
您可以使用以下代码从持久性存储器加载数据:
//load data
//persistant container
let persistentContainer = NSPersistentContainer.init(name: "Model")
//
lazy var fetchedResultsController: NSFetchedResultsController<Intervento> = {
// Create Fetch Request
let fetchRequest: NSFetchRequest<Intervento> = Intervento.fetchRequest()
// Configure Fetch Request
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "dataInizio", ascending: false)]
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managerContext = appDelegate.persistentContainer.viewContext
// Create Fetched Results Controller
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managerContext, sectionNameKeyPath: nil, cacheName: nil)
// Configure Fetched Results Controller
fetchedResultsController.delegate = self
return fetchedResultsController
}()
//carica
func load(){
//persistant container
persistentContainer.loadPersistentStores { (persistentStoreDescription, error) in
if let error = error {
print("Unable to Load Persistent Store")
print("\(error), \(error.localizedDescription)")
} else {
do {
try self.fetchedResultsController.performFetch()
} catch {
let fetchError = error as NSError
print("Unable to Perform Fetch Request")
print("\(fetchError), \(fetchError.localizedDescription)")
}
}
}
}
override func viewDidLoad(){
super.viewDidLoad()
iTableView.delegate = self
iTableView.dataSource = self
// trigger load
load()
}
为了实现此功能,您的ViewController必须符合NSFetchedResultsControllerDelegate协议,在这里您可以找到一个可行的实现:
extension iTableViewController: NSFetchedResultsControllerDelegate {
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
iTableView.beginUpdates()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
iTableView.endUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch (type) {
case .insert:
if let indexPath = newIndexPath {
iTableView.insertRows(at: [indexPath], with: .fade)
}
break;
case .delete:
if let indexPath = indexPath {
iTableView.deleteRows(at: [indexPath], with: .fade)
}
break;
case .update:
if let indexPath = indexPath, let cell = iTableView.cellForRow(at: indexPath) {
configureCell(cell, at: indexPath)
}
break;
case .move:
if let indexPath = indexPath {
iTableView.deleteRows(at: [indexPath], with: .fade)
}
if let newIndexPath = newIndexPath {
iTableView.insertRows(at: [newIndexPath], with: .fade)
}
break;
}
}
}
有关完整示例,请参见此处:首先,您的类应实现以下协议:
UIViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate
您可以使用以下代码从持久性存储器加载数据:
//load data
//persistant container
let persistentContainer = NSPersistentContainer.init(name: "Model")
//
lazy var fetchedResultsController: NSFetchedResultsController<Intervento> = {
// Create Fetch Request
let fetchRequest: NSFetchRequest<Intervento> = Intervento.fetchRequest()
// Configure Fetch Request
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "dataInizio", ascending: false)]
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managerContext = appDelegate.persistentContainer.viewContext
// Create Fetched Results Controller
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managerContext, sectionNameKeyPath: nil, cacheName: nil)
// Configure Fetched Results Controller
fetchedResultsController.delegate = self
return fetchedResultsController
}()
//carica
func load(){
//persistant container
persistentContainer.loadPersistentStores { (persistentStoreDescription, error) in
if let error = error {
print("Unable to Load Persistent Store")
print("\(error), \(error.localizedDescription)")
} else {
do {
try self.fetchedResultsController.performFetch()
} catch {
let fetchError = error as NSError
print("Unable to Perform Fetch Request")
print("\(fetchError), \(fetchError.localizedDescription)")
}
}
}
}
override func viewDidLoad(){
super.viewDidLoad()
iTableView.delegate = self
iTableView.dataSource = self
// trigger load
load()
}
为了实现此功能,您的ViewController必须符合NSFetchedResultsControllerDelegate协议,在这里您可以找到一个可行的实现:
extension iTableViewController: NSFetchedResultsControllerDelegate {
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
iTableView.beginUpdates()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
iTableView.endUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch (type) {
case .insert:
if let indexPath = newIndexPath {
iTableView.insertRows(at: [indexPath], with: .fade)
}
break;
case .delete:
if let indexPath = indexPath {
iTableView.deleteRows(at: [indexPath], with: .fade)
}
break;
case .update:
if let indexPath = indexPath, let cell = iTableView.cellForRow(at: indexPath) {
configureCell(cell, at: indexPath)
}
break;
case .move:
if let indexPath = indexPath {
iTableView.deleteRows(at: [indexPath], with: .fade)
}
if let newIndexPath = newIndexPath {
iTableView.insertRows(at: [newIndexPath], with: .fade)
}
break;
}
}
}
有关完整示例,请参见此处:Swift 3.3
lazy var fetchedResultsController: NSFetchedResultsController<SavedContact> = {
let fetchReqest: NSFetchRequest<SavedContact> = SavedContact.fetchRequest()
fetchReqest.sortDescriptors = [NSSortDescriptor(key: "id", ascending: true)]
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchReqest, managedObjectContext: Database.shared.mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController.delegate = self
return fetchedResultsController
}()
override func viewDidLoad() {
super.viewDidLoad()
self.performFetch()
}
func performFetch() {
do {
try self.fetchedResultsController.performFetch()
} catch {
Debug.Log(message: "Error in fetching Contact \(error)")
}
}
//MARK: - NSFetchResultcontrollerDelegate
extension YourViewC: NSFetchedResultsControllerDelegate {
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
self.tableView.reloadData()
}
}
// Database Class
private let _singletonInstance: Database = Database()
class Database: NSObject {
class var shared: Database {
return _singletonInstance
}
override init() {
super.init()
}
// Main Managed Object Context
lazy var mainManagedObjectContext: NSManagedObjectContext = {
let coordinator = self.persistentStoreCoordinator
var mainManagedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
mainManagedObjectContext.persistentStoreCoordinator = coordinator
return mainManagedObjectContext
}()
// Persistent Store Coordinator
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
let mOptions = [NSMigratePersistentStoresAutomaticallyOption: true,
NSInferMappingModelAutomaticallyOption: true]
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.appendingPathComponent("AppName.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: mOptions)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" as AnyObject?
dict[NSLocalizedFailureReasonErrorKey] = failureReason as AnyObject?
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
abort()
}
return coordinator
}()
// DB Directory and Path
lazy var applicationDocumentsDirectory: URL = {
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentDirectoryURL = urls[urls.count - 1] as URL
let dbDirectoryURL = documentDirectoryURL.appendingPathComponent("DB")
if FileManager.default.fileExists(atPath: dbDirectoryURL.path) == false{
do{
try FileManager.default.createDirectory(at: dbDirectoryURL, withIntermediateDirectories: false, attributes: nil)
}catch{
}
}
return dbDirectoryURL
}()
}
Swift 3.3
lazy var fetchedResultsController: NSFetchedResultsController<SavedContact> = {
let fetchReqest: NSFetchRequest<SavedContact> = SavedContact.fetchRequest()
fetchReqest.sortDescriptors = [NSSortDescriptor(key: "id", ascending: true)]
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchReqest, managedObjectContext: Database.shared.mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController.delegate = self
return fetchedResultsController
}()
override func viewDidLoad() {
super.viewDidLoad()
self.performFetch()
}
func performFetch() {
do {
try self.fetchedResultsController.performFetch()
} catch {
Debug.Log(message: "Error in fetching Contact \(error)")
}
}
//MARK: - NSFetchResultcontrollerDelegate
extension YourViewC: NSFetchedResultsControllerDelegate {
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
self.tableView.reloadData()
}
}
// Database Class
private let _singletonInstance: Database = Database()
class Database: NSObject {
class var shared: Database {
return _singletonInstance
}
override init() {
super.init()
}
// Main Managed Object Context
lazy var mainManagedObjectContext: NSManagedObjectContext = {
let coordinator = self.persistentStoreCoordinator
var mainManagedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
mainManagedObjectContext.persistentStoreCoordinator = coordinator
return mainManagedObjectContext
}()
// Persistent Store Coordinator
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
let mOptions = [NSMigratePersistentStoresAutomaticallyOption: true,
NSInferMappingModelAutomaticallyOption: true]
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.appendingPathComponent("AppName.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: mOptions)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" as AnyObject?
dict[NSLocalizedFailureReasonErrorKey] = failureReason as AnyObject?
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
abort()
}
return coordinator
}()
// DB Directory and Path
lazy var applicationDocumentsDirectory: URL = {
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentDirectoryURL = urls[urls.count - 1] as URL
let dbDirectoryURL = documentDirectoryURL.appendingPathComponent("DB")
if FileManager.default.fileExists(atPath: dbDirectoryURL.path) == false{
do{
try FileManager.default.createDirectory(at: dbDirectoryURL, withIntermediateDirectories: false, attributes: nil)
}catch{
}
}
return dbDirectoryURL
}()
}
你的代码很混乱。UITableViewController包含预定义的UITableView实例,该实例具有连接的委托和数据源。您正在使用NSFetchedResultsController吗?这段代码与手动获取数据完全不同。数据源阵列在哪里?类名称应该以大写字母开头。PS:选中“核心数据”复选框创建新的主详细信息项目。您将免费获得所需的几乎全部代码。谢谢,我已经添加了我的类和用于保存在数据库中的代码。也许我需要使用NsFetchedResultController,但如何使用NSFetchedResultsController是处理核心数据获取的一种非常方便的方法。遵循我在第二条评论中的建议。@Matt这是一个使用NSFetchedResultsController的很好的参考:您的代码令人困惑。UITableViewController包含预定义的UITableView实例,该实例具有连接的委托和数据源。您正在使用NSFetchedResultsController吗?这段代码与手动获取数据完全不同。数据源阵列在哪里?类名称应该以大写字母开头。PS:选中“核心数据”复选框创建新的主详细信息项目。您将免费获得所需的几乎全部代码。谢谢,我已经添加了我的类和用于保存在数据库中的代码。也许我需要使用NsFetchedResultController,但如何使用NSFetchedResultsController是处理核心数据获取的一种非常方便的方法。按照我在第二条评论中的建议来做。@Matt这是一个很好的参考资料,可以使用NSFetchedResultsController进行分析:谢谢你的详细回答,Mariusz!马吕斯,为了得到详细的答案,他工作得很卖力!工作得很有魅力
lazy var fetchedResultsController: NSFetchedResultsController<SavedContact> = {
let fetchReqest: NSFetchRequest<SavedContact> = SavedContact.fetchRequest()
fetchReqest.sortDescriptors = [NSSortDescriptor(key: "id", ascending: true)]
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchReqest, managedObjectContext: Database.shared.mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController.delegate = self
return fetchedResultsController
}()
override func viewDidLoad() {
super.viewDidLoad()
self.performFetch()
}
func performFetch() {
do {
try self.fetchedResultsController.performFetch()
} catch {
Debug.Log(message: "Error in fetching Contact \(error)")
}
}
//MARK: - NSFetchResultcontrollerDelegate
extension YourViewC: NSFetchedResultsControllerDelegate {
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
self.tableView.reloadData()
}
}
// Database Class
private let _singletonInstance: Database = Database()
class Database: NSObject {
class var shared: Database {
return _singletonInstance
}
override init() {
super.init()
}
// Main Managed Object Context
lazy var mainManagedObjectContext: NSManagedObjectContext = {
let coordinator = self.persistentStoreCoordinator
var mainManagedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
mainManagedObjectContext.persistentStoreCoordinator = coordinator
return mainManagedObjectContext
}()
// Persistent Store Coordinator
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
let mOptions = [NSMigratePersistentStoresAutomaticallyOption: true,
NSInferMappingModelAutomaticallyOption: true]
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.appendingPathComponent("AppName.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: mOptions)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" as AnyObject?
dict[NSLocalizedFailureReasonErrorKey] = failureReason as AnyObject?
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
abort()
}
return coordinator
}()
// DB Directory and Path
lazy var applicationDocumentsDirectory: URL = {
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentDirectoryURL = urls[urls.count - 1] as URL
let dbDirectoryURL = documentDirectoryURL.appendingPathComponent("DB")
if FileManager.default.fileExists(atPath: dbDirectoryURL.path) == false{
do{
try FileManager.default.createDirectory(at: dbDirectoryURL, withIntermediateDirectories: false, attributes: nil)
}catch{
}
}
return dbDirectoryURL
}()
}