滚动 UITableView 时,NSManagedObject 数组变为 nil

NSManagedObject Array becomes nil when UITableView is scrolled

我的应用程序中有一个 ViewController,我必须在其中向用户显示设置,用户可以使用 UISwitch 打开或关闭设置。我必须将设置存储在本地数据库中,并根据该显示数据在应用程序中向用户显示数据。

我正在使用 SugarRecord 进行核心数据管理。最初所有的设置都是打开的。

SugarRecordManager.swift

import Foundation
import SugarRecord
import CoreData


class SugarRecordManager
{
static let sharedInstance = SugarRecordManager()
private init(){

}

// Initializing CoreDataDefaultStorage
func coreDataStorage() -> CoreDataDefaultStorage {
    let store = CoreDataStore.named("db")
    let bundle = Bundle(for: type(of: self))
    let model = CoreDataObjectModel.merged([bundle])
    let defaultStorage = try! CoreDataDefaultStorage(store: store, model: model)
    return defaultStorage
}

//MARK:- User Settings methods

//update local settings
func updateSettingsModel(userSettings: [UserSetting]){
    let db = self.coreDataStorage()
    for localSetting in userSettings{
        try! db.operation { (context, save) -> Void in
            if let settingObjectToUpdate = try! context.request(UserSetting.self).filtered(with: "groupName", equalTo: localSetting.groupName!).fetch().first{
                settingObjectToUpdate.groupId = localSetting.groupId! as String
                settingObjectToUpdate.groupName = localSetting.groupName! as String
                settingObjectToUpdate.isGroupActive = localSetting.isGroupActive
                try! context.insert(settingObjectToUpdate)
                save()

            }
        }
    }
}

//retrieve settings from storage
func getAllSettings() -> [UserSetting] {
    let db = self.coreDataStorage()
    var userSettings : [UserSetting]
    do {
        userSettings = try db.fetch(FetchRequest<UserSetting>())
    } catch {
        userSettings = []
    }
    return userSettings
}

//initialise settings for the first time
func initialiseUserSettings(){
    let db = self.coreDataStorage()
    var groupNameArray = UserDefaults.standard.value(forKey: "groupNamesArrayKey") as? [String]
    var groupIdArray = UserDefaults.standard.value(forKey: "groupIdsArrayKey") as? [String]
    for i in 0 ..< groupIdArray!.count  {
        try! db.operation { (context, save) -> Void in
            let settingObject: UserSetting = try! context.new()
            settingObject.groupId = groupIdArray?[i];
            settingObject.groupName = groupNameArray?[i];
            settingObject.isGroupActive = true;
            try! context.insert(settingObject)
            save()
        }
    }
}
}

SettingsViewController.swift

class SettingsViewController: BaseViewController, UITableViewDataSource, UITableViewDelegate, SettingsCellDelegate {

@IBOutlet weak var btnSideNav: UIBarButtonItem!

@IBOutlet weak var settingsTable: UITableView!

var userSetting = [UserSetting]() //array to hold settings from storage

override func viewDidLoad() {
    super.viewDidLoad()
    self.automaticallyAdjustsScrollViewInsets = false;
    btnSideNav.target = revealViewController();
    btnSideNav.action = #selector(SWRevealViewController.revealToggle(_:));
    userSetting = SugarRecordManager.sharedInstance.getAllSettings() //here userSetting contains data and I have checked it
    self.settingsTable.reloadData()
    self.settingsTable.dataSource = self;
    self.settingsTable.delegate = self;
    // Do any additional setup after loading the view.
}

//MARK:- Table View Methods

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    print("Count of cells = \(self.userSetting.count)") //prints 18 which is good
    return self.userSetting.count
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 60;
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let settingsCell : SettingsCell? = tableView.dequeueReusableCell(withIdentifier: "SettingsCell") as? SettingsCell;
    settingsCell?.setUpWithModel(model: self.userSetting[indexPath.row], cell: settingsCell!)
    settingsCell?.delegate = self as SettingsCellDelegate;
    return settingsCell!
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: true)
}


func didTappedSwitch(cell: SettingsCell) {
    let indexPath = settingsTable.indexPath(for: cell);
    userSetting[(indexPath?.row)!].isGroupActive? = cell.isGroupActive.isOn as NSNumber
}

@IBAction func btnSaveTapped(_ sender: UIButton) {
    // code to save settings
}
}

SettingsCell.swift

protocol SettingsCellDelegate {
func didTappedSwitch(cell: SettingsCell)
}

class SettingsCell: UITableViewCell {

@IBOutlet weak var groupName: UILabel!

@IBOutlet weak var lblGroupId: UILabel!
@IBOutlet weak var isGroupActive: UISwitch!
var delegate: SettingsCellDelegate!
override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code
}

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
}

func setUpWithModel(model: UserSetting, cell: SettingsCell)
{
    cell.groupName.text = model.groupName;
    cell.lblGroupId.text = model.groupId;
    isGroupActive.setOn((model.isGroupActive?.boolValue)!, animated: false)
}


@IBAction func isGroupActiveValueChanged(_ sender: UISwitch) {
    delegate.didTappedSwitch(cell: self)

}

}

现在,最初填充了 TableView,所有数组都工作正常,但是一旦我滚动 TableView,所有数据都消失了。甚至 userSetting 数组也是空的。我知道这与上下文有关,但无法弄清楚是什么。任何帮助将不胜感激。

像这样改变你的func coreDataStorage() -> CoreDataDefaultStorage

// Initializing CoreDataDefaultStorage
    lazy var coreDataStorage: CoreDataDefaultStorage = {
        let store = CoreDataStore.named("db")
        let bundle = Bundle(for: type(of: self))
        let model = CoreDataObjectModel.merged([bundle])
        let defaultStorage = try! CoreDataDefaultStorage(store: store, model: model)
        return defaultStorage
    }()

你有这个问题是因为你每次做任何请求时都重新初始化CoreDataDefaultStorage

完成后 lazy - 您将只有一个 CoreDataDefaultStorage 整个应用生命周期

基本上把coreDataStorage改成singleton

就好了