IOS13+ NSPersistentCloudKitContainer UIRefreshControl如何刷新UITableView内容
IOS13+ NSPersistentCloudKitContainer UIRefreshControl how to refresh UITableView content
我正在使用 NSPersistentCloudKitContainer
同步数据。使用新的 iCloud 内容刷新 UITableView 内容的正确代码是什么?如果我关闭 UITableView 并重新打开它,新内容会立即出现。
我正在使用标准代码刷新 UITableView,但使用该代码我无法从 iCloud 获取新数据?
class listFirmenTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
firmenTableView.refreshControl = UIRefreshControl()
firmenTableView.refreshControl?.addTarget(self, action:
#selector(handleRefreshControl),
for: .valueChanged)
}
@objc func handleRefreshControl() {
reload(tableView: self.tableView)
// Dismiss the refresh control.
DispatchQueue.main.async {
self.firmenTableView.refreshControl?.endRefreshing()
}
}
func reload(tableView: UITableView) {
tableView.reloadData()
tableView.layoutIfNeeded()
}
使用 NSFetchedResultsController
将使您的 table 自动与 CoreData
数据库保持同步。在下面的代码中,您必须将 YourEntityName
的实例替换为您在项目中使用的真实数据库实体名称。
您可能还想适当地设置 request.sortDescriptors
。例如,如果您使用的是搜索栏,则可以在排序描述符中包含搜索栏文本,然后每次搜索栏文本更改时都必须调用方法 updateFetchedResultsController()
。
至于UIRefreshControl
,此后甚至不需要。
import UIKit
import CoreData
class YourTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {
var container: NSPersistentContainer? = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer
var fetchedResultsController: NSFetchedResultsController<YourEntityName>? {
didSet {
fetchedResultsController?.delegate = self
}
}
override func viewDidLoad() {
super.viewDidLoad()
updateFetchedResultsController()
}
func updateFetchedResultsController() {
guard let context = container?.viewContext else {
return
}
context.performAndWait {
let request: NSFetchRequest<YourEntityName> = YourEntityName.fetchRequest()
request.sortDescriptors = nil // set sort descriptors if you want data ordered specifically
request.predicate = nil // set predicate if you only want specific data
fetchedResultsController = NSFetchedResultsController<YourEntityName>(
fetchRequest: request,
managedObjectContext: context,
sectionNameKeyPath: nil,
cacheName: nil
)
do {
try fetchedResultsController!.performFetch()
tableView.reloadData()
} catch {
// Handle the error, for example, present an alert
}
}
}
// MARK:- UITableViewDataSource
override func numberOfSections(in tableView: UITableView) -> Int {
return fetchedResultsController?.sections?.count ?? 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let sections = fetchedResultsController?.sections, sections.count > 0 {
return sections[section].numberOfObjects
}
return 0
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if let sections = fetchedResultsController?.sections, sections.count > 0 {
return sections[section].name
}
return nil
}
override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return fetchedResultsController?.sectionIndexTitles
}
override func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
return fetchedResultsController?.section(forSectionIndexTitle: title, at: index) ?? 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellIdentifier", for: indexPath) as! YourTableViewCell
let object = fetchedResultsController?.object(at: indexPath)
// use data in object to update your cell
return cell
}
// MARK:- NSFetchedResultsControllerDelegate
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
switch type {
case .insert: tableView.insertSections([sectionIndex], with: .fade)
case .delete: tableView.deleteSections([sectionIndex], with: .fade)
default: break
}
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type {
case .insert:
tableView.insertRows(at: [newIndexPath!], with: .fade)
case .delete:
tableView.deleteRows(at: [indexPath!], with: .fade)
case .update:
tableView.reloadRows(at: [indexPath!], with: .fade)
case .move:
tableView.deleteRows(at: [indexPath!], with: .fade)
tableView.insertRows(at: [newIndexPath!], with: .fade)
default:
break
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
此外,请确保在 AppDelegate
中设置 container.viewContext.automaticallyMergesChangesFromParent = true
,如下所示:
lazy var persistentContainer: NSPersistentCloudKitContainer = {
let container = NSPersistentCloudKitContainer(name: "YourEntityName")
container.loadPersistentStores { description, error in
if let error = error {
// handle the error
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
return container
}()
我正在使用 NSPersistentCloudKitContainer
同步数据。使用新的 iCloud 内容刷新 UITableView 内容的正确代码是什么?如果我关闭 UITableView 并重新打开它,新内容会立即出现。
我正在使用标准代码刷新 UITableView,但使用该代码我无法从 iCloud 获取新数据?
class listFirmenTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
firmenTableView.refreshControl = UIRefreshControl()
firmenTableView.refreshControl?.addTarget(self, action:
#selector(handleRefreshControl),
for: .valueChanged)
}
@objc func handleRefreshControl() {
reload(tableView: self.tableView)
// Dismiss the refresh control.
DispatchQueue.main.async {
self.firmenTableView.refreshControl?.endRefreshing()
}
}
func reload(tableView: UITableView) {
tableView.reloadData()
tableView.layoutIfNeeded()
}
使用 NSFetchedResultsController
将使您的 table 自动与 CoreData
数据库保持同步。在下面的代码中,您必须将 YourEntityName
的实例替换为您在项目中使用的真实数据库实体名称。
您可能还想适当地设置 request.sortDescriptors
。例如,如果您使用的是搜索栏,则可以在排序描述符中包含搜索栏文本,然后每次搜索栏文本更改时都必须调用方法 updateFetchedResultsController()
。
至于UIRefreshControl
,此后甚至不需要。
import UIKit
import CoreData
class YourTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {
var container: NSPersistentContainer? = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer
var fetchedResultsController: NSFetchedResultsController<YourEntityName>? {
didSet {
fetchedResultsController?.delegate = self
}
}
override func viewDidLoad() {
super.viewDidLoad()
updateFetchedResultsController()
}
func updateFetchedResultsController() {
guard let context = container?.viewContext else {
return
}
context.performAndWait {
let request: NSFetchRequest<YourEntityName> = YourEntityName.fetchRequest()
request.sortDescriptors = nil // set sort descriptors if you want data ordered specifically
request.predicate = nil // set predicate if you only want specific data
fetchedResultsController = NSFetchedResultsController<YourEntityName>(
fetchRequest: request,
managedObjectContext: context,
sectionNameKeyPath: nil,
cacheName: nil
)
do {
try fetchedResultsController!.performFetch()
tableView.reloadData()
} catch {
// Handle the error, for example, present an alert
}
}
}
// MARK:- UITableViewDataSource
override func numberOfSections(in tableView: UITableView) -> Int {
return fetchedResultsController?.sections?.count ?? 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let sections = fetchedResultsController?.sections, sections.count > 0 {
return sections[section].numberOfObjects
}
return 0
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if let sections = fetchedResultsController?.sections, sections.count > 0 {
return sections[section].name
}
return nil
}
override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return fetchedResultsController?.sectionIndexTitles
}
override func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
return fetchedResultsController?.section(forSectionIndexTitle: title, at: index) ?? 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellIdentifier", for: indexPath) as! YourTableViewCell
let object = fetchedResultsController?.object(at: indexPath)
// use data in object to update your cell
return cell
}
// MARK:- NSFetchedResultsControllerDelegate
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
switch type {
case .insert: tableView.insertSections([sectionIndex], with: .fade)
case .delete: tableView.deleteSections([sectionIndex], with: .fade)
default: break
}
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type {
case .insert:
tableView.insertRows(at: [newIndexPath!], with: .fade)
case .delete:
tableView.deleteRows(at: [indexPath!], with: .fade)
case .update:
tableView.reloadRows(at: [indexPath!], with: .fade)
case .move:
tableView.deleteRows(at: [indexPath!], with: .fade)
tableView.insertRows(at: [newIndexPath!], with: .fade)
default:
break
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
此外,请确保在 AppDelegate
中设置 container.viewContext.automaticallyMergesChangesFromParent = true
,如下所示:
lazy var persistentContainer: NSPersistentCloudKitContainer = {
let container = NSPersistentCloudKitContainer(name: "YourEntityName")
container.loadPersistentStores { description, error in
if let error = error {
// handle the error
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
return container
}()