В чем разница между методами экземпляра, класса и статическими методами?

Ответ

В Swift существует три основных типа методов, отличающихся областью видимости и возможностью полиморфизма.

1. Метод экземпляра (Instance Method)

Работает с конкретным экземпляром класса/структуры. Имеет доступ к свойствам экземпляра через self.

class Counter {
    var count = 0
    // Метод экземпляра
    func increment() {
        count += 1 // Доступ к свойству экземпляра
        print(count)
    }
}
let myCounter = Counter()
myCounter.increment() // Вызов требует экземпляр

2. Метод класса (Class Method)

Объявляется с ключевым словом class func. Вызывается на самом типе, а не на экземпляре. Поддерживает переопределение в подклассах.

class Vehicle {
    class func description() -> String {
        return "A general vehicle"
    }
}

class Car: Vehicle {
    // Может быть переопределен
    override class func description() -> String {
        return "A car with wheels"
    }
}
print(Vehicle.description()) // "A general vehicle"
print(Car.description())    // "A car with wheels" (полиморфизм)

3. Статический метод (Static Method)

Объявляется с static func. Аналогичен методу класса, но не может быть переопределен в подклассах. Используется для утилитарных функций.

class MathUtils {
    static func square(_ x: Int) -> Int {
        return x * x
    }
}

class AdvancedMath: MathUtils {
    // Ошибка компиляции: нельзя переопределить static метод
    // override static func square(...) {}
}
print(MathUtils.square(5)) // 25

Сводка различий

Характеристика Метод экземпляра Метод класса (class) Статический метод (static)
Вызов На экземпляре: obj.method() На типе: Type.method() На типе: Type.method()
Доступ к self Экземпляр (self.property) Тип (Self.self) Тип (Self.self)
Переопределение Да (если не final) Да Нет
Использование Работа с состоянием объекта Фабричные методы, полиморфные утилиты Чисто утилитарные функции

Практический совет: используйте static по умолчанию для методов, не требующих полиморфизма. Переходите на class только если планируете переопределение в подклассах.

Ответ 18+ 🔞

А, ну это же про методы в Swift! Слушай, тут, блядь, целых три вида, и каждый со своим характером, как люди в очереди за колбасой. Один — конкретный работяга, второй — начальник отделения, а третий — вообще, типа, указ сверху, который не оспаривается. Ёпта, сейчас разжуем.

Первый тип — метод экземпляра. Это самый простой пацан. Он привязан к конкретной сущности, к этому вот объекту. Без экземпляра — он никто и звать его никак. Как будто ты кричишь «Вася!», а в комнате никого нет. Вот и он так же.

class Counter {
    var count = 0
    // Метод экземпляра
    func increment() {
        count += 1 // Доступ к свойству экземпляра
        print(count)
    }
}
let myCounter = Counter()
myCounter.increment() // Вызов требует экземпляр

Видишь? myCounter.increment(). Без myCounter этот increment — просто набор букв в памяти, грустный и никому не нужный. У него есть доступ к self, то есть к внутренностям этого самого счетчика. Работяга, одним словом.

Второй — метод класса (class func). Вот это уже поинтереснее. Это как начальник цеха, который может давать указания от имени всего завода. Вызываешь ты его не на объекте, а на самом типе. И главная его фишка — полиморфизм, ёбта! Его можно переопределить в наследниках. То есть, если папаша сказал одно, то сынок может сказать другое, и все будут слушать сынка, когда обращаются к нему.

class Vehicle {
    class func description() -> String {
        return "A general vehicle"
    }
}

class Car: Vehicle {
    // Может быть переопределен
    override class func description() -> String {
        return "A car with wheels"
    }
}
print(Vehicle.description()) // "A general vehicle"
print(Car.description())    // "A car with wheels" (полиморфизм)

Вот смотри: спрашиваем у Vehicle — он мямлит что-то общее. Спрашиваем у Car — а он уже конкретику выдает. Это и есть магия переопределения. class — это как разрешение на семейные разборки.

Третий — статический метод (static func). А это, сука, уже не метод, а приказ из министерства. Закон. Истина в последней инстанции. Вызывается тоже на типе, но переопределить его — ни хуя! Компилятор тебе такую ошибку выдаст, что мало не покажется. Он для утилиток, которые должны работать одинаково всегда и везде, и нечего тут умничать.

class MathUtils {
    static func square(_ x: Int) -> Int {
        return x * x
    }
}

class AdvancedMath: MathUtils {
    // Ошибка компиляции: нельзя переопределить static метод
    // override static func square(...) {} // Пиздец тебе, а не переопределение!
}
print(MathUtils.square(5)) // 25

Попробуй в наследнике переписать — получишь по ебалу от компилятора. «Не-не-не, дружок, тут власть моя».

А теперь, блядь, сводка для тех, кто в танке или просто забыл:

Признак Метод экземпляра Метод класса (class) Статик (static)
Кого звать? Объект: obj.method() Тип: Type.method() Тип: Type.method()
Кто его self? Сам экземпляр Сам тип (класс) Сам тип (класс)
Можно переписать? Да (если не final) Ага, можно! Ни хуя!
Зачем нужен? Ковыряться в данных объекта Фабрики, общие штуки с полиморфизмом Утилиты, законы, константы

И мой тебе совет, на правах старого ворчуна: начинай всегда со static. Это как поставить замок. Если потом окажется, что метод должен быть полиморфным и его надо переопределять — вот тогда уже меняй на class. А так — static и не парись. Проще жить будет, волнение ебать.