Друзья, сегодня разберем неочевидную проблему производительности в Swift, о которой мало кто знает. Речь пойдет о том, как простые операции вроде
String(describing:) или
as? могут серьезно замедлять работу приложения.
В
Swift Runtime есть метод:
swift_conformsToProtocolMaybeInstantiateSuperclasses
который выполняет проверки соответствия типов протоколам. В больших приложениях с десятками тысяч типов эти проверки превращаются в линейный поиск по огромному массиву.
Пример где мы теряем производительность:
String(describing:) и
String(reflecting:) кажутся безобидным, но:
struct User {
let id: Int
let name: String
}
let user = User(id: 1, name: "John")
let description = String(describing: user) // 4 проверки протоколов!
Приведение типов:
Операции
as? при работе с протоколами оказались особенно затратными:
// Такой код может быть затратнее, чем кажется
if let convertible = value as? CustomStringConvertible {
print(convertible.description)
}
// Приведение к конкретному классу работает значительно быстрее
if let viewController = object as? UIViewController {
}
Дженерики с ограничениями:
// Плохо для производительности
class Cache {
}
// Лучше
class Cache {
let encode: (T) -> Data
let decode: (Data) -> T
init(encode: @escaping (T) -> Data, decode: @escaping (Data) -> T) {
self.encode = encode
self.decode = decode
}
}
Вывод:
Производительность Swift-приложений - это не только вопросы асинхронности и сложных алгоритмов. Самые значительные улучшения часто скрываются в понимании внутренних механизмов
Swift Runtime и оптимизации, казалось бы, элементарных операций.