【第４回】Swiftアプリ開発チュートリアル -Food Tracker- のお供に（Implement a Custom Control 編）

# はじめに

AppleのSwiftアプリ開発チュートリアルを進めていて出てきた関数やクラスなどについて、調べたことを残していきます。
チュートリアルを進めながら、**ざっくりと**どういうものかを把握するためのお供になればと思います。

初学者のため、間違い等あればご指摘ください。 :bow: 

第１回：[Swiftアプリ開発チュートリアル -Food Tracker- のお供に（Build a Basic UI 編）](http://qiita.com/taji-taji/items/9202d944bf403957a22e)
第２回：[Swiftアプリ開発チュートリアル -Food Tracker- のお供に（Connect the UI to Code 編）](http://qiita.com/taji-taji/items/da3b800914fa3313d5a8)
第３回：[Swiftアプリ開発チュートリアル -Food Tracker- のお供に（Work with View Controllers 編）](http://qiita.com/taji-taji/items/a3a103b949bb7694c8b3)
第４回：Swiftアプリ開発チュートリアル -Food Tracker- のお供に（Implement a Custom Control 編）←今回はここ
第５回：[Swiftアプリ開発チュートリアル -Food Tracker- のお供に（Define Your Data Model 編）](http://qiita.com/taji-taji/items/2f2c4367752a839e8fb7)

# チュートリアルページ
https://developer.apple.com/library/prerelease/ios/referencelibrary/GettingStarted/DevelopiOSAppsSwift/Lesson2.html#//apple_ref/doc/uid/TP40015214-CH5-SW1

以下のような構成でレッスンが進んでいくので、それに沿って進めていきます。

- Building the UI
 - Build a Basic UI
 - Connect the UI to Code
 - Work with View Controllers
 - **Implement a Custom Control**（今回はここ）
 - Define Your Data Model
- Working with Table Views
 - Create a Table View
 - Implement Navigation
 - Implement Edit and Delete Behavior
 - Persist Data


# Implement a Custom Control

今回は以下のレッスンで出てきたものについて見ていきます。

https://developer.apple.com/library/prerelease/ios/referencelibrary/GettingStarted/DevelopiOSAppsSwift/Lesson5.html#//apple_ref/doc/uid/TP40015214-CH19-SW1


## ■ UIView

画面表示とその領域内のコンテンツを管理するクラス。
チュートリアルでは、rating部分をカスタムビューとして切り分ける際に使用している。

### チュートリアルでの使用例

```swift:RatingControl.swift
import UIKit
 
class RatingControl: UIView {
    
}
```

### ドキュメント

- 公式  
[UIView Class Reference](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIView_Class/)


## ■ init?(coder aDecoder: NSCoder)

UIViewのサブクラスでオーバーライドする必要があるinitializer。
`Interface Builder`からそのビューを呼び出す場合に使用する。
`Interface Builder`でビューを構築しない場合はinitializerとして`init(frame frame: CGRect)`をオーバーライドする。


### チュートリアルでの使用例

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

### ドキュメント

- 公式  
[init(coder:) - NSCoding Protocol Reference](https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Reference/Foundation/Protocols/NSCoding_Protocol/index.html#//apple_ref/occ/intfm/NSCoding/initWithCoder:)



## ■ intrinsicContentSize

ビューのサイズを指定して返し、それをレイアウトシステムに伝える役割を果たすメソッド。

### チュートリアルでの使用例

```swift:RatingControl.swift
override func intrinsicContentSize() -> CGSize {
    return CGSize(width: 240, height: 44)
}
```

### ドキュメント

- 公式  
[intrinsicContentSize() - UIView Class Reference](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIView_Class/index.html#//apple_ref/occ/instm/UIView/intrinsicContentSize)


## ■ addTarget

UIControlクラスにて定義されているメソッド。
特定のイベントが起こった時に指定したターゲットに対して、指定したアクションを起こすことができる。

チュートリアルでは、ボタンがタップ（TouchDown）された時、自身（self）の `ratingButtonTapped`を起動している。


### チュートリアルでの使用例

```swift:RatingControl.swift
button.addTarget(self, action: "ratingButtonTapped:", forControlEvents: .TouchDown)
```

### ドキュメント

- 公式  
[addTarget(_:action:forControlEvents:) - UIControl Class Reference](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIControl_Class/#//apple_ref/occ/instm/UIControl/addTarget:action:forControlEvents:)


## ■ layoutSubviews()

`UIView`クラスのメソッド。
この中にサブビューのレイアウト処理を書くことで`view`の状態に合わせて必要な時にレイアウト処理が行われる。


### チュートリアルでの使用例

```swift:RatingControl.swift
override func layoutSubviews() {
    var buttonFrame = CGRect(x: 0, y: 0, width: 44, height: 44)
    
    // Offset each button's origin by the length of the button plus spacing.
    for (index, button) in ratingButtons.enumerate() {
        buttonFrame.origin.x = CGFloat(index * (44 + 5))
        button.frame = buttonFrame
    }
}
```

### ドキュメント

- 公式
[layoutSubviews() - UIView Class Reference](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instm/UIView/layoutSubviews)

- 参考
http://qiita.com/nori0620/items/f2e6aef9cac3a8c9e366


## ■ enumerate()

Swiftの標準関数。
配列からそれぞれのインデックスと値を持つタプルをkタプルを返す。


### チュートリアルでの使用例

```swift:RatingControl.swift
for (index, button) in ratingButtons.enumerate() {
    buttonFrame.origin.x = CGFloat(index * (44 + 5))
    button.frame = buttonFrame
}
```

### ドキュメント

- 公式  
[The Swift Programming Language (Swift 2.1): Collection Types](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html)  
http://swift-studying.com/blog/swift/?p=142


## ■ setImage(_:forState:)

`UIButton`クラスのメソッド。
ボタンの見た目として独自に用意した画像を使用することができる。
`forState`でボタンがどういう状態の時の画像かが設定できるため、
ボタンの状態によって画像を変更することが可能。

状態を表す`UIControlState`は[こちら](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIControl_Class/index.html#//apple_ref/c/tdef/UIControlState)。

### チュートリアルでの使用例

```swift:RatingControl.swift
button.setImage(emptyStarImage, forState: .Normal)
button.setImage(filledStarImage, forState: .Selected)
button.setImage(filledStarImage, forState: [.Highlighted, .Selected])
```

### ドキュメント

- 公式  
[setImage(_:forState:) - UIButton Class Reference](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIButton_Class/#//apple_ref/occ/instm/UIButton/setImage:forState:)


## ■ adjustsImageWhenHighlighted

`UIButton`クラスのプロパティ。
ボタン画像がHighlightedの状態になった時に画像を変更するかどうかの真偽値。


### チュートリアルでの使用例

```swift:RatingControl.swift
button.adjustsImageWhenHighlighted = false
```

### ドキュメント

- 公式  
[adjustsImageWhenHighlighted - UIButton Class Reference](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIButton_Class/#//apple_ref/occ/instp/UIButton/adjustsImageWhenHighlighted)


## ■ indexOf

配列や辞書の中の値を渡すことでその値のインデックスを返す。


### チュートリアルでの使用例

```swift:RatingControl.swift
rating = ratingButtons.indexOf(button)! + 1
```
タップされたボタンのインデックス+1を`rating`の値にしている。


### ドキュメント

- 公式  
[indexOf(_: Self.Generator.Element) -> Self.Index? - CollectionType Protocol Reference](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_CollectionType_Protocol/#//apple_ref/swift/intfm/CollectionType/s:FeRq_Ss14CollectionTypeqqq_S_9GeneratorSs13GeneratorType7ElementSs9Equatable_SsS_7indexOfuRq_S_qqq_S_9GeneratorS0_7ElementS1__Fq_Fqqq_S_9GeneratorS0_7ElementGSqqq_Ss9Indexable5Index_)


## ■ didSet

**プロパティ監視**。
プロパティに設定することでプロパティの値が変わった後に起こる処理を書くことができる。

同様にプロパティの値が変わる前に起こる処理を書く場合は`willSet`を使う。


### チュートリアルでの使用例

```swift:RatingControl.swift
var rating = 0 {
didSet {
    setNeedsLayout()
}
}
```

### ドキュメント

- 公式  
[The Swift Programming Language (Swift 2.1): Declarations](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html)


## ■ setNeedsLayout()

layoutSubviews()を呼び出し、レイアウトを更新する。


### チュートリアルでの使用例

```swift:RatingControl.swift
var rating = 0 {
    didSet {
        setNeedsLayout()
    }
}
```

### ドキュメント

- 公式  
[setNeedsLayout() - UIView Class Reference](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instm/UIView/setNeedsLayout)


---



# 参考サイト
http://qiita.com/nori0620/items/f2e6aef9cac3a8c9e366


# 次回レッスン
第５回：[Swiftアプリ開発チュートリアル -Food Tracker- のお供に（Define Your Data Model 編）](http://qiita.com/taji-taji/items/2f2c4367752a839e8fb7)