#ios #swift
#iOS #swift
Вопрос:
Я новичок в разработке ios и изучаю основные данные и застрял в обновлении ячеек tableview с помощью reloaddata(). Вот код в моем GoalsVC:
import UIKit
import CoreData
//make app delegate accessible for all view controllers as in has core data things
let appDelegate = UIApplication.shared.delegate as? AppDelegate
class GoalsVC: UIViewController {
@IBOutlet weak var tableView: UITableView!
var goals: [Goal] = []
override func viewDidLoad() {
super.viewDidLoad()
//set tableview delegate and source so that it knows what its delegate its datasource is from otherwise it does not know where its getting information from
tableView.delegate = self
tableView.dataSource = self
tableView.isHidden = false
}
//need to think about when should we fetch the data. viewdidlaod only called once when the view is originally load. after we presented goalvc, creategoalvc on the top and dismiss them, viewdidload is not called bcs were just presenting a view on top of it and dismissing it.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.fetch { (complete) in
if complete {
if goals.count >= 1 {
//showing tableview or hide them depending if data is available or not
tableView.isHidden = false
} else {
tableView.isHidden = true
}
}
}
self.tableView.reloadData()
}
Я не знаю, почему self.tableView.reloadData()
в конце не будет обновляться tableview.
Вот код, который я сделал для сохранения данных в FinishGoalVC, если это поможет получить более четкое представление:
func save(completion: (_ finished: Bool) -> ()) {
guard let managedContext = appDelegate?.persistentContainer.viewContext else {
return
}
//accessing core data properties
let goal = Goal(context: managedContext)
goal.goalDescription = goalDescription
goal.goalType = goalType.rawValue
goal.goalCompletionValue = Int32(pointsTextField.text!)!
goal.goalProgress = Int32(0)
//using save in order to commit unsaved changes to the context parents store
do {
try managedContext.save()
completion(true)
} catch {
debugPrint("Could not save (error.localizedDescription)")
completion(false)
}
}
Комментарии:
1. Обработчик завершения в
save
бессмыслен, потому что весь код синхронен. И я думаю, что так и естьfetch
. Метод с параметром вместо обработчика завершения решил бы проблему.2. Использовать developer.apple.com/documentation/coredata/…
Ответ №1:
Обновите tableview после завершения выборки. if goals.count >= 1
использование !goals.isEmpty
— хорошая практика.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.fetch { complete in
if complete {
tableView.isHidden = goals.isEmpty
if !goals.isEmpty {
//showing tableview or hide them depending if data is available or not
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
}
Комментарии:
1. Спасибо за ввод и полезный совет! 🙂
Ответ №2:
Просто отредактируйте свою функцию, как показано ниже;
if goals.count >= 1 {
//showing tableview or hide them depending if data is available or not
tableView.isHidden = false
} else {
tableView.isHidden = true
self.tableView.reloadData()
}
Потому что ваша функция перезагрузки работает до получения данных из-за потоков. Вы должны запустить это после извлечения данных.
Комментарии:
1. Спасибо за предложение! 🙂
Ответ №3:
Итак, я только что понял, почему он не показывает обновленный tableview. Я просто помещу это здесь на случай, если кто-то столкнется с подобными проблемами в будущем (?), лол.
Так что да, в любом случае,
- Я ввел точки останова для TableView.reloadData() и проверил отладчик и увидел, что у него есть данные, и он вызвал метод reloadData(), когда я закончил создавать цели. Итак, никаких проблем с reloadData()
- Однако самость.вызов выборки в функции viewWillAppear не был запущен после того, как я закончил создавать новые цели. Он запускался только при запуске приложения и получении уже созданных целей.
Прежде чем двигаться дальше, вот начальный код, который я использовал для расширения UIViewController под названием presentDetail:
расширение UIViewController {
func presentDetail(_ viewControllerToPresent: UIViewController) {
let transition = CATransition()
transition.duration = 0.3
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromRight
self.view.window?.layer.add(transition, forKey: kCATransition)
present(viewControllerToPresent, animated: false, completion: nil)
}
и это расширение использовалось для кнопки addGoal, которая представляет следующий VC, createGoalVC:
@IBAction func addGoalBtnWasPressed(_ sender: Any) {
guard let createGoalVC = storyboard?.instantiateViewController(identifier:
"CreateGoalVC") else {
return
}
presentDetail(createGoalVC)
}
}
У меня также было другое расширение для UIViewController, которое было:
func presentSecondaryDetail(_ viewControllerToPresent: UIViewController) {
let transition = CATransition()
transition.duration = 0.3
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromRight
guard let presentedViewController = presentedViewController else {return}
presentedViewController.dismiss(animated: false) {
self.view.window?.layer.add(transition, forKey: kCATransition)
self.present(viewControllerToPresent, animated: false, completion:
nil)
}
}
эта функция использовалась для nextButton, которая представляет окончательный VC, finishGoalVC:
@IBAction func nextBtnWasPressed(_ sender: Any) {
if goalTextView.text != "" amp;amp; goalTextView.text != "What is your goal?" {
guard let finishGoalVC =
storyboard?.instantiateViewController(identifier: "FinishGoalVC") as?
FinishGoalVC else {
return
}
finishGoalVC.initData(description: goalTextView.text!, type: goalType)
presentingViewController?.presentSecondaryDetail(finishGoalVC)
}
}
И поскольку мой первый VC (GoalsVC) не был представлен в полноэкранном режиме, createGoalsVC и finishGoalsVC не были должным образом отклонены, поскольку GoalsVC не охватывал два других контроллера представления. Если это имеет какой-то смысл. Следовательно, почему функция viewWillAppear вызывалась только один раз, а не после создания новых целей.
Таким образом, окончательный код для функции presentDetail расширения UIViewController был изменен на:
расширение UIViewController {
func presentDetail(_ viewControllerToPresent: UIViewController) {
let transition = CATransition()
transition.duration = 0.3
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromRight
self.view.window?.layer.add(transition, forKey: kCATransition)
let navigationController: UINavigationController =
UINavigationController(rootViewController: viewControllerToPresent)
navigationController.modalPresentationStyle = .fullScreen
present(navigationController, animated: false, completion: nil)
}
и для функции presentSecondaryDetail:
func presentSecondaryDetail(_ viewControllerToPresent: UIViewController) {
let transition = CATransition()
transition.duration = 0.3
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromRight
guard let presentedViewController = presentedViewController else { return }
presentedViewController.dismiss(animated: false) {
self.view.window?.layer.add(transition, forKey: kCATransition)
let navigationController: UINavigationController =
UINavigationController(rootViewController: viewControllerToPresent)
navigationController.modalPresentationStyle = .fullScreen
self.present(navigationController, animated: false, completion: nil)
}
}
И это решило проблему! Tableview был обновлен с учетом новых целей пользователя 🙂