Storyboardを極力使わずSwiftでGithubのissuesとpull requestsを一覧で見れるアプリ作る


業務で扱うGithubのリポジトリが20個くらいあってどこにissuesがあってどのpull requestsを見ていないかがわちゃわちゃしています。
なので管理したいなと、swiftでアプリ作ってます。

今回はSwiftに触れてみたいという思いなのでStoryboardは極力使わずコードのみという異端な方法で作っています。
Storyboardでできることをコードで書くのでコードが増えたり見通しが悪くなるのでどうやってるかとswiftで困ったことをまとめます。
個人的にはStoryboardがそれほど好きではないので、コードやplaygroundをうまく使いたい派です。Storyboard便利なんですけどね。

（こんなの）
![写真 2015-04-02 23 18 46.png](https://qiita-image-store.s3.amazonaws.com/0/47431/c438b263-7a1a-b627-95ff-ea4914383805.png "写真 2015-04-02 23 18 46.png")

個人でもしくわチーム内で使えばいいアプリなのでリリースするつもりはなくTest Flightで配布します。
[bonegollira/GitOdo](https://github.com/bonegollira/GitOdo)

さて、気にしているポイントですが


## Viewとロジックを分ける

Storyboardを使わないとViewのプロパティの設定とロジックがごっちゃになるので`extension`を使って分けます

```
protocol ViewComponentLayout {
  func render ()
}

// Viewに関するコード
// funcは基本的にconfigure__***とautolayout__***の2種類
extension TableHeaderView: ViewComponentLayout {
  
  // configure__***でプロパティのセット
  func configure__self () {
    self.contentView.backgroundColor = UIColor.whiteColor()
  }
  
  func configure__titleLabel () {
    self.titleLabel.font = UIFont(name: "Helvetica-Bold", size: 12)
    self.titleLabel.textColor = UIColor.blackColor()
    self.titleLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
  }
  
  // autolayout__***でautolayoutの設定
  // Cartographyを使ってます
  func autolayout__titleLabel () {
    layout(self.titleLabel) { titleLabel in
      titleLabel.left == (titleLabel.superview!.left + 20) ~ 250
      titleLabel.right == (titleLabel.superview!.right - 20) ~ 250
      titleLabel.bottom == titleLabel.superview!.bottom - 5
    }
  }
  
  // このview自体はaddSubviewせずrenderを呼ぶ
  // addSubview、configure、autolayoutを設定
  func render () {
    self.contentView.addSubview(self.titleLabel)
    self.configure__titleLabel()
    self.autolayout__titleLabel()
  }
  
}

// ロジックのコード

class TableHeaderView: UITableViewHeaderFooterView {
  
  class var identifier: String {
    return "TableHeaderView"
  }
  
  // viewパーツの初期化はこちらで
  let titleLabel = UILabel()
  
  var sectionName: String? {
    get {
      return self.titleLabel.text
    }
    set {
      self.titleLabel.text = newValue
    }
  }
  
  required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
  }
  
  override init(frame: CGRect) {
    super.init(frame: frame)
  }
  
  override init(reuseIdentifier: String?) {
    super.init(reuseIdentifier: reuseIdentifier)
    self.render()
  }
  
}
```

と書いて

- `extension`でStoryboardでできたViewの設定を
- `class`でロジックを

書いてます。
ただStoryboardの強みである

- `ViewController`同士のつながり
- Viewの確認

の良さげなやり方が分かっていません。


## エラーですぎワロタ

ぶちあたったエラー書いとく、swift関係なくてもだ

### SourceKitクラッシュしまくり

orz

### CocoaPodsでライブラリ入れられないん？
Swiftで書かれたライブラリのサポートはCocoaPodsのバージョン0.36かららしい
使っていたバージョンが0.35だったためアップデートで回避
http://www.infoq.com/jp/news/2015/01/cocoapods-adds-swift-framework

### Dictionaryにnilいれらないん？
いれるなら`NSNull()`な

### @selectorってどうやって書くん？
```
UIBarButtonItem(
  barButtonSystemItem: .Add,
  target: self,
  action: "someMethod:"
)
```
とStringで書けばいい

### クラスメソッドどうやるん？
```
class Class {
  class func classMethod () {
    // do something...
  }
}
```

### クラス変数どうやるん？
```
  // getを省略してるで
  class var identifier: String {
    return "tableViewCell"
  }
```
http://qiita.com/takkyun/items/384013e52f404773893b
にプロパティについて詳しくまとめてくださっています。

### カスタムUITableViewCellでinit実装で文句言われるで？
```
  override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
  }
  
  // を実装すると
  
  required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
  }
  
  // を求められる
```
と`required`で実装しないとエラーがでる。これ書いたら動くから原因はわかってません。

### 型宣言だけした空のDictionaryを作っておきたいで？
OptionalつけるとアンラップだらけになってややこしいのでArrayとDictionaryに関しては極力空の値をいれて初期化しておきたい。

```
  // こっちをしたくない
  var list: [String: String]?
  // けどこうするとエラー
  var list: [String: String] = []
  
  // なのでこうする
  let list = [String: String]()
```

#### 追記
@akuraruさんに教えていただきました。

```
  var list: [String: String] = [:]
```
でいける。


### UITableViewDataSource実装してるで？

`does not conform to protocol 'UITableViewDataSource'`
と言われるのは`UITableViewDataSource`のrequireメソッドを定義していないから。
swiftのバージョンがあがって？引数のOptional指定が変更になってたりして、web上にある古い`UITableViewDataSource`のメソッドをコピペとかしたりしてると実装しているつもりでもエラーがでる。
ちゃんと

```
  func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  }
  
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
  }
```

を補完で打ち込もう。
ちなみに僕はタイポでエラー言われてた。

### 省略形の3項演算子使えんのん？
`:?`は使えないみたい
`let str = nil :? "string"`と書けない

#### 追記
@YoshimasaAokiさんに教えていただきました。
`let str = nil ?? "string"`
と`??`でいける

### didSet定義したやつ、init内で初期化しても呼ばれんのん？
```
  // init内で初期化してもdidSetは呼ばれない
  var prop: Bool {
    didSet {
      println(prop)
      println(oldValue)
    }
  }
  
  override init () {
    // init内でセットしてもdidSetは呼ばれない
    self.prop = true
    super.init()
```

### マクロどう定義するん？

```
public func rgba(r: Int, g: Int, b: Int, a: CGFloat = 1.0) -> UIColor {
  let red = CGFloat(r)
  let green = CGFloat(g)
  let blue = CGFloat(b)
  return UIColor(
    red: CGFloat(red / 255),
    green: CGFloat(green / 255),
    blue: CGFloat(blue / 255),
    alpha: a
  )
}
```

### SwiftってRefactor使えないん？
使えない

### Autolayoutの設定のタイミングってどこが適切？
`init`で全部`NSConstraint`をつけてるけど本来はどのタイミングがいいのか？

### initの実装でrequired求められるで？

```
  required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
  }
```

を書けば許されるけどなんでなん？