#ios #swift
#iOS #swift
Вопрос:
Приведенные ниже 2 структуры одинаковы, за исключением того, как они генерируют идентификатор. Не могли бы вы объяснить, в чем разница? Если я использую первый, мой UICollectionViewDiffableDataSource работает должным образом (без прокрутки при обновлении). Если я использую второй, диффабля будет прокручиваться.
struct PostDetail {
var comment: Comment
var like: CommentLike?
var user: User
}
extension PostDetail: Hashable {
var identifier: UUID {
return UUID()
}
func hash(into hasher: inout Hasher) {
return hasher.combine(identifier)
}
public static func == (lhs: PostDetail, rhs: PostDetail) -> Bool {
return lhs.identifier == rhs.identifier
}
}
struct PostDetail {
let identifier = UUID()
var comment: Comment
var like: CommentLike?
var user: User
}
extension PostDetail: Hashable {
func hash(into hasher: inout Hasher) {
return hasher.combine(identifier)
}
public static func == (lhs: PostDetail, rhs: PostDetail) -> Bool {
return lhs.identifier == rhs.identifier
}
}
Комментарии:
1. Первый из них недействителен, потому что он просто генерирует новый и другой UUID каждый раз, когда кто-либо запрашивает его идентификатор. UUID является допустимым идентификатором только в том случае, если он является постоянным для «того же» экземпляра.
Ответ №1:
Просто чтобы расширить то, что я сказал в своем комментарии, и Роб Нейпир сказал в своем ответе:
В вашей первой структуре identifier
это просто функция, которая генерирует совершенно новое значение каждый раз, когда она вызывается. Так что это никогда не повторяется дважды! Давайте попробуем. Вот сокращенная версия вашей структуры:
struct PostDetail : Equatable {
var identifier: UUID {
return UUID()
}
static func ==(lhs:PostDetail, rhs:PostDetail) -> Bool {
lhs.identifier == rhs.identifier
}
}
Давайте протестируем это:
let p = PostDetail()
p.identifier // 3FFE9C66-5B80-4EF4-95EC-50388D35040B
p.identifier // 2D180097-CFAC-47E9-8530-C3BD3D39F433
Таким образом, его «идентификатор» не является константой; наоборот, он постоянно меняется. Но вы не можете «идентифицировать» что-либо таким образом. Любая попытка определить Equatable на основе этого завершится неудачей, потому что никакие два объекта PostDetail никогда не могут быть равными, даже если они являются одним и тем же объектом!
let p2 = PostDetail()
p2 == p2 // false
Аналогично, ваш хэш-файл всегда будет терпеть неудачу в том смысле, что никакие два объекта PostDetail не попадут в один и тот же хэш-сегмент, даже два экземпляра одного и того же объекта.
Чтобы быть идентификатором, UUID должен быть постоянным. В вашей второй структуре мы видим эту строку:
let identifier = UUID()
Это константа. Он генерируется при создании экземпляра и никогда не меняется (потому let
что). Именно так должен вести себя UUID.
Итак, может показаться, что вы работаете над каким-то анимационным «сбоем», но вы делаете это совершенно незаконным и бессмысленным способом. Я полагаю, анимации нет, потому что каждый PostDetail «отличается» от любого другого, включая самого себя. Заменяется все различимое содержимое источника данных, поэтому анимировать нечего (или что-то в этом роде). Возможно, вы избегаете какого-то поведения интерфейса, которое вам не нравится, но вы просто обманываете себя, как кто-то, кто заклеивает черную ленту сигнальной лампой на приборной панели автомобиля.
Комментарии:
1. Незначительный nit: Вы говорите: «В вашей первой структуре идентификатор — это просто функция, которая генерирует совершенно новое значение …» Это вычисляемое свойство, которое Swift обрабатывает иначе, чем функция. Вы, конечно, можете утверждать, что вычисляемое свойство очень похоже на функцию, поскольку оно выполняет код и возвращает новое значение, но язык Swift проводит различие между ними.
2. @DuncanC я не согласен. Вычисляемое свойство, доступное только для чтения, — это не что иное, как его функция получения.
3. «Возможно, вы избегаете какого-то поведения интерфейса, которое вам не нравится, но вы просто обманываете себя, как кто-то, кто заклеивает черную ленту контрольной лампой на приборной панели автомобиля». Ха-ха, это именно то, что я делал! Я изменил его, чтобы он был правильным, как вы предложили, также моя проблема с прокруткой была связана с тем, что расчетная высота компоновки композиции была слишком маленькой для многих моих ячеек. Проблема, с которой я сталкиваюсь сейчас, заключается в том, что как только загружается представление коллекции, одна из ячеек отображается довольно большой, но как только я прокручиваю, она исправляется, поэтому это нужно исправить! P.S У меня есть несколько версий ваших книг по программированию для iOS
Ответ №2:
Код в первом примере почти наверняка неверен:
var identifier: UUID {
return UUID()
}
Это создает новый идентификатор каждый раз, когда вы обращаетесь к нему, что является противоположностью «идентификатору». Второй пример правильный.