我有tableView
,其中填充了fetchedResultsController
。一切正常。根据需要,tableView
根据需要加载managedObjectContext
中的数据。问题是它的数据太多,所以我创建了一个CLLocationManager
类,其中包含一个协议,当tableView
有一个位置时,它会通知fetchedResultsController
,而tableView控制器会在LocationManager
上添加一个谓词减少可能性的数量。
我遇到的问题是应用的初始加载。似乎在tableView
完成加载之前调用了import CoreLocation
protocol LocationManagerDelegate: class {
func updateTableView()
}
class LocationManager: NSObject {
static let sharedInstance = LocationManager()
public var currentLocation: CLLocation? {
get {
return locationManager.location
}
}
private var locationManager = CLLocationManager()
private override init() {
super.init()
locationManager.delegate = self
self.getCurrentLocation()
}
public weak var delegate: LocationManagerDelegate?
public func updateLocation() {
getCurrentLocation()
}
private func getCurrentLocation() {
// Also tried without the DispatchQueue
DispatchQueue.global(qos: .userInitiated).async {
// DispatchQueue.global(qos: .userInitiated).sync {
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
}
}
extension LocationManager: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
delegate?.updateTableView()
// still crashes
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.delegate?.updateTableView()
}
}
}
委托。
我在初次发布时遇到此错误,但不会在后续发布中出现:
[错误]错误:严重的应用程序错误。在调用-controllerDidChangeContent:期间,从NSFetchedResultsController的委托中捕获到异常。无效更新:无效的节数。更新后的表视图中包含的节数(1)必须等于更新前的表视图中包含的节数(0),加上或减去插入或删除的节数(0插入,0删除)。 with userInfo(null)
CoreData:错误:严重的应用程序错误。在调用-controllerDidChangeContent:期间,从NSFetchedResultsController的委托中捕获到异常。无效更新:无效的节数。更新后的表视图中包含的节数(1)必须等于更新前的表视图中包含的节数(0),加上或减去插入或删除的节数(0插入,0删除)。 with userInfo(null)
locationManager
我一直在AppDelegate.swift
启动 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
LocationManager.sharedInstance.updateLocation()
return true
}
以加快加载时间。
viewDidLoad
认为这是罪魁祸首,我把它移到了locationManager
的末尾,没有成功。应用程序在初始启动后加载了精细的NSFetchedResultsControllerDelegate
委托,但我无法在初始启动时解决错误。
以下是我的// MARK: - NSFetchedResultsControllerDelegate methods
extension MyViewController: NSFetchedResultsControllerDelegate {
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.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 {
tableView.insertRows(at: [indexPath], with: .automatic)
}
break;
case .delete:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .automatic)
}
break;
case .update:
if let indexPath = indexPath, let cell = tableView.cellForRow(at: indexPath) {
configureCell(cell, at: indexPath)
}
break;
case .move:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .automatic)
}
if let newIndexPath = newIndexPath {
tableView.insertRows(at: [newIndexPath], with: .automatic)
}
break;
}
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
print("controller didChange sectionInfo")
}
}
extension MyViewController: LocationManagerDelegate {
func updateTableView() {
filterBasedOnDistance(miles: Double(slider.value))
}
}
实施:
updateTableView()
以下是 private func degreeRangeInMiles(degrees: Double, miles: Double) -> Range<Double> {
let metersPerDegree: Double = 111_000
let degreesInMeters = degrees * metersPerDegree
let metersPerMileDouble = 1_609.344
let milesDifferential = miles * metersPerMileDouble
let upperBound = (degreesInMeters + milesDifferential) / metersPerDegree
let lowerBound = (degreesInMeters - milesDifferential) / metersPerDegree
return Range(lowerBound..<upperBound)
}
func filterBasedOnDistance(miles: Double) {
guard locationManager.currentLocation != nil else { return }
let latitude = locationManager.currentLocation?.coordinate.latitude
let longitude = locationManager.currentLocation?.coordinate.longitude
let latitudeRange = degreeRangeInMiles(degrees: latitude!, miles: miles)
let longitudeRange = degreeRangeInMiles(degrees: longitude!, miles: miles)
let distancePredicate = NSPredicate(format: "latitude BETWEEN { \(latitudeRange.lowerBound),\(latitudeRange.upperBound) } AND longitude BETWEEN {\(longitudeRange.lowerBound),\(longitudeRange.upperBound)}")
fetchedResultsController.fetchRequest.predicate = distancePredicate
do {
try fetchedResultsController.performFetch()
} catch {
print(error.localizedDescription)
}
tableView.reloadData()
}
调用的方法:
LocationManager
我想弄明白我的错误在哪里,我该如何解决?谢谢你的阅读!
更新
我尝试在 public var locationServicesAuthorized: Bool {
get {
return CLLocationManager.locationServicesEnabled()
}
}
类上添加面向公众的get-only属性,以确定设备的授权状态:
extension MyViewController: LocationManagerDelegate {
func updateTableView() {
guard locationManager.locationServicesAuthorized else { return }
filterBasedOnDistance(miles: Double(slider.value))
}
}
我更新了我的委托方法调用,如下所示:
beginUpdates
结果相同。即使我已经实现了endUpdates
和 using Android.App;
using Android.Content.PM;
using Android.Content.Res;
using Android.OS;
using Android.Support.V4.Widget;
using Android.Views;
using Android.Widget;
using System.Collections;
using Android.Support.V7.App;
using Android.Support.V4.View;
using Android.Support.Design.Widget;
using Auth0.OidcClient;
using Android.Content;
using IdentityModel.OidcClient;
using Android.Graphics;
using System.Net;
using System;
using Android.Runtime;
using Android.Text.Method;
using System.Text;
using System.Threading;
using System.Collections.Generic;
namespace whirlpoolgratitudeapp
{
[Activity(Label = "whirlpoolgratitudeapp", MainLauncher = true, Icon = "@drawable/icon")]
[IntentFilter(
new[] { Intent.ActionView },
Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
DataScheme = "whirlpoolgratitudeapp.whirlpoolgratitudeapp",
DataHost = "lucasmsantos.auth0.com",
DataPathPrefix = "/android/whirlpoolgratitudeapp.whirlpoolgratitudeapp/callback")]
public class MainActivity : Activity
{
private ArrayList enderecos;
TextView queroreconhecer;
TextView crie;
TextView conquiste;
TextView entregue;
TextView viva;
TextView comentar;
EditText comentário;
Spinner spinner;
ArrayAdapter adapter;
RadioGroup rdgcrie;
RadioGroup rdgconquiste;
RadioGroup rdgentregue;
RadioGroup rdgviva;
Button enviar;
private Auth0Client client;
private AuthorizeState authorizeState;
ProgressDialog progress;
List<RadioGroup> lista = new List<RadioGroup>();
protected override void OnResume()
{
base.OnResume();
if (progress != null)
{
progress.Dismiss();
progress.Dispose();
progress = null;
}
}
protected override async void OnNewIntent(Intent intent)
{
base.OnNewIntent(intent);
var loginResult = await client.ProcessResponseAsync(intent.DataString, authorizeState);
var sb = new StringBuilder();
if (loginResult.IsError)
{
sb.AppendLine($"An error occurred during login: {loginResult.Error}");
}
else
{
sb.AppendLine($"ID Token: {loginResult.IdentityToken}");
sb.AppendLine($"Access Token: {loginResult.AccessToken}");
sb.AppendLine($"Refresh Token: {loginResult.RefreshToken}");
sb.AppendLine();
sb.AppendLine("-- Claims --");
foreach (var claim in loginResult.User.Claims)
{
sb.AppendLine($"{claim.Type} = {claim.Value}");
}
}
}
private async void LoginButtonOnClick(object sender, EventArgs eventArgs)
{
progress = new ProgressDialog(this);
progress.SetTitle("Log In");
progress.SetMessage("Please wait while redirecting to login screen...");
progress.SetCancelable(false); // disable dismiss by tapping outside of the dialog
progress.Show();
// Prepare for the login
authorizeState = await client.PrepareLoginAsync();
// Send the user off to the authorization endpoint
var uri = Android.Net.Uri.Parse(authorizeState.StartUrl);
var intent = new Intent(Intent.ActionView, uri);
intent.AddFlags(ActivityFlags.NoHistory);
StartActivity(intent);
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
client = new Auth0Client(new Auth0ClientOptions
{
Domain = Resources.GetString(Resource.String.auth0_domain),
ClientId = Resources.GetString(Resource.String.auth0_client_id),
Activity = this
});
//preenche o arraylist com os dados
GetEmails();
//cria a instância do spinner declarado no arquivo Main
spinner = FindViewById<Spinner>(Resource.Id.spnDados);
//cria textview
queroreconhecer = FindViewById<TextView>(Resource.Id.txtReconhecer);
crie = FindViewById<TextView>(Resource.Id.txtCrie);
conquiste = FindViewById<TextView>(Resource.Id.txtConquiste);
entregue = FindViewById<TextView>(Resource.Id.txtEntregue);
viva = FindViewById<TextView>(Resource.Id.txtViva);
comentar = FindViewById<TextView>(Resource.Id.txtComentário);
comentário = FindViewById<EditText>(Resource.Id.edtComentario);
rdgcrie = FindViewById<RadioGroup>(Resource.Id.rdgCrie);
rdgconquiste = FindViewById<RadioGroup>(Resource.Id.rdgConquiste);
rdgentregue = FindViewById<RadioGroup>(Resource.Id.rdgEntregue);
rdgviva = FindViewById<RadioGroup>(Resource.Id.rdgViva);
adapter = new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, enderecos);
spinner.Adapter = adapter;
spinner.ItemSelected += Spinner_ItemSelected;
enviar = FindViewById<Button>(Resource.Id.button1);
enviar.Click += enviar_Click;
lista.Add(rdgconquiste);
lista.Add(rdgcrie);
lista.Add(rdgentregue);
lista.Add(rdgviva);
void GetEmails()
{
enderecos = new ArrayList();
enderecos.Add("Escolha um colaborador");
enderecos.Add("alexandre_bonfim@whirlpool.com");
enderecos.Add("alexandre_t_pires@whirlpool.com");
enderecos.Add("ana_carolina_simoes @whirlpool.com");
enderecos.Add("ana_claudia_s_belarmino@whirlpool.com");
enderecos.Add("andre_costa@whirlpool.com");
enderecos.Add("andre_l_teixeira@whirlpool.com");
enderecos.Add("andreza_a_valle@whirlpool.com");
enderecos.Add("anna_carolina_b_ferreira@whirlpool.com");
enderecos.Add("bruno_b_souza@whirlpool.com");
enderecos.Add("bruno_c_castanho@whirlpool.com");
enderecos.Add("bruno_s_lombardero@whirlpool.com");
enderecos.Add("caio_c_sacoman@whirlpool.com");
enderecos.Add("carla_sedin@whirlpool.com");
enderecos.Add("cassia_r_nascimento@whirlpool.com");
enderecos.Add("celia_r_araujo@whirlpool.com");
enderecos.Add("cesar_leandro_de_oliveira@whirlpool.com");
enderecos.Add("daniel_b_szortyka@whirlpool.com");
enderecos.Add("denis_caciatori@whirlpool.com");
enderecos.Add("elisabete_c_ferreira@whirlpool.com");
enderecos.Add("erick_c_senzaki@whirlpool.com");
enderecos.Add("erika_g_souza@whirlpool.com");
enderecos.Add("fabiana_monteiro@whirlpool.com");
enderecos.Add("fernando_v_santos@whirlpool.com");
enderecos.Add("gabriel_roveda@whirlpool.com");
enderecos.Add("herivelto_alves_jr@whirlpool.com");
enderecos.Add("jefferson_s_pecanha@whirlpool.com");
enderecos.Add("josiane_a_teles@whirlpool.com");
enderecos.Add("juliana_g_saito@whirlpool.com");
enderecos.Add("juliano_ventola@whirlpool.com");
enderecos.Add("leonardo_l_costa@whirlpool.com");
enderecos.Add("leonardo_r_silva@whirlpool.com");
enderecos.Add("lucas_m_santos@whirlpool.com");
enderecos.Add("luiz_perea@whirlpool.com");
enderecos.Add("norma_raphaeli@whirlpool.com");
enderecos.Add("patricia_f_prates@whirlpool.com");
enderecos.Add("priscila_l_dattilo@whirlpool.com");
enderecos.Add("priscila_m_konte@whirlpool.com");
enderecos.Add("reider_a_bernucio@whirlpool.com");
enderecos.Add("renato_occhiuto@whirlpool.com");
enderecos.Add("ricardo_a_fernandes@whirlpool.com");
enderecos.Add("ricardo_matos_campaneruti @whirlpool.com");
enderecos.Add("rogerio_pagotto@whirlpool.com");
enderecos.Add("ruben_c_anacleto@whirlpool.com");
enderecos.Add("taise_azevedo@whirlpool.com");
enderecos.Add("vinicius_marques_assis@whirlpool.com");
enderecos.Add("wanderly_t_limeira@whirlpool.com");
}// fim getEmails
void Spinner_ItemSelected(object sender, AdapterView.ItemSelectedEventArgs e)
{
Spinner spinner = (Spinner)sender;
string toast = string.Format("Colaborador selecionado: {0}", spinner.GetItemAtPosition(e.Position));
string welcome = "Bem vindo ao aplicativo de agradecimento";
if (toast.Equals("Escolha um colaborador") )
{
Toast.MakeText(this, welcome, ToastLength.Long).Show();
}
else {
Toast.MakeText(this, toast, ToastLength.Long).Show();
}
}
void showbox(string msg)
{
var progressDialog = ProgressDialog.Show(this, "Mensagem", msg, true);
new System.Threading.Thread(new ThreadStart(delegate
{
//LOAD METHOD TO GET ACCOUNT INFO
RunOnUiThread(() => Toast.MakeText(this, msg, ToastLength.Long).Show());
//HIDE PROGRESS DIALOG
RunOnUiThread(() => progressDialog.Dismiss());
RunOnUiThread(() => progressDialog.Hide());
})).Start();
}
void enviar_Click(object sender, EventArgs e)
{
try
{
RadioButton rdbgrupo1 = FindViewById<RadioButton>(rdgconquiste.CheckedRadioButtonId);
RadioButton rdbgrupo2 = FindViewById<RadioButton>(rdgcrie.CheckedRadioButtonId);
RadioButton rdbgrupo3 = FindViewById<RadioButton>(rdgviva.CheckedRadioButtonId);
RadioButton rdbgrupo4 = FindViewById<RadioButton>(rdgentregue.CheckedRadioButtonId);
int RadioGroupIsChecked(RadioGroup radioGroup)
{
//-1 means empty selection
return radioGroup.CheckedRadioButtonId;
}
//When user doesn't check a radio button, show a Toast
if (RadioGroupIsChecked(rdgconquiste) == -1 & RadioGroupIsChecked(rdgcrie) == -1 & RadioGroupIsChecked(rdgviva) == -1 & RadioGroupIsChecked(rdgentregue) == -1)
{
string excecao = "Ao menos um botão deve ser selecionado e o comentário deve ser preenchido";
Toast.MakeText(this, excecao, ToastLength.Long).Show();
}
else
{
String emailescolhido = spinner.SelectedItem.ToString();
if (emailescolhido == "Escolha um colaborador abaixo")
{
string excecao = "Por favor, escolha um colaborador";
Toast.MakeText(this, excecao, ToastLength.Long).Show();
}
else {
String campocomentario = comentário.Text;
string emailchefe = "acursio_maia@whirlpool.com";
var email = new Intent(Android.Content.Intent.ActionSend);
//send to
email.PutExtra(Android.Content.Intent.ExtraEmail,
new string[] { "" + emailescolhido });
//if (emailescolhido == "andreza_a_valle" || emailescolhido.Equals("lucas_m_santos") || emailescolhido == "erika_g_souza@whirlpool.com" || emailescolhido == "caio_c_sacoman")
//{
// //cc to
// email.PutExtra(Android.Content.Intent.ExtraCc,
// new string[] { "comite_clima_ti@whirlpool.com" + emailchefe });
//}
//cc to
email.PutExtra(Android.Content.Intent.ExtraCc,
new string[] { "comite_clima_ti@whirlpool.com" + emailchefe });
//subject
email.PutExtra(Android.Content.Intent.ExtraSubject, "SABIA QUE VOCÊ FOI RECONHECIDO?");
//content
if (RadioGroupIsChecked(rdgconquiste) != -1 & RadioGroupIsChecked(rdgcrie) != -1 & RadioGroupIsChecked(rdgviva) != -1 & RadioGroupIsChecked(rdgentregue) != -1)
{
email.PutExtra(Android.Content.Intent.ExtraText,
"Você foi reconhecido pelo(s) valor(es) de: " + rdbgrupo1.Text + " , " + rdbgrupo2.Text + " , " + rdbgrupo3.Text + " e " + rdbgrupo4.Text + "" + System.Environment.NewLine + "" + System.Environment.NewLine + campocomentario + System.Environment.NewLine);
}
else if (RadioGroupIsChecked(rdgconquiste) != -1)
{
email.PutExtra(Android.Content.Intent.ExtraText,
"Você foi reconhecido pelo(s) valor(es) de: " + rdbgrupo1.Text + "" + System.Environment.NewLine + "" + System.Environment.NewLine + campocomentario + System.Environment.NewLine);
}
else if (RadioGroupIsChecked(rdgcrie) != -1)
{
email.PutExtra(Android.Content.Intent.ExtraText,
"Você foi reconhecido pelo(s) valor(es) de: " + rdbgrupo2.Text + "" + System.Environment.NewLine + "" + System.Environment.NewLine + campocomentario + System.Environment.NewLine);
}
else if (RadioGroupIsChecked(rdgviva) != -1)
{
email.PutExtra(Android.Content.Intent.ExtraText,
"Você foi reconhecido pelo(s) valor(es) de: " + rdbgrupo3.Text + "" + System.Environment.NewLine + "" + System.Environment.NewLine + campocomentario + System.Environment.NewLine);
}
else if (RadioGroupIsChecked(rdgentregue) != -1)
{
email.PutExtra(Android.Content.Intent.ExtraText,
"Você foi reconhecido pelo(s) valor(es) de: " + rdbgrupo4.Text + "" + System.Environment.NewLine + "" + System.Environment.NewLine + campocomentario + System.Environment.NewLine);
}
else if (RadioGroupIsChecked(rdgconquiste) != -1 & RadioGroupIsChecked(rdgcrie) != -1)
{
email.PutExtra(Android.Content.Intent.ExtraText,
"Você foi reconhecido pelo(s) valor(es) de: " + rdbgrupo1.Text + " , " + rdbgrupo2.Text + "" + System.Environment.NewLine + "" + System.Environment.NewLine + campocomentario + System.Environment.NewLine);
}
else if (RadioGroupIsChecked(rdgconquiste) != -1 & RadioGroupIsChecked(rdgentregue) != -1)
{
email.PutExtra(Android.Content.Intent.ExtraText,
"Você foi reconhecido pelo(s) valor(es) de: " + rdbgrupo1.Text + " , " + rdbgrupo4.Text + "" + System.Environment.NewLine + "" + System.Environment.NewLine + campocomentario + System.Environment.NewLine);
}
else if (RadioGroupIsChecked(rdgcrie) != -1 & RadioGroupIsChecked(rdgviva) != -1)
{
email.PutExtra(Android.Content.Intent.ExtraText,
"Você foi reconhecido pelo(s) valor(es) de: " + rdbgrupo2.Text + " , " + rdbgrupo3.Text + "" + System.Environment.NewLine + "" + System.Environment.NewLine + campocomentario + System.Environment.NewLine);
}
else if (RadioGroupIsChecked(rdgcrie) != -1 & RadioGroupIsChecked(rdgentregue) != -1)
{
email.PutExtra(Android.Content.Intent.ExtraText,
"Você foi reconhecido pelo(s) valor(es) de: " + rdbgrupo2.Text + " , " + rdbgrupo4.Text + "" + System.Environment.NewLine + "" + System.Environment.NewLine + campocomentario + System.Environment.NewLine);
}
else if (RadioGroupIsChecked(rdgviva) != -1 & RadioGroupIsChecked(rdgentregue) != -1)
{
email.PutExtra(Android.Content.Intent.ExtraText,
"Você foi reconhecido pelo(s) valor(es) de: " + rdbgrupo3.Text + " , " + rdbgrupo4.Text + "" + System.Environment.NewLine + "" + System.Environment.NewLine + campocomentario + System.Environment.NewLine);
}
else if (RadioGroupIsChecked(rdgconquiste) != -1 & RadioGroupIsChecked(rdgcrie) != -1 & RadioGroupIsChecked(rdgviva) != -1)
{
email.PutExtra(Android.Content.Intent.ExtraText,
"Você foi reconhecido pelo(s) valor(es) de: " +rdbgrupo1.Text + " , " + rdbgrupo2.Text + " e " + rdbgrupo3.Text + "" + System.Environment.NewLine + "" + System.Environment.NewLine + campocomentario + System.Environment.NewLine);
}
else if (RadioGroupIsChecked(rdgconquiste) != -1 & RadioGroupIsChecked(rdgcrie) != -1 & RadioGroupIsChecked(rdgentregue) != -1)
{
email.PutExtra(Android.Content.Intent.ExtraText,
"Você foi reconhecido pelo(s) valor(es) de: " + rdbgrupo1.Text + " , " + rdbgrupo2.Text + " e " + rdbgrupo4.Text + "" + System.Environment.NewLine + "" + System.Environment.NewLine + campocomentario + System.Environment.NewLine);
}
else if (RadioGroupIsChecked(rdgconquiste) != -1 & RadioGroupIsChecked(rdgviva) != -1 & RadioGroupIsChecked(rdgviva) != -1)
{
email.PutExtra(Android.Content.Intent.ExtraText,
"Você foi reconhecido pelo(s) valor(es) de: " + rdbgrupo1.Text + " , " + rdbgrupo3.Text + " e " + rdbgrupo3.Text + "" + System.Environment.NewLine + "" + System.Environment.NewLine + campocomentario + System.Environment.NewLine);
}
else if (RadioGroupIsChecked(rdgcrie) != -1 & RadioGroupIsChecked(rdgviva) != -1 & RadioGroupIsChecked(rdgentregue) != -1)
{
email.PutExtra(Android.Content.Intent.ExtraText,
"Você foi reconhecido pelo(s) valor(es) de: " + rdbgrupo2.Text + " , " + rdbgrupo3.Text + " e " + rdbgrupo4.Text + "" + System.Environment.NewLine + "" + System.Environment.NewLine + campocomentario + System.Environment.NewLine);
}
email.SetType("message/rfc822");
StartActivity(email);
Android.App.AlertDialog.Builder alertdialog = new Android.App.AlertDialog.Builder(this);
alertdialog.SetTitle("Confirmação de envio");
alertdialog.SetMessage("Email enviado com sucesso");
alertdialog.SetNeutralButton("Ok", delegate {
alertdialog.Dispose();
});
alertdialog.Show();
}
}
}
catch (Java.Lang.Exception ex)
{
showbox(ex.Message);
} } }
}
}
,我也会收到错误信息,即部分数量无效。
答案 0 :(得分:1)
在 pbasdf的建议中,我实现了didChange sectionInfo
NSFetchedResultsController委托方法。 Apple's boilerplate on their site在Objective-C中,但这是翻译的Swift版本:
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
switch type {
case .insert:
tableView.insertSections([sectionIndex], with: .fade)
break
case .delete:
tableView.deleteSections([sectionIndex], with: .fade)
default:
break
}
}