#ios #swift
#iOS #swift
Вопрос:
У меня есть UIViewController с некоторыми метками и UICollectionView. UICollectionView представляет собой самодельный календарь, загруженный из xib. Когда я нажимаю на одну из ячеек представления коллекции (скажем, выбираю день в календаре), я соответствующим образом меняю свою базовую модель, и мне нужно обновить метки. Но при нажатии ничего не обновляется.
У меня есть метод, который обновляет метки и вызывает его в viewDidLoad(). После первой загрузки все метки становятся нулевыми, и объявление меток как ‘var’, а не как ‘weak var’ не помогает. При вызове некоторых функций в ViewController self.view, таких как layoutSubviews(), ярлыки, похоже, существуют, вызываются viewDidLoad() (и updateLabels()), но на экране ничего не меняется. Я попытался создать (подкласс) UIView с метками, используя xib и программно, разместил метки непосредственно в ViewController, поместив весь код в одно место — тот же результат. setNeedsDisplay(), методы жизненного цикла, удаление-добавление в superview — ничего из этого не сработало для меня. Я делаю что-то не так или упускаю что-то важное?
class ChallengeViewController: UIViewController {
var challenge = Challenge(title: Challenge.sampleTitle, startDate: Challenge.sampleStartDate, durationInDays: 40, checkIns: [Bool](repeating: true, count: 40), cheatDaysPlanned: 2, isActive: true, roundNumber: 1, pointsScored: 0)
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var calendarView: CalendarView!
@IBOutlet weak var statisticsView: ChallengeStatisticsView!
//contains labels that should be updated
override func viewDidLoad() {
super.viewDidLoad()
calendarView.challenge = challenge
calendarView.updateMonthAndYearLabels(for: challenge)
statisticsView.updateLabels()
titleLabel.text = challenge.title
}
}
class CalendarView: UIView {
var challenge: Challenge?
//other code here
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "calendarCell", for: indexPath) as! CalendarCollectionViewCell
collectionView.performBatchUpdates({
if let challenge = challenge {
cell.update(challenge: challenge)
let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ChallengeScreenViewController") as! ChallengeViewController
viewController.view.layoutSubviews()
viewController.challenge = challenge
viewController.updateLabels()
collectionView.reloadItems(at: [indexPath])
}
}, completion: nil)
}
}
Ответ №1:
Вы создаете совершенно новый контроллер представления в своем cell.update
, и он никогда не отображается на экране, поэтому вы не видите никаких обновлений. Не уверен, что ваш update
метод на самом деле делает в любом случае, но похоже, что просто вызов self.updateLabels()
или self.statisticsView.updateLabels()
должен сделать трюк. Не уверен, что, поскольку у вас, похоже, есть оба.
Комментарии:
1. Большое вам спасибо! Это очень помогло.
Ответ №2:
Почему вы перезагружаете свой VC?
Когда вы нажимаете на CollectionViewCell, создайте протокол делегирования, чтобы сообщить VC перезагрузить метки с помощью datamodel.
Ответ №3:
- Используйте
cellForItem(at:)
метод для получения выбранной ячейки - Чтобы обновить представление в текущем контроллере представления, просто вызовите метод update . Не создавайте новый контроллер представления.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! CalendarCollectionViewCell
if let challenge = challenge {
cell.update(challenge: challenge)
collectionView.reloadItems(at: [indexPath])
self.updateLabels()
}
}
Ответ №4:
Я не знал, что UIStoryboard(name:, bundle:).instantiateViewController(withIdentifier:)
это создает совершенно новый vc, это была главная ошибка. Итак, я решил использовать Центр уведомлений, чтобы заставить контроллер реагировать на изменения в модели. Теперь все работает.
class CalendarView: UIView {
var challenge: Challenge?
//other code here
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "calendarCell", for: indexPath) as! CalendarCollectionViewCell
collectionView.performBatchUpdates({
if let challenge = challenge {
cell.update(challenge: challenge)
// assigning a new value to calendarView's own variable, posting the notification
self.challenge = challenge
let name = Notification.Name("CellTapped")
NotificationCenter.default.post(name: name, object: nil)
collectionView.reloadItems(at: [indexPath])
}
}, completion: nil)
}
}
class ChallengeViewController: UIViewController {
var challenge = Challenge(title: Challenge.sampleTitle, startDate: Challenge.sampleStartDate, durationInDays: 40, checkIns: [Bool](repeating: true, count: 40), cheatDaysPlanned: 2, isActive: true, roundNumber: 1, pointsScored: 0)
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var calendarView: CalendarView!
@IBOutlet weak var statisticsView: ChallengeStatisticsView!
// taking the changed variable from calendarView when the notification is posted
@objc func updateAfterTap() {
if let calendarViewChallenge = calendarView.challenge {
self.challenge = calendarViewChallenge
statisticsView.updateLabels()
}
}
override func viewDidLoad() {
super.viewDidLoad()
calendarView.challenge = challenge
calendarView.updateMonthAndYearLabels(for: challenge)
statisticsView.updateLabels()
titleLabel.text = challenge.title
NotificationCenter.default.addObserver(self, selector: #selector(self.updateAfterTap), name: Notification.Name("CellTapped"), object: nil)
}
}