Static и class properties — это свойства, принадлежащие типу, а не экземпляру. Исторически они появились для решения задачи хранения информации, общей для всех инстансов (например, счетчиков, конфигураций, фабрик). В Swift static можно использовать во всех типах (class, struct, enum), а class — только в классах и только для вычисляемых свойств, обеспечивая возможность переопределения в наследниках.
Проблема: неправильное использование статических свойств может привести к состоянию гонки и ошибкам при доступе из разных потоков. Также легко спутать static и class и неправильно выбрать механизм для перекрытия в наследниках.
Решение:
Пример кода:
class Counter { static var count = 0 static let queue = DispatchQueue(label: "counter.queue") static func increment() { queue.sync { count += 1 } } class var typeDescription: String { return "Generic Counter" } } class NamedCounter: Counter { override class var typeDescription: String { return "Named Counter" } }
Ключевые особенности:
Вопрос 1: Можно ли объявить static let property как вычисляемое (computed) свойство с get?
Да, static property может быть как stored, так и computed. Для let свойств это обычно константа, однако static var вполне может быть вычисляемым:
struct Math { static var pi: Double { return 3.1415926 } }
Вопрос 2: Являются ли static var thread-safe по умолчанию?
Нет, если static var изменяется из разных потоков, возможны состояния гонки. read/write должны быть синхронизированы вручную.
Вопрос 3: Можно ли использовать class var для stored свойств?
Нет, class var всегда должно быть вычисляемым свойством (property with get/optional set), stored свойства разрешены только для static.
В приложении счетчик входа пользователя хранился в static var и инкрементировался из разных потоков без синхронизации.
Плюсы:
Минусы:
Для глобального конфигурационного объекта использовали static let и доступ к нему был только на чтение или с использованием DispatchQueue для записи.
Плюсы:
Минусы: