Swift and using class extension
Asked Answered
E

2

14

I don't understand why programmers use the extension keyword in their class implementation. You can read in other topics that code is then more semantically separated and etc. But when I work with my own code, it feels clearer to me to use // MARK - Something. Then when you use methods list (ctrl+6) in Xcode, everything is seen at first look.

In Apple documentation you can read:

“Extensions add new functionality to an existing class, structure, or enumeration type.”

So why not write my own code directly inside my own class? Unlike when I want to extend functionality of some foreign class, like NSURLSession or Dictionary, where you have to use extensions.

Mattt Thompson use extension in his Alamofire library, maybe he can give me little explanation, why he chose this approach.

Entrechat answered 6/2, 2015 at 14:27 Comment(1)
Use whichever you prefer, but the extension makes it more explicit than mere MARK:, clearly designating where it starts and where it ends. Frankly, it's not an either/or issue, as I will use both MARK: and an extension. Another advantage of extension is that you can easily fold that code (e.g. "Editor" - "Code Folding..." - "Fold" or clicking in shaded left margin).Fantom
E
14

For me it seems completely reasonable since you can use extensions to expose different parts of logic to different extensions. This can also be used to make class conformance to protocols more readable, for instance

class ViewController: UIViewController {
...
}

extension ViewController: UITableViewDelegate {
...
}

extension ViewController: UITableViewDataSource {
...
}

extension ViewController: UITextFieldDelegate {
...
}

Protocol methods are separated in different extensions for clarity, this seems to be far better to read than lets say:

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

So, I'd say there's no harm in using extensions to make your own code more readable, not just to extend already existing classes from SDK. Using extensions you can avoid having huge chunks of code in your controllers and split functionality into easily readable parts, so there's no disadvantage of using those.

Edger answered 6/2, 2015 at 14:51 Comment(4)
And what for NSCoding protocol? You can't use extension for this protocol.Entrechat
This is where it gets tricky, extensions can't add designated initializers, therefore NSCoding's init(coder:) is not supposed to be implemented via extensions, not so sure myself.Edger
Doesn't work if you need to access anything private from the class you're extending, does it? Or am I missing something?Thaddeus
Exactly, this is new in Swift 3. You need to use fileprivate keyword to access stuff in extensions (if you have those extension in the same file, obviously). In previous swift versions private meant private for the file by default.Edger
K
7

Using extensions allows you to keep your declaration of protocol conformance next to the methods that implement that protocol.

If there were no extensions, imagine declaring your type as:

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 this with using extensions, where you bundle together the implementation of the protocols with those specific methods that implement it:

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.
    }
}

Yes, you can mark your protocol implementations with // MARK (and bear in mind, you can combine both techniques), but you would still be split across the top of the file, where the declaration of protocol support would be, and the body of the file, where your implementation is.

Also, bear in mind if you’re implementing a protocol, you will get helpful (if slightly verbose) feedback from the IDE as you go, telling you what you’ve got left to implement. Using extensions to do each protocol one by one makes it (for me) far easier than doing it all in one go (or hopping back and forth from top to bottom as you add them).

Given this, it’s then natural to group other, non-protocol but related methods into extensions as well.

I actually find it frustrating occasionally when you can’t do this. For example,

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
        }
    }
}

So you have to implement both within the same extension.

Kalisz answered 6/2, 2015 at 14:53 Comment(3)
Ok, so when you have your class source code few pages long, you don't see which protocols that class implements. You must search this information through the code. For me is this not clearer than using // MARK in code.Entrechat
Horses for courses, but I’d say using the language rather than comments to indicate intent is clearer. Also see my edit, it makes implementing the protocols as you go easier in my experience.Kalisz
Thank you for your opinion. I will try to combine both approaches - using extensions and mark them with // MARK.Entrechat

© 2022 - 2024 — McMap. All rights reserved.