#swift #uiviewcontroller #segue #instantiation #uistoryboardsegue
#swift #uiviewcontroller #segue #создание экземпляра #uistoryboardsegue
Вопрос:
Я продолжаю получать фатальную ошибку, в которой говорится, как значение было развернуто, и оно было равно нулю, и я не понимаю, как. Когда я создаю экземпляр контроллера представления с определенными переменными, все они отображаются, но когда я выполняю переход к точному VC, значения не отображаются.
Возьмем, к примеру, эти функции…
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if let displayVC = storyboard?.instantiateViewController(withIdentifier: Constants.Storyboards.TeachStoryboardID) as? SchoolEventDetailsViewController {
displayVC.selectedEventName = events[indexPath.row].eventName
displayVC.selectedEventDate = documentsDate[indexPath.row].eventDate
displayVC.selectedEventCost = documentsCost[indexPath.row].eventCost
displayVC.selectedEventGrade = documentsGrade[indexPath.row].eventGrade
displayVC.selectedEventDocID = documentsID[indexPath.row]?.docID
navigationController?.pushViewController(displayVC, animated: true)
}
}
Это в сочетании с этой функцией :
func verifyInstantiation() {
if let dateToLoad = selectedEventDate {
dateEditableTextF.text = dateToLoad
}
if let costToLoad = selectedEventCost {
costEditableTextF.text = costToLoad
}
if let gradesToLoad = selectedEventGrade {
gradesEditableTextF.text = gradesToLoad
}
if let docIDtoLoad = selectedEventDocID {
docIDUneditableTextF.text = docIDtoLoad
}
if let eventNameToLoad = selectedEventName {
eventNameEditableTextF.text = eventNameToLoad
}
}
Отлично загружает данные, но когда я пытаюсь выполнить переход из контроллера поиска, данных там нет.
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = selectedEventName
Я установил в названии vc имя события, а также недавно добавил текстовое поле для его хранения в экспериментальных целях (этот вопрос).
Теперь проблема в том, что я хочу выполнить передачу данных из поискового контроллера Algolia в этот VC, и у меня появились все остальные поля, кроме одного, и это был идентификатор документа. Итак, я создал функцию обработчика завершения, чтобы получить идентификатор документа в виде строки и вставить его в vc при выполнении перехода, точно так же, как это происходит при создании экземпляра vc.
Вот функция :
func getTheEventDocID(completion: @escaping ((String?) -> ())) {
documentListener = db.collection(Constants.Firebase.schoolCollectionName).whereField("event_name", isEqualTo: selectedEventName ?? navigationItem.title).addSnapshotListener(includeMetadataChanges: true) { (querySnapshot, error) in
if let error = error {
print("There was an error fetching the documents: (error)")
} else {
self.documentsID = querySnapshot!.documents.map { document in
return EventDocID(docID: (document.documentID) as! String)
}
let fixedID = "(self.documentsID)"
let substrings = fixedID.dropFirst(22).dropLast(3)
let realString = String(substrings)
completion(realString)
}
}
}
Я думал, что либо selectedEventName
или navigationItem.title
выполнит работу и предоставит значение, когда я использую функцию в функции передачи данных, которую я сейчас покажу :
//MARK: - Data Transfer From Algolia Search to School Event Details
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
otherVC.getTheEventDocID { (eventdocid) in
if let id = eventdocid {
if segue.identifier == Constants.Segues.fromSearchToSchoolEventDetails {
let vc = segue.destination as! SchoolEventDetailsViewController
vc.selectedEventName = self.nameTheEvent
vc.selectedEventDate = self.dateTheEvent
vc.selectedEventCost = self.costTheEvent
vc.selectedEventGrade = self.gradeTheEvent
vc.selectedEventDocID = id
}
}
}
}
Но в итоге ничего не отображается при нажатии на результат поиска, что довольно огорчительно, я не могу понять, почему они оба являются пустыми значениями, когда я объявил их в SchoolEventDetailsVC
. Я попытался принудительно развернуть selectedEventName
, и он вылетает, говоря, что есть нулевое значение, и я не могу понять, почему. На самом деле в этом вопросе гораздо больше, но я просто постарался сделать его коротким, чтобы люди действительно попытались прочитать его и помочь, поскольку никто никогда не читает вопросы, которые я публикую, так что да, заранее спасибо.
Комментарии:
1. Что
getTheEventDocID
делать? Если он работает асинхронно, возможно, код выполняется слишком поздно.2.
getTheEventDocID
Получает идентификатор документа события, сгенерированный Firebase в виде строки. Он работает асинхронно, есть ли способ предотвратить выполнение кода слишком поздно? @AndreasOetjen
Ответ №1:
Я немного смущен тем, что otherVC
это такое, которое устанавливает само свойство в getTheEventDocID
, в то время как в замыкании вы устанавливаете свойства self
, которые являются другим контроллером. Но ничего, я надеюсь, вы знаете, что делаете.
Поскольку getTheEventDocID
выполняется асинхронно, представление будет загружено и отображено до того, как будут доступны данные. Поэтому viewDidLoad
не видит фактические данные, но что-то, что скоро устареет.
Итак, вам нужно сообщить контроллеру представления сведений о том, что доступны новые данные, и обновить его пользовательский интерфейс. Что-то вроде
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
otherVC.getTheEventDocID { (eventdocid) in
if let id = eventdocid {
if segue.identifier == Constants.Segues.fromSearchToSchoolEventDetails {
let vc = segue.destination as! SchoolEventDetailsViewController
vc.selectedEventName = self.nameTheEvent
vc.selectedEventDate = self.dateTheEvent
vc.selectedEventCost = self.costTheEvent
vc.selectedEventGrade = self.gradeTheEvent
vc.selectedEventDocID = id
vc.updateUI()
}
}
}
}
и в контроллере представления назначения:
class SchoolEventDetailsViewController ... {
override func viewDidLoad() {
super.viewDidLoad()
updateUI()
}
func updateUI () {
navigationItem.title = selectedEventName
// and so on
}
}
Комментарии:
1. Это
otherVC
vc, который извлекает детали события при создании экземпляра, я не смог вызватьgetTheEventDocID
в текущем tableVC, потому что в этом vc нет сохраненной информации, но я попробую это сделать. @Andreas Oetjen2. Да, он по-прежнему вылетает с нулевой ошибкой. @Andreas Oetjen
3. что, если я помещу это в viewWillAppear? будет ли это иметь значение? @Andreas Oetjen
4. Но где именно происходит сбой? В updateUI() или раньше? Что такое стек вызовов?
Ответ №2:
Хорошо, поэтому я решил попробовать обходной путь и полностью отказался от getTheEventDocID()
метода, потому что это просто вызывало у меня стресс. Поэтому я решил отказаться от идентификаторов документов, сгенерированных Firebase, и просто использовать 10-значные идентификаторы, сгенерированные из функции, которую я создал. Я также выяснил, как добавить этот точно такой же 10-значный идентификатор в запись Algolia, просто сохранив случайный 10-значный идентификатор в переменной и используя его в обоих местах. Итак, теперь вместо того, чтобы использовать вызов запроса для получения идентификатора документа, сгенерированного Firebase, и каждый раз, когда я нажимаю на результат поиска, мое приложение зависает, я в основном отредактировал Struct
запись Algolia и просто добавил eventDocID
свойство, с которым можно использовать hits.hitSource(at: indexPath.row).eventDocID
.
И теперь точно так же, как я добавил другие поля в vc с помощью segue data transfer, теперь я могу сделать то же самое с моим идентификатором документа, потому что все совпадает :).