Быстрое и расширение класса

Я не понимаю, почему программисты используют ключевое слово extension в своей реализации класса. Вы можете прочитать в других темах, что код затем более семантически разделен и т.д. Но когда я работаю с собственным кодом, мне становится понятнее использовать // MARK - Something. Затем, когда вы используете список методов (ctrl + 6) в Xcode, все будет видно при первом просмотре.

В документации Apple вы можете прочитать:

"Расширения добавляют новые функции к существующему классу, структуре или типу перечисления".

Так почему бы не написать собственный код непосредственно внутри моего собственного класса? В отличие от того, когда я хочу расширить функциональность какого-либо иностранного класса, например NSURLSession или Dictionary, где вам нужно использовать расширения.

Мэтт Томпсон использует расширение в своей библиотеке Alamofire, может быть, он может дать мне небольшое объяснение, почему он выбрал этот подход.

Ответ 1

Для меня это кажется вполне разумным, так как вы можете использовать расширения, чтобы подвергать разные части логики различным расширениям. Это также можно использовать, чтобы сделать соответствие классов протоколам более читабельными, например

class ViewController: UIViewController {
...
}

extension ViewController: UITableViewDelegate {
...
}

extension ViewController: UITableViewDataSource {
...
}

extension ViewController: UITextFieldDelegate {
...
}

Для ясности методы протокола разделены в разных расширениях, это, по-видимому, гораздо лучше, чем позволяет:

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {}

Итак, я бы сказал, что нет вреда в использовании расширений, чтобы сделать ваш собственный код более читаемым, а не просто расширять уже существующие классы из SDK. Используя расширения, вы можете избежать огромных кусков кода в контроллерах и разделить функциональность на легко читаемые части, поэтому нет недостатка в их использовании.

Ответ 2

Использование расширений позволяет сохранять декларацию соответствия протокола рядом с методами, реализующими этот протокол.

Если расширений не было, представьте, что ваш тип:

struct Queue<T>: SequenceType, ArrayLiteralConvertible, Equatable, Printable, Deflectable, VariousOtherables {

// lotsa code...

// and here we find the implementation of ArrayLiteralConvertible
    /// Create an instance containing `elements`.
    init(arrayLiteral elements: T…) {
        etc
    } 

}

Контрастируйте это с помощью расширений, в которых вы объединяете реализацию протоколов с этими конкретными методами, которые его реализуют:

struct Queue<T> {
   // here go the basics of queue - the essential member variables,
   // maybe the enqueue and dequeue methods 
}

extension SequenceType {
    // here go just the specifics of what you need for a sequence type
    typealias Generator = GeneratorOf<T>
    func generate() -> Generator {
        return GeneratorOf { 
          // etc.
        }
    }
}

extension Queue: ArrayLiteralConvertible {
    init(arrayLiteral elements: T...) {
        // etc.
    }
}

Да, вы можете пометить реализации своих протоколов с помощью // MARK (и помните, что вы можете комбинировать оба метода), но вы все равно должны быть разделены в верхней части файла, где будет объявлена ​​поддержка протокола, и тело файла, где выполняется ваша реализация.

Кроме того, имейте в виду, что если вы реализуете протокол, вы получите полезную (если немного подробную) обратную связь от IDE по мере того, как вы расскажете, что вам осталось реализовать. Использование расширений для каждого протокола один за другим делает его (для меня) намного проще, чем делать все за один раз (или прыгать назад и вперед сверху вниз, когда вы их добавляете).

Учитывая это, тогда естественно сопоставить другие, не протокольные, но связанные с ними методы и в расширениях.

Я действительно нахожу, что это иногда расстраивает, когда вы не можете это сделать. Например,

extension Queue: CollectionType {
    // amongst other things, subscript get:
    subscript(idx: Index) -> T {
        // etc
    }
}

// all MutableCollectionType adds is a subscript setter
extension Queue: MutableCollectionType {
    // this is not valid - you’re redeclaring subscript(Index)
    subscript(idx: Int) -> T {
        // and this is not valid - you must declare
        // a get when you declare a set
        set(val) {
            // etc
        }
    }
}

Таким образом, вы должны реализовать как внутри одного расширения.