WWDC 2019真的挤满了iOS的新的东西,新的数据源TableViews和CollectionView这UITableViewDiffableDataSource。
我已经成功地将上述新数据源与核心数据集成,删除和插入新记录工作没有任何问题,不幸的是我在将项目从一个部分移动到另一个部分时遇到问题,如果我试图移动最后一个单元格,就会出现问题这部分 。
下面是我的代码:
表视图设置
private func setupTableView() {
diffableDataSource = UITableViewDiffableDataSource<Int, Reminder>(tableView: remindersTableView) { (tableView, indexPath, reminder) -> UITableViewCell? in
let cell = tableView.dequeueReusableCell(withIdentifier: "SYReminderCompactCell", for: indexPath) as! SYReminderCompactCell
var reminderDateString = ""
let reminderTitle = "\(reminder.emoji ?? "") \(reminder.title ?? "")"
if let date = reminder.date {// check if reminder has date or no , if yes check number of todos and if date in today
let dateFormatter = SYDateFormatterManager.sharedManager.getDateFormaatter() …Run Code Online (Sandbox Code Playgroud) 我目前在使用UITableViewDiffableDataSource.
我想尝试一下这个新功能,所以我在网上看了很多教程,但似乎没有一个能回答我的问题。
在我当前的 viewController 中,我有一个UITableView, 有 3 个不同的对象(每个对象有不同的类型),但UITableViewDiffableDataSource是强类型的。
喜欢: dataSource = UITableViewDiffableDataSource <SectionType, ItemType>
我所有的部分都有类似的东西
func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return bigObject.ObjectsOfType1.count
} else if section == 1 {
return bigObject.ObjectsOfType2.count
} else {
return bigObject.ObjectsOfType3.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as! …Run Code Online (Sandbox Code Playgroud) 我已经使用了一段时间的 diffable 数据源,UITableView我喜欢它。但是今天我意识到它设计中固有的一个问题。使用diffable数据源,需要在数据发生变化时生成并应用快照。如果数据量很大,或者更有可能数据量不是很大,但是生成每个数据点的时间很短,生成快照的累积时间会变得很明显,导致用户体验不佳。我不认为旧的 API 有这个问题,因为只为要在屏幕上显示的项目调用委托函数。
由于它是一项新技术(它是为 SwiftUI 引入的,对吗?),我无法相信它会有如此明显的局限性。但是从我在网上能找到的资料来看,我看不出它是如何解决这个问题的。在 WWDC 2019 session 220 视频中,演讲者提到它可以以透明的方式在后台线程上运行,但我认为这不一定能缓解所有场景中的问题。例如,在用户交互启动数据更改的场景中,通常以同步方式处理数据和更新 UI,因此在后台运行并没有真正的帮助。
我想我一定错过了什么,但我看不到它是什么。任何解释将不胜感激。
我有一个简单的UICollectionView1 个部分和 1 个项目类型,由新的 iOS 13 提供支持UICollectionViewDiffableDataSource。
即使没有更改数据源(相同hashValue),UICollectionViewDiffableDataSource也会更新整个集合视图(调用cellProvier每个可见单元格)。
问题是,相同的场景按UITableViewDiffableDataSource预期工作,即不更改数据源,UITableViewDiffableDataSource 什么也不做。
这是设计上的差异,还是某种错误?
uikit ios ios13 diffabledatasource nsdiffabledatasourcesnapshot
NSDiffableDataSourceSnapshot和的正确使用方法是什么- (void)tableView:(nonnull UITableView *)tableView prefetchRowsAtIndexPaths:(nonnull NSArray<NSIndexPath *> *)indexPaths?
似乎每次预取重新加载表视图时,表视图都会在调用apply快照后要求更多预取,从而创建无限循环。
- (void)reloadViews {
//[self.tableView reloadData];
NSMutableArray *items = [NSMutableArray new];
for (TCHChannel* channel in self.channels) {
[items addObject:channel.sid];
}
if ([items count] == 0) {
return;
}
NSDiffableDataSourceSnapshot<ConversationSectionType*, NSString*> *snapshot =
[[NSDiffableDataSourceSnapshot<ConversationSectionType*, NSString*> alloc] init];
ConversationSectionType *main = [ConversationSectionType new];
main.section = kMain;
[snapshot appendSectionsWithIdentifiers:@[main]];
[snapshot appendItemsWithIdentifiers:items intoSectionWithIdentifier:main];
[self.diffDataSource applySnapshot:snapshot animatingDifferences:NO];
}
Run Code Online (Sandbox Code Playgroud)
这是预取方法:
- (void)tableView:(nonnull UITableView *)tableView prefetchRowsAtIndexPaths:(nonnull NSArray<NSIndexPath *> *)indexPaths {
for (NSIndexPath *indexPath in …Run Code Online (Sandbox Code Playgroud) 这是一个玩具示例,但它准确地减少了我所处的情况:
class MyDataSource: UITableViewDiffableDataSource<String,String> {
var string : String?
init(string:String?) {
self.string = string
super.init(tableView: UITableView()) { (_, _, _) -> UITableViewCell? in
print(self.string) // error
return nil
}
}
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试使我的表视图数据源自包含,而我这样做的方式(到目前为止)是将 UITableViewDiffableDataSource 子类化。这工作正常,除非我尝试为我的子类提供自定义初始值设定项。玩具示例显示了问题。
我想要填充单元格的方式绝对取决于在数据源的生命周期以后可以更改的值。因此它不能被硬编码到单元提供者函数中。我不能在这里简单地引用在string初始化程序中传递的值;我必须参考,self.string因为string稍后其他代码将有权更改此数据源的实例属性,并且我希望单元提供程序在发生这种情况时使用该新值。
但是,我收到错误“在所有成员初始化之前被闭包捕获的自我”。这似乎不公平。我确实string在调用之前初始化了我的实例属性super.init。因此,在可能调用单元提供程序方法的最早时刻,它确实具有值。
So I've just recently playing around with Compositional Layouts with Diffable DataSource and so far loving it. But all of my endeavors have included a single type of Data Item.
What I'm trying to achieve is have two different types of List, say Car and Airplane
So far what I've done is created the layouts, created an Enum
enum DataItem: Hashable{
case cars(Car)
case airplane(Airplane)
}
Run Code Online (Sandbox Code Playgroud)
And dataSource initialization:
func configureDataSource(){
dataSource = UICollectionViewDiffableDataSource
<Section, DataItem>(collectionView: collectionView) {
(collectionView: UICollectionView, …Run Code Online (Sandbox Code Playgroud) 我的收藏视图遇到了一个非常奇怪的问题。我正在使用适用于 iOS 13+ 的组合布局和 Diffable 数据源 API,但我遇到了一些非常奇怪的行为。如下面的视频所示,当我更新数据源时,添加到顶部部分的第一个单元格无法正确调整大小,然后当我添加第二个单元格时,两个单元格都会消失,然后当我添加第三个单元格时,所有内容均以正确的尺寸加载并显示。当我取消添加所有单元格并第二次以类似的方式将它们添加回来时,最初的问题不会再次发生。
我尝试以某种方式使用以下解决方案:
collectionView.collectionViewLayout.invalidateLayout()
cell.contentView.setNeedsLayout() followed by cell.contentView.layoutIfNeeded()
collectionView.reloadData()
Run Code Online (Sandbox Code Playgroud)
我似乎无法弄清楚可能是什么导致了这个问题。也许我有两个不同的单元格注册到集合视图中,并且不正确地使它们出列,或者我的数据类型没有正确符合可散列。我相信我已经解决了这两个问题,但我还将提供我的代码来提供帮助。此外,提到的数据控制器是一个简单的类,它存储用于配置的单元格的视图模型数组(那里不应该有任何问题)。谢谢!
集合视图控制器
import UIKit
class PartyInvitesViewController: UIViewController {
private var collectionView: UICollectionView!
private lazy var layout = createLayout()
private lazy var dataSource = createDataSource()
private let searchController = UISearchController(searchResultsController: nil)
private let dataController = InvitesDataController()
override func loadView() {
super.loadView()
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(collectionView)
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
collectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
override func viewDidLoad() { …Run Code Online (Sandbox Code Playgroud) ios uicollectionview swift diffabledatasource uicollectionviewcompositionallayout
当我拥有较大的数据集(大约 22,000 个项目)时,我会遇到可比较数据源的性能问题。令我惊讶的是,当动画打开时,应用快照需要花费如此多的时间。请参阅代码部分:
let shouldAnimate = tableView.numberOfSections != 0
apply(snapshot as NSDiffableDataSourceSnapshot<String, NSManagedObjectID>, animatingDifferences: shouldAnimate)
Run Code Online (Sandbox Code Playgroud)
注意: Jesse Squires 提供了一个很好的资源:
我的问题是,考虑到应用快照是 O(n) 操作,我是否遗漏了某些内容或可区分数据源无法更快地处理此问题?
关闭动画,与 相同reloadData,会有一定帮助。
示例代码是由很棒的SwiftLee基于这篇文章设置的。
请参阅此处的示例项目。
示例视频在这里。
更新(2021 年 9 月 2 日):这里有一个很好的 Twitter 讨论。
旁注:示例应用程序可以通过不设置来改进,fetchBatchSize因为请求与NSFetchedResultsController. 请参阅链接。
core-data uitableview nsfetchedresultscontroller diffabledatasource uitableviewdiffabledatasource
我正在使用 UITableViewDataSourcePrefetching 进行分页。
这些值将从领域本地存储中获取。
我将得到一个对象数组。这些值将应用于现有的 UITableViewDiffableDataSource 数据源。
应用快照后,表格视图滚动到顶部。
我已经验证我的所有 ChatMessage 对象都具有唯一的 hashValues。
如何防止滚动?
视频链接TableView_scroll_issue_video
鉴于我的代码片段
private func appendLocal(chats chatMessages: [ChatMessage]) {
var sections: [String] = chatMessages.map({ $0.chatDateTime.toString() })
sections.removeDuplicates()
guard !sections.isEmpty else { return }
var snapshot = dataSource.snapshot()
let chatSections = snapshot.sectionIdentifiers
sections.forEach { section in
let messages = chatMessages.filter({ $0.chatDateTime.toString() == section })
/// Checking the section is already exists in the dataSource
if let index = chatSections.firstIndex(of: section) {
let indexPath = IndexPath(row: 0, section: index) …Run Code Online (Sandbox Code Playgroud) uitableview ios swift diffabledatasource uitableviewdiffabledatasource
ios ×8
swift ×5
uitableview ×4
uikit ×3
ios13 ×2
uitableviewdiffabledatasource ×2
core-data ×1
nsdiffabledatasourcesnapshot ×1
objective-c ×1