#swift #closures #uicollectionviewdiffabledatasource
Вопрос:
Изучая Swift с помощью учебника Пола Хадсонса, я столкнулся с чем-то странным.
Инициализатор UICollectionViewDiffableDataSource определяется как:
public init(collectionView: UICollectionView, cellProvider: @escaping UICollectionViewDiffableDataSource<SectionIdentifierType, ItemIdentifierType>.CellProvider)
Насколько я могу судить, другого инициализатора нет. Однако Пол успешно инициализирует его таким образом, опуская аргумент cellProvider:
dataSource = UICollectionViewDiffableDataSource<Section, App>(collectionView: collectionView) { collectionView, indexPath, app in
switch self.sections[indexPath.section].type {
case "mediumTable":
return self.configure(MediumTableCell.self, with: app, for: indexPath)
case "smallTable":
return self.configure(SmallTableCell.self, with: app, for: indexPath)
default:
return self.configure(FeaturedCell.self, with: app, for: indexPath)
}
}
Между тем, учебник Рэя Вендерлиха сделал бы это так:
dataSource = UICollectionViewDiffableDataSource<Section, App>(collectionView: collectionView, cellProvider: { (collectionView, indexPath, app) -> UICollectionViewCell? in
switch self.sections[indexPath.section].type {
case "mediumTable":
return self.configure(MediumTableCell.self, with: app, for: indexPath)
case "smallTable":
return self.configure(SmallTableCell.self, with: app, for: indexPath)
default:
return self.configure(FeaturedCell.self, with: app, for: indexPath)
}
})
Я пытаюсь понять, какая быстрая «магия» происходит за спиной Пола, поскольку ему, похоже, сходит с рук отказ от аргумента cellProvider и вместо этого он делает какую-то странную вещь с закрытием. Какие именно правила Swift он здесь применяет?
Комментарии:
1. Я рекомендую прочитать этот раздел руководства Swift.
Ответ №1:
В вашем случае вы видите два способа, как вы можете написать то же самое с другим синтаксисом.
Здесь вы используете все параметры ожидаемым образом с двумя параметрами CollectionView и cellProvider.
dataSource = UICollectionViewDiffableDataSource<Section, App>(collectionView: collectionView, cellProvider: { (collectionView, indexPath, app) -> UICollectionViewCell? in
switch self.sections[indexPath.section].type {
case "mediumTable":
return self.configure(MediumTableCell.self, with: app, for: indexPath)
case "smallTable":
return self.configure(SmallTableCell.self, with: app, for: indexPath)
default:
return self.configure(FeaturedCell.self, with: app, for: indexPath)
}
})
И здесь вы используете второй параметр (cellProvider:) в качестве конечного закрытия после скобок с параметрами, кроме последнего.
dataSource = UICollectionViewDiffableDataSource<Section, App>(collectionView: collectionView) { collectionView, indexPath, app in
switch self.sections[indexPath.section].type {
case "mediumTable":
return self.configure(MediumTableCell.self, with: app, for: indexPath)
case "smallTable":
return self.configure(SmallTableCell.self, with: app, for: indexPath)
default:
return self.configure(FeaturedCell.self, with: app, for: indexPath)
}
}
Видите, что это одно и то же в обоих примерах:
{ collectionView, indexPath, app in
switch self.sections[indexPath.section].type {
case "mediumTable":
return self.configure(MediumTableCell.self, with: app, for: indexPath)
case "smallTable":
return self.configure(SmallTableCell.self, with: app, for: indexPath)
default:
return self.configure(FeaturedCell.self, with: app, for: indexPath)
}
Подробнее о конечных замыканиях или о том, что такое синтаксис конечных замыканий?
Ответ №2:
Спасибо всем, кто направил меня в правильном направлении. Это может помочь увидеть дополнительные более сжатые примеры:
func executeThis(info: String, completion: ((String) -> Void)) {
completion(info)
}
let completion: ((String) -> Void) = { value in
print("Done: " value)
}
// Pass the closure variable to the completion param:
executeThis(info:"Some Activity", completion:completion)
// Provide the closure directly as an argument:
executeThis(info:"Some Activity 2", completion: { value in
print("Done: " value)
})
// Trailing closure: the last param, which is a closure, is implicitly provided via "{ value in"
executeThis(info:"Some Activity 3") { value in
print("Trailing closure done: " value)
}
Комментарии:
1. Отличная работа. Еще одна маленькая вещь, удалите точки с запятой из вашего закрытия завершения. 🙂