2015-02-06 2 views
12

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

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

«Расширения добавляют новые функциональные возможности существующего класса, структуры или типа перечисления»

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

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

+0

Используйте то, что вам больше нравится, но расширение делает его более явным, чем просто «MARK:», четко обозначая, где он начинается и где он заканчивается. Честно говоря, это не проблема/или проблема, так как я буду использовать оба «MARK:» и «extension». Еще одно преимущество «расширения» заключается в том, что вы можете легко сбрасывать этот код (например, «Редактор» - «Складка кода ...» - «Сложить» или щелкнуть по затененному левому краю). – Rob

ответ

14

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

class ViewController: UIViewController { 
... 
} 

extension ViewController: UITableViewDelegate { 
... 
} 

extension ViewController: UITableViewDataSource { 
... 
} 

extension ViewController: UITextFieldDelegate { 
... 
} 

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

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

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

+0

А для протокола NSCoding? Вы не можете использовать расширение для этого протокола. – Deny

+0

Здесь сложнее, расширения не могут добавить назначенные инициализаторы, поэтому N init ('' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ' – libec

+0

Не работает, если вам нужно получить доступ к чему-либо частному из класса, который вы распространяете, не так ли? Или я чего-то не хватает? –

6

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

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

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 
    } 

} 

Contrast это с помощью расширений, где вы Bundle вместе реализацию протоколов с этими специфическими методами, которые реализуют его:

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 (и помните, что вы можете комбинировать обе технологии), но вы все равно будете разделены по верхней части файла, где объявление поддержки протокола будет b e и тело файла, где выполняется ваша реализация.

Кроме того, помните, если вы реализуете протокол, вы получите полезную (если немного подробную) обратную связь от 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 
     } 
    } 
} 

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

+1

Итак, когда у вас есть исходный код вашего класса на несколько страниц, вы не видите, какие протоколы реализует этот класс. Вы должны искать эту информацию через код. Для меня это не яснее, чем использование // MARK в коде. – Deny

+0

Лошади для курсов, но я бы сказал, используя язык, а не комментарии, чтобы указать, что цель понятна. Также см. Мое редактирование, оно делает реализацию протоколов по мере того, как вы делаете это легче. –

+0

Спасибо за ваше мнение. Я попытаюсь объединить оба подхода - используя расширения и пометить их с помощью // MARK. – Deny

Смежные вопросы