Как сохранить данные в CoreData в одном контроллере представления, а затем иметь представление таблицы, отображающее данные в другом контроллере представления? - PullRequest
0 голосов
/ 06 июня 2019

Прежде всего, я очень новичок в быстром программировании и мне очень неясно во многих вещах, и поэтому я следую инструкциям, чтобы убедиться, что мое приложение может работать.

По сути, я следовал руководству в(https://www.brianadvent.com/build-simple-core-data-driven-ios-app/) для создания простого iOS-приложения, основанного на основных данных. Я точно следовал коду и он работает. Однако мне пришлось внести дополнительные улучшения в приложение, и именно здесь возникла проблема.

По сути, в этом руководстве загрузка элементов в базовые данные и просмотр таблицы выполняются в одном контроллере представления. В моем новом приложении мне бы хотелось, чтобы пользователь вводил строки, которые будут сохраняться в основных данных.таким же образом, и отображение таблицы в виде введенных данных на другом контроллере представления. Я быстро понял, что нельзя вызывать переменные и функции из разных контроллеров представления, поэтому я решил, что создание новых переменных и moc во втором контроллере представления не должно быть большой проблемой.

Это то, что я пробовал до сих пор. Я сохранил всеВ коде, потому что я боюсь, что это может быть ошибка.

Первый контроллер представления (где данные хранятся в основных данных:

import UIKit
import CoreData

class ViewController: UIViewController {
    //name of entity = Alarm
    var alarmItems = [Alarm]() // array of alarm items called     alarmItems
    var moc: NSManagedObjectContext!
    let appDelegate = UIApplication.shared.delegate as? AppDelegate


    @IBOutlet weak var engineerName: UITextField!

    @IBOutlet weak var dateTimeOfAlarm: UITextField!

    @IBOutlet weak var trueFalseAlarmSelector: UISwitch!

    @IBOutlet weak var engineerComments: UITextField!

    //saving alarm attributes into coredata
    @IBOutlet weak var submitButton: UIStackView!

    override func viewDidLoad() {
        super.viewDidLoad()
        engineerName.delegate = (self as UITextFieldDelegate)
        dateTimeOfAlarm.delegate = (self as UITextFieldDelegate)
        //trueFalseAlarmSelector.delegate = self
        moc = appDelegate?.persistentContainer.viewContext
        // Do any additional setup after loading the view.
        loadData()
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?){
        engineerName.resignFirstResponder()
        dateTimeOfAlarm.resignFirstResponder()
    }

    @IBAction func dateTimeOfAlarmEdit(_ sender: UITextField) {
        let datePickerView = UIDatePicker()
        datePickerView.datePickerMode = .dateAndTime
        sender.inputView = datePickerView
        datePickerView.addTarget(self, action:     #selector(handleDatePicker(sender:)), for: .valueChanged)
    }

    @objc func handleDatePicker(sender: UIDatePicker) {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "dd MMM yyyy HH:mm"
        dateTimeOfAlarm.text = dateFormatter.string(from: sender.date)
    }

    //sending the attributes to the coredata
    @IBAction func submitAlarmAttributes(_ sender: UIButton) {
        let alarmItem = Alarm(context: moc)

        //true/false button checker
        if trueFalseAlarmSelector.isOn {
            alarmItem.trueOrFalseAlarm = true
        } else {
            alarmItem.trueOrFalseAlarm = false
        }

        alarmItem.nameOfEngineer = engineerName.text
        alarmItem.dateTimeOfAlarm = dateTimeOfAlarm.text
        alarmItem.engineerComments = engineerComments.text

        appDelegate?.saveContext()
        loadData()
    }

    //loadData will update the alarmItems array with the new and most current data from the database.
    func loadData(){
        let alarmRequest:NSFetchRequest<Alarm> = Alarm.fetchRequest()
        let sortDescriptor = NSSortDescriptor(key: "dateTimeOfAlarm", ascending: false)
        alarmRequest.sortDescriptors = [sortDescriptor]

        do{try alarmItems=moc.fetch(alarmRequest)

        } catch {
            print("Could not load data")
        }

        //self.tableView.reloadData()

    }
}

extension ViewController : UITextFieldDelegate {
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
}

Второй viewController (гденаходится tableview):

import UIKit
import CoreData


class SecondViewController: UIViewController, UITableViewDataSource {

    var alarmItems = [Alarm]()
    var moc: NSManagedObjectContext!
    let appDelegate = UIApplication.shared.delegate as? AppDelegate


    @IBOutlet weak var historyTable: UITableView!

    @IBOutlet weak var uploadJson: UIButton!

    @IBOutlet weak var refreshTable: UIButton!


    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.dataSource = self

        func refreshButtonClick(_ sender: UIButton) {
            loadData()
        }

        func loadData(){
            let alarmRequest:NSFetchRequest<Alarm> = Alarm.fetchRequest()
            let sortDescriptor = NSSortDescriptor(key: "dateTimeOfAlarm", ascending: false)
            alarmRequest.sortDescriptors = [sortDescriptor]

            do{try alarmItems=moc.fetch(alarmRequest)

            } catch {
                print("Could not load data")
            }
            //self.tableView.reloadData()

        }

        func numberOfSections (in tableView: UITableView) -> Int {
            return 1
        }

        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return alarmItems.count
        }
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

            let alarmItem = alarmItems[indexPath.row]

            let alarmDate = alarmItem.dateTimeOfAlarm as String?
            cell.detailTextLabel?.text = alarmDate

            let alarmEngineerName = alarmItem.nameOfEngineer as String?
            cell.detailTextLabel?.text = alarmEngineerName

            let alarmTrueFalse = alarmItem.trueOrFalseAlarm as Bool?
            let alarmTrueFalseString = alarmTrueFalse?.description
            cell.detailTextLabel?.text = alarmTrueFalseString

            let alarmEngineerComments = alarmItem.engineerComments as String?
            cell.detailTextLabel?.text = alarmEngineerComments
        }
        return cell
    }

}

Первый контроллер представления не имеет никаких сообщений об ошибках.

Однако второй контроллер представления имеет много проблем.Например, в самом начале есть эта ошибка. Тип 'SecondViewController' не соответствует протоколу 'UITableViewDataSource' ". В некоторых строках есть несколько сообщений об ошибках, в которых говорится" Заменитель редактора в исходном файле ". Также имеется"У значения типа 'SecondViewController' нет члена 'tableView' 'ошибка, даже если у меня есть tableView, и, наконец, в конце есть "Использование неразрешенного идентификатора' cell '".

Большое спасибоЗа последние несколько дней я пытался разобраться в этой проблеме, и я действительно не знаю, что еще можно сделать.

1 Ответ

0 голосов
/ 06 июня 2019

Я подозреваю, что вы сделали копирование / вставку в InterfaceBuilder для создания вашего SecondViewController.

Исходный код, который вы использовали, имел переменную с именем tableView, на которую все еще ссылается InterfaceBuilder. Чтобы это исправить, откройте InterfaceBuilder и найдите свой SecondViewController. Если он еще не раскрыт, разверните объекты сцены и выберите свой SecondViewController, а затем с помощью инспектора справа отобразите «Инспектор соединений». Скорее всего, вы найдете розетку tableView с восклицательным знаком и другую розетку с именем historyTable. Просто удалите ссылку tableView и убедитесь, что ваша historyTable правильно связана.

Что касается «неразрешенной ячейки идентификатора», то это потому, что вы не поместили закрывающую скобку своей функции viewDidLoad. Поскольку ваша функция не закрыта, все остальные функции после этого создаются как локальные функции viewDidLoad вместо функций вашего SecondViewController. Чтобы исправить ваш источник, просто удалите скобку, которая находится чуть выше return cell, и добавьте ее просто self.historyTable.dataSource = self (Да, в настоящее время она имеет значение self.tableView.dataSource, но ваша переменная называется historyTable).

...