В SwiftUI метод представления OnDisappear не запускается в первый раз, когда различаемый источник данных применяется к UIOS

Программируем под IOS
Ответить Пред. темаСлед. тема
Anonymous
 В SwiftUI метод представления OnDisappear не запускается в первый раз, когда различаемый источник данных применяется к U

Сообщение Anonymous »

Я работаю над приложением для iOS, используя как UITableViewDiffableDataSource, так и SwiftUI, и столкнулся с двумя отдельными, но загадочными проблемами:
UITableViewDiffableDataSource не использует повторно ячейки при первом применении после первоначального снимка. После первого применения он работает так, как ожидалось, со второго раза.
SwiftUI View внутри UITableViewCell onDisappear Не запускает первые изменения снимка после первоначального снимка. После этого onDispear вызывает, как и ожидалось.
С обычным UITableView он работает нормально.
Вызывает проблему — из-за этого проигрыватель и ячейки сильно сохраняют память.
Пример кода для воспроизведения с использованием diffable (DiffableTableViewExampleViewController) и нормальной работы без diffable (RegularTableViewExampleViewController)

Код: Выделить всё

import UIKit

enum TableSection: Hashable {
case featured
case regular
}

struct FeaturedItem: Hashable {
let id: UUID
let title: String
let subtitle: String
}

struct RegularItem: Hashable {
let id: UUID
let description: String
}

class DiffableTableViewExampleViewController: UIViewController {

private var tableView: UITableView!
private var dataSource: UITableViewDiffableDataSource!

override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white

setupTableView()
configureDataSource()
applyInitialSnapshot()
}

// Update the setupTableView method to use custom cells
private func setupTableView() {
tableView = UITableView(frame: view.bounds, style: .insetGrouped)
tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

tableView.register(FeaturedCell.self, forCellReuseIdentifier: "FeaturedCell")
tableView.register(RegularCell.self, forCellReuseIdentifier: "RegularCell")

view.addSubview(tableView)

navigationItem.rightBarButtonItems = [
UIBarButtonItem(
title: "Reload",
style: .plain,
target: self,
action: #selector(reloadSnapshot)
),
UIBarButtonItem(
title: "Regular View",
style: .plain,
target: self,
action: #selector(navigateToRegularView)
)
]
}

@objc private func navigateToRegularView() {
let regularVC = RegularTableViewExampleViewController()
navigationController?.pushViewController(regularVC, animated: true)
}

@objc private func reloadSnapshot() {
// deleteSections()
self.appendNewItems()
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {

// self.applyInitialSnapshot()
}
//appendNewItems()
}

func deleteSections() {
var snapshot = dataSource.snapshot()
snapshot.deleteSections([.regular, .featured])
dataSource.apply(snapshot, animatingDifferences: false)
}

func appendNewItems() {
//        var snapshot = NSDiffableDataSourceSnapshot()
//
//        snapshot.appendSections([.featured, .regular])

var snapshot = dataSource.snapshot()
snapshot.deleteItems(featuredItems.map { $0.id })
self.featuredItems = [
FeaturedItem(id: UUID(), title: "Featured Item 1", subtitle: "Subtitle 1")
//            FeaturedItem(id: UUID(), title: "Featured Item 2", subtitle: "Subtitle 2"),
].shuffled()
self.regularItems = [
//            RegularItem(id: UUID(), description: "Regular Item 2")
//            RegularItem(id: UUID(), description: "Regular Item 3"),
].shuffled()
snapshot.appendItems(featuredItems.map { $0.id })
//        snapshot.appendItems(regularItems.map { $0.id }, toSection: .regular)

dataSource.apply(snapshot, animatingDifferences: true)
}

// Update the configureDataSource method to use custom cells
private func configureDataSource() {
dataSource = UITableViewDiffableDataSource(
tableView: tableView
) { tableView, indexPath, itemIdentifier in
if let featuredItem = self.featuredItems.first(where: { $0.id == itemIdentifier }) {
let cell =
tableView.dequeueReusableCell(withIdentifier: "FeaturedCell", for: indexPath)
as! FeaturedCell
cell.configure(with: featuredItem)
return cell
} else if let regularItem = self.regularItems.first(where: { $0.id == itemIdentifier }) {
let cell =
tableView.dequeueReusableCell(withIdentifier: "RegularCell", for: indexPath)
as! RegularCell
cell.configure(with:  regularItem)
return cell
}
return UITableViewCell()
}
}

private var featuredItems: [FeaturedItem] = []
private var regularItems: [RegularItem] = []

private func applyInitialSnapshot() {
var snapshot = NSDiffableDataSourceSnapshot()

featuredItems = [
FeaturedItem(id: UUID(), title: "Featured Item 1", subtitle: "Subtitle 1"),
]
//        regularItems = [
//            RegularItem(id: UUID(), description: "Regular Item 1"),
//            RegularItem(id: UUID(), description: "Regular Item 2"),
//            RegularItem(id: UUID(), description: "Regular Item 3"),
//        ]

snapshot.appendSections([.featured, .regular])
snapshot.appendItems(featuredItems.map { $0.id }, toSection: .featured)
//        snapshot.appendItems(regularItems.map { $0.id }, toSection: .regular)
dataSource.apply(snapshot, animatingDifferences: true)
}
}

import SwiftUI
class RegularTableViewExampleViewController: UIViewController {

private var tableView: UITableView!
private var featuredItems: [FeaturedItem] = []
private var regularItems: [RegularItem] = []

override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white

setupTableView()
applyInitialData()
}

private func setupTableView() {
tableView = UITableView(frame: view.bounds, style: .insetGrouped)
tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

tableView.register(FeaturedCell.self, forCellReuseIdentifier: "FeaturedCell")
tableView.register(RegularCell.self, forCellReuseIdentifier: "RegularCell")

tableView.dataSource = self
view.addSubview(tableView)

navigationItem.rightBarButtonItem = UIBarButtonItem(
title: "Reload",
style: .plain,
target: self,
action: #selector(reloadData)
)
}

@objc private func reloadData() {
appendNewItems()
tableView.reloadData()
}

private func applyInitialData() {
featuredItems = [
FeaturedItem(id: UUID(), title: "Featured Item 1", subtitle: "Subtitle 1")
]
regularItems = [
]
}

private func appendNewItems() {
featuredItems.removeAll()
featuredItems.append(FeaturedItem(id: UUID(), title: "New Featured Item", subtitle: "New Subtitle"))
}
}

extension RegularTableViewExampleViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return featuredItems.count
case 1:
return regularItems.count
default:
return 0
}
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->  UITableViewCell {
switch indexPath.section {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "FeaturedCell", for: indexPath) as! FeaturedCell
cell.configure(with: featuredItems[indexPath.row])
return cell
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: "RegularCell", for: indexPath) as! RegularCell
cell.configure(with: regularItems[indexPath.row])
return cell
default:
return UITableViewCell()
}
}
}
import AVKit

struct FeaturedCellView: View {
let featuredItem: FeaturedItem
@State private var player = AVPlayer(url: URL(string: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4")!)
var body: some View {
VStack {
Text(featuredItem.title)
.font(.headline)
Text(featuredItem.subtitle)
.font(.subheadline)
VideoPlayer(player: player)
.frame(height: 200)
}.onAppear {
print("FeaturedCellView onAppear for item: \(featuredItem.title)")
player.play()
}
.onDisappear {
print("FeaturedCellView onDisappear for item: \(featuredItem.title)")
player.pause()
}
}
}

// add preview
#Preview {
FeaturedCellView(featuredItem: FeaturedItem(id: UUID(), title: "Featured Item 1", subtitle: "Subtitle 1"))
}

struct RegularCellView: View {
let regularItem: RegularItem
@State private var player = AVPlayer(url: URL(string: "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4")!)

var body: some View {
VStack {
Text(regularItem.description)
.font(.body)
VideoPlayer(player: player)
.frame(height: 200)
}.onAppear {
print("RegularCellView onAppear with item: \(regularItem.description)")
player.play()
}
.onDisappear {
print("RegularCellView onDisappear with item: \(regularItem.description)")
player.pause()
}
}
}

class FeaturedCell: UITableViewCell {
private var hostingController: UIHostingController?

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: .subtitle, reuseIdentifier: reuseIdentifier)
print("FeaturedCell init")
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

func configure(with featuredItem: FeaturedItem) {
let view = FeaturedCellView(featuredItem: featuredItem)
hostingController = UIHostingController(rootView: view)
if let hostingController = hostingController {
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(hostingController.view)
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: contentView.topAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
hostingController.view.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
])
}
}

override func prepareForReuse() {
super.prepareForReuse()
print("FeaturedCell prepareForReuse")
hostingController?.view.removeFromSuperview()
hostingController = nil
}

deinit {
print("FeaturedCell deallocated")
}
}

class RegularCell: UITableViewCell {
private var hostingController: UIHostingController?

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: .default, reuseIdentifier: reuseIdentifier)
print("RegularCell init")
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

func configure(with regularItem: RegularItem) {
let view = RegularCellView(regularItem:  regularItem)
hostingController = UIHostingController(rootView: view)
if let hostingController = hostingController {
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(hostingController.view)
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: contentView.topAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
hostingController.view.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
])
}
}

override func prepareForReuse() {
super.prepareForReuse()
print("RegularCell prepareForReuse")
hostingController?.view.removeFromSuperview()
hostingController = nil
}

deinit {
print("RegularCell deallocated")
}
}
https://gist.github.com/SURYAKANTSHARMA ... 00ba5aed17 Мы будем очень признательны за любые идеи или предложения по этим вопросам!
Заранее спасибо !

Подробнее здесь: https://stackoverflow.com/questions/793 ... r-the-firs
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «IOS»