При попытке изменить sh indexPath.row в методе cellForRowAt возвращает неправильное значение - PullRequest
0 голосов
/ 10 января 2020

Я стажер iOS Разработчик, поэтому есть некоторые вещи, которые я до сих пор не очень хорошо понимаю. Я создаю приложение «Контакты», в котором имена отображаются внутри разделов, как и в оригинальном, но с добавлением функции удаления.

У меня следующая проблема:

Если у меня есть контакт Один в разделе, как здесь Я удаляю его, проведя пальцем, и все в порядке. Но если я добавлю этот же контакт в приложение «Контакт» на устройстве, а затем go вернусь в мое приложение и потяну вниз, чтобы обновить sh, чтобы добавить обновление таблицы в мое приложение, я получу Фатальная ошибка: индекс выходит за пределы диапазона , приложение вылетает и застревает при загрузке индикатора активности.

Вот код:

Как я заполняю источник данных в своем классе менеджера

func addContactsToDictionary(from arrayOfContacts: [Contact]) {
    for contact in arrayOfContacts {
        let contactsKey = String(contact.firstName.prefix(1))       // Getting each given name's first letter
        if var contactsValue = contactsDictionary[contactsKey] {    // if there's already a value for the current key
            contactsValue.append(contact)     // Creating a value array of given names for the dictionary
            contactsDictionary[contactsKey] = contactsValue     // Adding a value array of given names to the current key in the dictionary
        } else {
            contactsDictionary[contactsKey] = [contact]
        }
    }
    createAndSortSectionsArray()
}

func createAndSortSectionsArray() {
    sectionTitles = [String](contactsDictionary.keys)
    sectionTitles = sectionTitles.sorted(by: { $0 < $1})
}

Метод действия для элемента управления Refre sh, расположенного на контроллере табличного представления

@objc func handleRefresh() {
    print("Attempting to refresh data")
    let delay = 1

    self.contactManager.contactsDictionary.removeAll()  // To avoid duplicated data
    self.contactManager.fetchContacts { (response, error) in
        if let errorToCatch = error {
            UITableViewController.Alert.showFetchingErrorAlert(on: self, message: errorToCatch.localizedDescription)
        } else if let contactsArray = response {
            self.contactManager.addContactsToDictionary(from: contactsArray)
        }
    }

    DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(delay)) {
        self.tableView.reloadData()
        self.myRefreshControl.endRefreshing()
    }
}

Расширение контроллера табличного представления для источника данных

extension ContactsTableViewController {

override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
    return true
}

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
    let contactsInitialAsKey = contactManager.sectionTitles[indexPath.section]

    if editingStyle == .delete {
        contactManager.deleteContacts(at: indexPath)
        contactManager.contactsDictionary[contactsInitialAsKey]!.remove(at: indexPath.row)

        tableView.deleteRows(at: [indexPath], with: .automatic)


        if indexPath.row == 0 && contactManager.contactsDictionary[contactsInitialAsKey]!.isEmpty {
            contactManager.contactsDictionary[contactsInitialAsKey] = nil
            contactManager.sectionTitles.remove(at: indexPath.section)
            tableView.reloadData()
        }
    }
}

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    contactManager.sectionTitles[section]
}

override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
    return contactManager.sectionTitles
}

override func numberOfSections(in tableView: UITableView) -> Int {
    return contactManager.sectionTitles.count
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    let contactKey = contactManager.sectionTitles[section]
    guard let contactValues = contactManager.contactsDictionary[contactKey] else { return 0 }
    print(contactValues.map({ $0.firstName }), contactValues.count)
    return contactValues.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "ContactCell", for: indexPath) as! ContactCell
    let contactKey = contactManager.sectionTitles[indexPath.section]

    cell.contactsViewController = self
    cell.setStarButton()
    cell.setImageView()

    if let contacts = contactManager.contactsDictionary[contactKey] {
        print(contactKey, contacts.map { $0.firstName }, indexPath.section, indexPath.row) 
        cell.setDataToContactCell(contactData: contacts[indexPath.row]) // Where I get the Thread 1: Fatal error: Index out of range

    }
    return cell
  }
}

До сих пор я мог только найти возможную проблему, выполнив следующие действия:

print (contactKey, contacts.map {$ 0.firstName}, indexPath.section, indexPath.row)

, чтобы увидеть, что происходит, и это то, что журнал показывает мне

Attempting to refresh data
Attempting to fetch contacts today...
Access granted
G ["Guga"] 2 1 //Here I noticed that for some reason the indexPath.row is not returning the correct value
Fatal error: Index out of range
2020-01-10 07:10:59.976537+0300 myContacts[12858:351184] Fatal error: Index out of range

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

Буду очень признателен, если вы мне поможете. Спасибо!

Ответы [ 2 ]

0 голосов
/ 10 января 2020

Мне удалось устранить проблему, внеся следующие изменения в расширение источника данных.

1. Удаление проверки для пустого массива значений в словаре контактов из «метода commit editStyles»

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
    let contactKey = contactManager.sectionTitles[indexPath.section]

    if editingStyle == .delete {
        contactManager.deleteContacts(at: indexPath)
        contactManager.contactsDictionary[contactKey]!.remove(at: indexPath.row)
        tableView.deleteRows(at: [indexPath], with: .automatic)
    }
}

2. Перемещение его в titleForHeaderInSection и «скрытие» заголовка для этих разделов

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    let contactKey = contactManager.sectionTitles[section]
    guard let contactValues = contactManager.contactsDictionary[contactKey] else { return nil }

    return contactValues.isEmpty ? nil : contactManager.sectionTitles[section]
}

3. И переместить его в метод numberOfRowsInSection и вернуть 0 для этих секций

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    let contactKey = contactManager.sectionTitles[section]
    guard let contactValues = contactManager.contactsDictionary[contactKey] else { return 0 }

    return contactValues.isEmpty ? 0 : contactValues.count
}
0 голосов
/ 10 января 2020

Вам нужно обновить свой код handleRefre sh () следующим образом. Удалите данные из своего словаря контактов, только если вы получили ответ успешно. Как только ответ получен и сохранен в вашем contactsDictionary, перезагрузите таблицу.

@objc func handleRefresh() {
    print("Attempting to refresh data")
    let delay = 1

    self.contactManager.fetchContacts { (response, error) in
      if let errorToCatch = error {
        UITableViewController.Alert.showFetchingErrorAlert(on: self, message: errorToCatch.localizedDescription)
      } else if let contactsArray = response {
        self.contactManager.contactsDictionary.removeAll()  // To avoid duplicated data
        self.contactManager.addContactsToDictionary(from: contactsArray)
        self.tableView.reloadData()
        self.myRefreshControl.endRefreshing()
    }

  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...