#ios #swift
#iOS #swift
Вопрос:
Каждый раз, когда я использую pull для обновления, активный индикатор и само приложение на мгновение зависают. Я нашел, какой метод вызывает эту проблему — getTracks (), если я удалю его, то все будет работать хорошо (за исключением того, что таблица не обновляется), но я не могу понять, в чем дело, я перепробовал много вариантов, но без результата. Кто-нибудь может мне помочь? Мой код:
class LibraryViewController: UIViewController {
private let fetchManager = FetchManager()
private var tracks: [TrackModelProtocol] = []
...
private let refreshControl: UIRefreshControl = {
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(refreshTableView), for: .valueChanged)
return refreshControl
}()
...
override func viewDidLoad() {
super.viewDidLoad()
...
getTracks()
setupTableView()
tableView.refreshControl = refreshControl
}
...
private func getTracks() {
guard let tracks = fetchManager.setupTrackModels() else { return }
self.tracks = tracks
}
//pull to refresh
@objc private func refreshTableView(sender: UIRefreshControl) {
getTracks()
tableView.reloadData()
sender.endRefreshing()
}
...
}
...
class FetchManager {
var content: [URL] = []
private var currentDirectory : URL?
private var playerQueue: [AVPlayerItem] = []
private let audioPlayer = AudioPlayer()
private func fetchDataFromDeviceMemory() -> [URL]? {
var content: [URL] = []
if currentDirectory == nil {
currentDirectory = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
}
do {
let allURLs = try FileManager.default.contentsOfDirectory(at: currentDirectory!, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles, .skipsPackageDescendants])
content = allURLs.filter{ $0.pathExtension == "mp3" || $0.pathExtension == "aac" || $0.pathExtension == "wav" }
} catch {
content = []
}
return content
}
func setupTrackModels() -> [TrackModelProtocol]? {
guard let content = fetchDataFromDeviceMemory() else { return [] }
self.content = content
playerQueue = audioPlayer.createPlayerQueue(from: content)
var tracks: [TrackModelProtocol] = []
for index in 0..<playerQueue.count {
var artwork: UIImage?
let playerItem = playerQueue[index]
let metadataList = playerItem.asset.metadata
for item in metadataList {
guard let key = item.commonKey?.rawValue, let value = item.value else{
continue
}
switch key {
case "artwork" where value is Data:
artwork = UIImage(data: value as! Data)
default:
continue
}
}
let track = TrackFromDeviceMemory(
fileName: content[index].lastPathComponent,
duration: playerQueue[index].asset.duration.seconds,
artwork: artwork,
url: content[index].absoluteURL)
tracks.append(track)
}
return tracks
}
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
if isSearchActive {
let deletedTrackURL = filteredTracks[indexPath.row].url
print(deletedTrackURL)
do {
try FileManager.default.removeItem(at: deletedTrackURL)
} catch {
print(error.localizedDescription)
}
getTracks()
searchController.isActive = false
// tableView.reloadData()
tableView.delegate?.tableView!(tableView, didSelectRowAt: IndexPath(row: 0, section: indexPath.section))
} else {
let deletedTrackURL = tracks[indexPath.row].url
print(deletedTrackURL)
do {
try FileManager.default.removeItem(at: deletedTrackURL)
} catch {
print(error.localizedDescription)
}
getTracks()
tableView.deleteRows(at: [indexPath], with: .automatic)
// tableView.reloadData()
Комментарии:
1. IMO было бы лучше переместить метод
tableView.reloadData()
andsender.endRefreshing()
вgetTracks()
после получения ответа от API. попробуйте это и посмотрите, работает ли это.2. Я сделал, как вы сказали, переместил TableView.reloadData () и TableView.refreshControl.endRefreshing() в функцию getTracks (), но это не помогает
3. Мне кажется, что проблема заключается в получении дорожек из памяти устройства
4. Вы пробовали использовать
DispatchQueue.main
?5. Что именно я должен поместить в основную очередь?
Ответ №1:
Вместо возврата массива с помощью setupTrackModels
вы пробовали использовать обработчик завершения и выполнить выборку из глобальной очереди? Само выполнение выборки в основной очереди может быть причиной зависания.
func setupTrackModels(completion: (_ models: [TrackModelProtocol])->Void) {
DispatchQueue.global().async {
guard let content = fetchDataFromDeviceMemory() else {
DispatchQueue.main.async {
completion([])
return
}
}
self.content = content
playerQueue = audioPlayer.createPlayerQueue(from: content)
var tracks: [TrackModelProtocol] = []
for index in 0..<playerQueue.count {
var artwork: UIImage?
let playerItem = playerQueue[index]
let metadataList = playerItem.asset.metadata
for item in metadataList {
guard let key = item.commonKey?.rawValue, let value = item.value else{
continue
}
switch key {
case "artwork" where value is Data:
artwork = UIImage(data: value as! Data)
default:
continue
}
}
let track = TrackFromDeviceMemory(
fileName: content[index].lastPathComponent,
duration: playerQueue[index].asset.duration.seconds,
artwork: artwork,
url: content[index].absoluteURL)
tracks.append(track)
}
DispatchQueue.main.async {
completion(tracks)
}
}
}
На сайте вызова:
fetchManager.setupTrackModels { tracks in
refreshControl.endRefreshing()
self.tracks = tracks
tableView.reloadData()
}
Комментарии:
1. Это работает, но теперь, когда я удаляю строку, приложение вылетает. В функции … зафиксируйте стиль редактирования… Я использую … Просмотр таблицы.делегировать?.Просмотр таблицы! (TableView, didSelectRowAt… И asyncAfter не помогает
2. Я добавил к основному вопросу
3. Происходит ли сбой при
getTracks()
илиtableView.delegate?.tableView!(tableView, didSelectRowAt
? что за ошибка выводится в консоли?4. Ошибка: Завершение работы приложения из-за неперехваченного исключения ‘NSInternalInconsistencyException’, причина: ‘Недопустимое обновление: недопустимое количество строк в разделе 0. Количество строк, содержащихся в существующем разделе после обновления (29), должно быть равно количеству строк, содержащихся в этом разделе до обновления (29), плюс или минус количество строк, вставленных или удаленных из этого раздела (0 вставлено, 1 удалено), и плюс или минус количество строк, перемещенных в этот раздел или из него (0 перемещено, 0 удалено)
5. При перезагрузке данных происходит сбой