SwiftのProtocol指向の実装例

# はじめに
いまプロトコル指向で実装するのが流行りということでどういうのか調べていましたが、WWDCの動画だと自分には難しかったので、ちょうどわかりやすい例がはてブにでていたので訳してみました

* 元の記事：https://medium.com/@gonzalezreal/ios-cell-registration-reusing-with-swift-protocol-extensions-and-generics-c5ac4fb5b75e#.1v64g8b2p

* gistもあった♥
https://gist.github.com/gonzalezreal/92507b53d2b1e267d49a

以下翻訳
---

# Swiftのプロトコル拡張とジェネリクスを使ってiOSのセルの登録と再利用する
A common task when developing iOS apps is to register custom cell subclasses for both `UITableView` and `UICollectionView`. Well, that is if you don’t use Storyboards, of course.
iOSアプリを開発している時によくあるタスクとして、Storyboardを使わないのであれば、'UITableView'や
'UICollectionView'のためにカスタムセルサブクラスを実装する

Both `UITableView` and `UICollectionView` offer a similar API to register custom cell classes:
`UITableView`や`UICollectionView`は似たようなカスタムセルクラスの登録APIを提供している

```swift
public func registerClass(cellClass: AnyClass?, forCellWithReuseIdentifier identifier: String)
public func registerNib(nib: UINib?, forCellWithReuseIdentifier identifier: String)
```

A widely accepted solution to handle cell registration and dequeuing is to declare a constant for the reuse identifier:
広く受け入れられた解決方法はreuseIdentifierを宣言してセルの登録処理とdequeuingを実装する

```swift
private let reuseIdentifier = "BookCell"

class BookListViewController: UIViewController, UICollectionViewDataSource {

    @IBOutlet private weak var collectionView: UICollectionView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let nib = UINib(nibName: "BookCell", bundle: nil)
        self.collectionView.registerNib(nib, forCellWithReuseIdentifier: reuseIdentifier)
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath)
    
        if let bookCell = cell as? BookCell {
            // TODO: configure cell
        }
    
        return cell
    }
}
```

Let’s try to generalize this code and make it simpler and safe.
じゃあこのコードをより単純に安全にしてみよう！

First of all, it would be nice to get away with declaring a constant for every reuse identifier in our app. We can just use the name of the custom cell class as a **default reuse identifier**.
We can create a **protocol for Reusable Views** and provide a default implementation constrained to `UIView` subclasses.
まず、アプリ内でいちいちreuseIdentifierを宣言するのをやめるのがよさそうだ。
私たちは**デフォルトのreuseIdentifier**としてカスタムセルのクラス名を使うことにする。
なので**再利用できるViewのためのプロトコル**を作って、UIViewのサブクラスに強制的にその機能を提供することができる

```swift
protocol ReusableView: class {
    static var defaultReuseIdentifier: String { get }
}

extension ReusableView where Self: UIView {
    static var defaultReuseIdentifier: String {
        return NSStringFromClass(self)
    }
}

extension UICollectionViewCell: ReusableView {
}
```

By making `UICollectionViewCell` conform to the `ReusableView` protocol, we get a unique reuse identifier per cell subclass.
UICollectionViewCellは`ReuseableView`プロトコルに従うことによって、それぞれのセルのサブクラスから固有のreuseIdentifierを取得することができる

```swift
let identifier = BookCell.defaultReuseIdentifier
// identifier = "MyModule.BookCell"
```

Next, we can get rid of the hard-coded string we are using to load the Nib.
次に、Nibを読み込むためにハードコードしてる文字列を取り除くことができる

Let’s create a protocol for **Nib Loadable Views** and provide a default implementation using protocol extensions.
じゃあ**Nibを読み込むためのViews**ためのプロコトルを作って、プロトコル拡張を使ってその機能を提供できるようにしよう！

```swift
protocol NibLoadableView: class {
    static var nibName: String { get }
}

extension NibLoadableView where Self: UIView {
    static var nibName: String {
        return NSStringFromClass(self).componentsSeparatedByString(".").last!
    }
}

extension BookCell: NibLoadableView {
}
```

By making our `BookCell` class conform to the `NibLoadableView` protocol we now have a safer way to get the Nib name.
この`BookCell`クラスは`NibLoadeableView`に従うことで、より安全にNibの名前を手に入れることができる

```swift
let nibName = BookCell.nibName
// nibName = "BookCell"
```

If you use a different name for the XIB file than the one provided by Xcode, you can always override the default implementation of the nibName property.
Xcodeから提供されたXIBファイルに違う名前を使いたいなら、いつでも`nibName`プロパティの機能をオーバーライドできる

With these two protocols in place, we can use **Swift Generics** and extend `UICollectionView` to simplify cell registration and dequeuing.

この2つのプロトコルを使って、セルの登録処理とdequeuingを`UICollectionView`を簡単に拡張し、**Swiftジェネリクス**を使える

```swift
extension UICollectionView {
    
    func register<T: UICollectionViewCell where T: ReusableView>(_: T.Type) {
        registerClass(T.self, forCellWithReuseIdentifier: T.defaultReuseIdentifier)
    }
    
    func register<T: UICollectionViewCell where T: ReusableView, T: NibLoadableView>(_: T.Type) {
        let bundle = NSBundle(forClass: T.self)
        let nib = UINib(nibName: T.nibName, bundle: bundle)
        
        registerNib(nib, forCellWithReuseIdentifier: T.defaultReuseIdentifier)
    }
    
    func dequeueReusableCell<T: UICollectionViewCell where T: ReusableView>(forIndexPath indexPath: NSIndexPath) -> T {
        guard let cell = dequeueReusableCellWithReuseIdentifier(T.defaultReuseIdentifier, forIndexPath: indexPath) as? T else {
            fatalError("Could not dequeue cell with identifier: \(T.defaultReuseIdentifier)")
        }
        
        return cell
    }    
}
```

Notice that we created two versions of the register method, one for cell subclasses implementing just `ReusableView` and another one for cell subclasses implementing both `ReusableView` and `NibLoadableView`. This nicely decouples the view controller from the specific cell registration method.
登録メソッドの２つのバージョンを作ってみて、セルのサブクラスの実装の１つは単に`ReusableView`を実装しているもの、もう片方が`ReusableView`と`NibLoadableView`の2つを実装してるものがあることに気づく。
これは特定のセルの登録メソッドからViewControllerをうまく分離している

Another nice detail is that the `dequeueReusableCell` method doesn’t need to take any reuse identifier and uses the cell subclass type for the return value.
ほかにも`dequeueReusableCell`メソッドはreuseIdentifierをとる必要がなく、セルのサブクラスの返り値を使っているのはいいdetailだ

Now the cell registration and dequeuing code looks much better :).
セルの登録処理とdequeuingはいまや見違えるようだ( ･`ω･´)

```swift
class BookListViewController: UIViewController, UICollectionViewDataSource {

    @IBOutlet private weak var collectionView: UICollectionView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.collectionView.register(BookCell.self)
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        
        let cell: BookCell = collectionView.dequeueReusableCell(forIndexPath: indexPath)
        
        // TODO: configure cell
    
        return cell
    }
    ...
}
```

## Conclusion
If you are coming from Objective-C it is worth to investigate powerful Swift features like Protocol Extensions and Generics to find alternate and more elegant ways to deal with Cocoa classes.

##最後に
もし君がObjective-Cから来たのであれば、SwiftのすばらしくパワフルなProtocolやGenericsといった機能を調べたり、違いを見つけたり、Cocoaクラスによりエレガントな方法を適用するのは有意義だろう

---
以上翻訳
### 圧倒的感謝 :v::sob: :v: