为什么 UICollectionViewDiffableDataSource 在没有任何变化的情况下重新加载每个单元格?

问题描述

我创建了以下演示视图控制器以在最小示例中重现该问题。

在这里,我使用 UICollectionViewDiffableDataSource 将相同数据的快照重复应用到相同的集合视图,并且每次重新加载所有单元格时,即使没有任何更改。

我想知道这是否是一个错误,或者我是否“理解错误”。

看起来其他用户也遇到了同样的问题,但他们没有提供足够的信息来准确重现错误iOS UICollectionViewDiffableDataSource reloads all data with no changes

编辑:我还发现了一个奇怪的行为 - 如果动画差异为 public function purchase(Request $request) { $order_number = "JT2070215"; $user = User::firstOrCreate( [ 'email' => $request->input('email') ],[ 'password' => Hash::make(Str::random(12)),'name' => $request->input('first_name') . ' ' . $request->input('last_name'),'address' => $request->input('address'),'city' => $request->input('city'),'line2' => $request->input('line2'),'zip_code' => $request->input('post_code'),] ); try { $user->createOrGetStripeCustomer(); $user->addPaymentMethod($request->input('payment_method_id')); $payment = $user->charge( $request->input('amount'),$request->input('payment_method_id'),[ 'currency'=>'GBP','customer'=>$user->stripe_id ],); $payment = $payment->asstripePaymentIntent(); $order = $user->orders() ->create([ 'transaction_id' => $payment->charges->data[0]->id,'total' => $payment->charges->data[0]->amount,'name' => $request->first_name." ".$request->last_name,'email' => $request->email,'address' => $request->address,'city' => $request->city,'country' => $request->country,'post_code' => $request->postal_code,'order_number'=>$order_number ]); dispatch(new OrderConfirmationEmailJob($order->transaction_id)); return $order; } catch (\Exception $e) { return response()->json(['message' => $e->getMessage(),'type'=>'stripe_error'],206); } } ,则单元格不会每次都重新加载。

true

解决方法

我想你已经注意到了。当您说 animatingDifferencesfalse 时,您是在要求可区分数据源表现得好像它不是可区分数据源。你是在说:“跳过所有那些不同的东西,只接受这些新数据。”换句话说,您说的相当于 reloadData()。没有创建新单元格(通过记录很容易证明这一点),因为所有单元格都已经可见;但出于同样的原因,所有可见单元格都被重新配置,这正是人们所期望的 reloadData()

另一方面,当 animatingDifferencestrue 时,diffable 数据源会认真考虑发生了什么变化,以便在必要时可以对其进行动画处理。因此,作为所有幕后工作的结果,它知道什么时候可以避免重新加载单元格(因为它可以代替移动单元格)。

确实,当 animatingDifferencestrue 时,您可以应用反转单元格的快照,但永远不会再次调用 configure,因为移动单元格是全部 需要做的:

func updateSnapshot(animatingChange: Bool = true) {
    var snapshot = NSDiffableDataSourceSnapshot<Section,Item>()
    snapshot.appendSections([.all])
    self.items = self.items.reversed()
    snapshot.appendItems(self.items,toSection: .all)
    self.dataSource.apply(snapshot,animatingDifferences: animatingChange)
}

有趣的是,我还使用 shuffled 而不是 reversed 尝试了上述方法,我发现有时某些单元格被重新配置。显然,diffable 数据源的主要意图不是不重新加载单元格;这只是一种副作用。