Ios DiffableDataSource是否能够正确处理项目移动、项目修改和项目移动&;修改?
我一直觉得,一个好的Diff库,应该具备检测以下3个方面的能力Ios DiffableDataSource是否能够正确处理项目移动、项目修改和项目移动&;修改?,ios,swift,Ios,Swift,我一直觉得,一个好的Diff库,应该具备检测以下3个方面的能力 当项目被移动时 当项目被修改时 移动和修改项目时 当我查看WWDC 2019的源代码时,我注意到这些实现只能够检测移动,而不能检测修改 class WiFiController { struct Network: Hashable { let name: String let identifier = UUID() func hash(into hasher: inout
当我查看WWDC 2019的源代码时,我注意到这些实现只能够检测移动,而不能检测修改
class WiFiController {
struct Network: Hashable {
let name: String
let identifier = UUID()
func hash(into hasher: inout Hasher) {
hasher.combine(identifier)
}
static func == (lhs: Network, rhs: Network) -> Bool {
return lhs.identifier == rhs.identifier
}
}
移动好啊
检测到移动,因为我们检测到标识符=0从索引0移动到索引1
修改。失败
未检测到修改,因为前后的标识符保持不变func==
仅考虑标识符
我想,我可以通过修改上面的类来解决这个问题
class WiFiController {
struct Network: Hashable {
let name: String
let identifier = UUID()
func hash(into hasher: inout Hasher) {
hasher.combine(name, identifier)
}
static func == (lhs: Network, rhs: Network) -> Bool {
return lhs.name == rhs.name && lhs.identifier == rhs.identifier
}
}
移动好啊
检测到移动,因为我们检测到name=“WiFi A”标识符=0从索引0移动到索引1
修改。好的(也许)
检测到修改,因为我们检测到name=“WiFi A”标识符=0被修改为name=“WiFi X”标识符=0
或者,图书馆可能会得出结论,我已从索引0中删除name=“WiFi A”标识符=0,并在索引0中插入新的name=“WiFi X”标识符=0
移动和修改。失败
无法检测移动,因为我们正在比较名称和标识符
我可以知道你如何解决上述问题吗 我认为这可能是
DiffableDataSource
库的一个缺点。由于仅基于散列
和=
,它无法回答这两个问题
func==
时,我们只能使其比较标识或比较内容,但不能两者兼而有之强>
p/s 如果我检查一下安卓系统做得如何,它们提供了两种方法
/**
* Called by the DiffUtil to decide whether two object represent the same Item.
* <p>
* For example, if your items have unique ids, this method should check their id equality.
*
* @param oldItemPosition The position of the item in the old list
* @param newItemPosition The position of the item in the new list
* @return True if the two items represent the same object or false if they are different.
*/
public abstract boolean areItemsTheSame(int oldItemPosition, int newItemPosition);
/**
* Called by the DiffUtil when it wants to check whether two items have the same data.
* DiffUtil uses this information to detect if the contents of an item has changed.
* <p>
* DiffUtil uses this method to check equality instead of {@link Object#equals(Object)}
* so that you can change its behavior depending on your UI.
* For example, if you are using DiffUtil with a
* {@link RecyclerView.Adapter RecyclerView.Adapter}, you should
* return whether the items' visual representations are the same.
* <p>
* This method is called only if {@link #areItemsTheSame(int, int)} returns
* {@code true} for these items.
*
* @param oldItemPosition The position of the item in the old list
* @param newItemPosition The position of the item in the new list which replaces the
* oldItem
* @return True if the contents of the items are the same or false if they are different.
*/
public abstract boolean areContentsTheSame(int oldItemPosition, int newItemPosition);
/**
*由DiffUtil调用以确定两个对象是否表示同一项。
*
*例如,如果项目具有唯一的id,则此方法应检查其id是否相等。
*
*@param oldItemPosition项目在旧列表中的位置
*@param newItemPosition项目在新列表中的位置
*@如果两个项目代表相同的对象,则返回True;如果两个项目不同,则返回false。
*/
公共抽象布尔值是相同的(int-oldItemPosition,int-newItemPosition);
/**
*当DiffUtil想要检查两个项是否具有相同的数据时,调用该函数。
*DiffUtil使用此信息检测项目的内容是否已更改。
*
*DiffUtil使用此方法检查相等性,而不是{@link Object#equals(Object)}
*因此,您可以根据您的UI更改其行为。
*例如,如果将DiffUtil与
*{@link RecyclerView.Adapter RecyclerView.Adapter},您应该
*返回项目的视觉表示是否相同。
*
*仅当{@link#areItemsTheSame(int,int)}返回时才调用此方法
*{@code true}用于这些项目。
*
*@param oldItemPosition项目在旧列表中的位置
*@param newItemPosition项目在新列表中的位置,该列表将替换
*旧项目
*@如果项目内容相同,则返回True;如果项目内容不同,则返回false。
*/
公共抽象布尔值是相同的内容(int oldItemPosition,int newItemPosition);
class WiFiController {
struct Network: Hashable {
let name: String
let identifier = UUID()
func hash(into hasher: inout Hasher) {
hasher.combine(name, identifier)
}
static func == (lhs: Network, rhs: Network) -> Bool {
return lhs.name == rhs.name && lhs.identifier == rhs.identifier
}
}
Index Before After
0 [name = "WiFi A", identifier = 0] [name = "WiFi B", identifier = 1]
1 [name = "WiFi B", identifier = 1] [name = "WiFi A", identifier = 0]
2 [name = "WiFi C", identifier = 2] [name = "WiFi C", identifier = 2]
Index Before After
0 [name = "WiFi A", identifier = 0] [name = "WiFi X", identifier = 0]
1 [name = "WiFi B", identifier = 1] [name = "WiFi B", identifier = 1]
2 [name = "WiFi C", identifier = 2] [name = "WiFi C", identifier = 2]
Index Before After
0 [name = "WiFi A", identifier = 0] [name = "WiFi B", identifier = 1]
1 [name = "WiFi B", identifier = 1] [name = "WiFi X", identifier = 0]
2 [name = "WiFi C", identifier = 2] [name = "WiFi C", identifier = 2]
/**
* Called by the DiffUtil to decide whether two object represent the same Item.
* <p>
* For example, if your items have unique ids, this method should check their id equality.
*
* @param oldItemPosition The position of the item in the old list
* @param newItemPosition The position of the item in the new list
* @return True if the two items represent the same object or false if they are different.
*/
public abstract boolean areItemsTheSame(int oldItemPosition, int newItemPosition);
/**
* Called by the DiffUtil when it wants to check whether two items have the same data.
* DiffUtil uses this information to detect if the contents of an item has changed.
* <p>
* DiffUtil uses this method to check equality instead of {@link Object#equals(Object)}
* so that you can change its behavior depending on your UI.
* For example, if you are using DiffUtil with a
* {@link RecyclerView.Adapter RecyclerView.Adapter}, you should
* return whether the items' visual representations are the same.
* <p>
* This method is called only if {@link #areItemsTheSame(int, int)} returns
* {@code true} for these items.
*
* @param oldItemPosition The position of the item in the old list
* @param newItemPosition The position of the item in the new list which replaces the
* oldItem
* @return True if the contents of the items are the same or false if they are different.
*/
public abstract boolean areContentsTheSame(int oldItemPosition, int newItemPosition);