Избавляемся от текстовых id для ячеек и вьюконтроллеров
Недавно затащил в проект SwiftLint, чтобы код как можно ближе соответствовал Swift Style Guide, ну чтобы в общем был по всем канонам. Куча ворнингов, и довольно часто встречается вот такой:
Line Length Violation: Line should be 120 characters or less: currently 139 characters (line_length)
Вылазит для куска кода, где в wireframe инстанциируется View-слой для VIPER-модуля. Аналогично и для получения ячейки по идентификатору из UICollectionView / UITableView
// for storyboard | |
let viewController = storyboard.instantiateViewController(withIdentifier: "MyViperModuleViewController") as! MyViperModuleViewController | |
// for collection view | |
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyViperModuleCollectionViewCell", for: indexPath) as! MyViperModuleCollectionViewCell |
Казалось бы, куда уж короче, ведь строчку некуда сокращать. Нашлась достаточно удобная оптимизация, позволяющая сделать код более читаемым, а также избавиться от строковых констант, для которых автокомплит не сработает. Кроме повышения читаемости кода, исключаем риск опечататься в строковом идентификаторе, который задан в Storyboard
Глядя на код выше, мы-таки можем что-то сделать, чтобы не писать 2 раза 2 раза MyViperModuleViewController
. Как минимум идея заключается в том, чтобы давать названия для вьюконтроллеров в самих сторибоардах ровно так, как они и называются
Для начала научимся получать текстовый идентификатор из имени нужного класса:
protocol Descriptable { | |
static var id: String { get } | |
} | |
extension Descriptable where Self: Any { | |
static var id: String { | |
return String(describing: Self.self) | |
} | |
} | |
extension NSObject: Descriptable { } |
Ну и сделать укороченные версии методов для UIStoryboard, UICollectionView и UITableView:
extension UICollectionView { | |
func dequeueCell<T: UICollectionViewCell>(for indexPath: IndexPath) -> T { | |
return dequeueReusableCell(withReuseIdentifier: T.id, for: indexPath) as! T | |
} | |
} | |
extension UITableView { | |
func dequeueCell<T: UITableViewCell>(for indexPath: IndexPath) -> T { | |
return dequeueReusableCell(withIdentifier: T.id, for: indexPath) as! T | |
} | |
func dequeueCell<T: UITableViewCell>() -> T { | |
return dequeueReusableCell(withIdentifier: T.id) as! T | |
} | |
} | |
extension UIStoryboard { | |
func instantiate<T: UIViewController>() -> T { | |
return instantiateViewController(withIdentifier: T.id) as! T | |
} | |
} |
Получаем более читаемый код, в котором опущены id вьюконтроллеров и ячеек:
// collection view cell | |
let cell: MyViperModuleCollectionViewCell = collectionView.dequeueCell(for: indexPath) | |
// table view header view | |
let cell: MyViperModuleTableHeaderCell = tableView.dequeueCell() | |
// viper module view | |
let viewController: MyViperModuleViewController = genericStoryboard.instantiate() |
??????
PROFIT