UIViewのサブクラスによってmasksToBoundsの初期値が異なる

UIViewのサブクラスはCALayerクラスをもっています。そんなCALayerのmasksToBoundsのプロパティの初期値がUIViewのサブクラスによって異なっていたので共有したいと思います。


# masksToBounds
まず、masksToBoundsプロパティの説明ですが、CALayer Class Referenceによると下記のように記述してあります。

>When the value of this property is true, Core Animation creates an implicit clipping mask that matches the bounds of the layer and includes any corner radius effects. If a value for the mask property is also specified, the two masks are multiplied to get the final mask value.

>The default value of this property is false.

[CALayer Class Reference参照](https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CALayer_class/#//apple_ref/occ/instp/CALayer/masksToBounds)

つまりmasksToBoundsがtrueの場合はコンテンツのサブレイヤの境界矩形外に描画処理はされないようですね。CALayer Class Referenceによると初期値は**false**とされています。

## 使用例
```Swift
        let view  = UIView(frame: CGRectMake(0, 0, 200, 50))
        view.backgroundColor = UIColor.lightGrayColor()
        view.layer.masksToBounds = false
        self.view.addSubview(view)
        
        let label = UILabel(frame: CGRectMake(0, 0, 300, 50))
        label.text = "masksToBounds Test by Shohei"
        self.view.addSubview(label)
```
masksToBoundsがfalseの状態だとUILabelがUIViewをはみだしてもしっかり描画されていますね。

<img width="375" alt="スクリーンショット 2015-12-19 15.51.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/62451/945e999b-570c-4172-c33a-2eee6d6e0f6f.png">

この状態でmasksToBoundsをtrueにしてあげると、下の図のようにUIViewの境界矩形外は描画されなくなります。

<img width="375" alt="スクリーンショット 2015-12-19 15.50.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/62451/0d5c5be9-071c-fdd4-242d-43e06b739145.png">

つまりmasksToBoundsをtrueの状態だと影の描画などもされなくなるんですね。


# masksToBoundsの初期値の違いについて
CALayer Class ReferenceではmasksToBoundsの初期値はfalseとされていましたが、UIViewのサブクラスによって初期値は異なるようです。

## ウィンドウ系
```Swift
        let window = UIWindow()//デバイスの画面上の最下層のビュー
        print(window.layer.masksToBounds)// ->false
```

## コンテンツ表示系
```Swift
        let label = UILabel()//テキスト表示
        print(label.layer.masksToBounds)// ->false
        
        let textView = UITextView()//テキストの表示・編集
        print(textView.layer.masksToBounds)// ->true
        
        let imageView = UIImageView()//画像表示
        print(imageView.layer.masksToBounds)// ->false
        
        let scrollView = UIScrollView()//スクロール可能なビュー
        print(scrollView.layer.masksToBounds)// ->true
        
        let webView = UIWebView()//ウェブコンテンツ表示
        print(webView.layer.masksToBounds)// ->false
        
        let progressView = UIProgressView()//進捗の表示
        print(progressView.layer.masksToBounds)// ->false
        
        let activityIndicatorView = UIActivityIndicatorView()//処理中を示すビュー
        print(activityIndicatorView.layer.masksToBounds)// ->false
        
        let actionSheet = UIActionSheet()//アクション表示(iOS8.3からはUIAlertController推奨)
        print(actionSheet.layer.masksToBounds)// ->false
        
        let alertView = UIAlertView()//アラート表示のためのポップアップ
        print(alertView.layer.masksToBounds)// ->false
        
        let pickerView = UIPickerView()//選択肢の表示と選択
        print(pickerView.layer.masksToBounds)// ->true
```
## データコレクション表示系
```swift
        let tableView = UITableView()//縦方向にセルを表示
        print(tableView.layer.masksToBounds)// ->true
        
        let collectionView = UICollectionView()//任意のレイアウトでセル表示
        print(collectionView.layer.masksToBounds)// ->true
```
## UIコントロール系
```swift        
        let control = UIControl()//UIコントロール共通のスーパークラス
        print(control.layer.masksToBounds)// ->false
        
        let button = UIButton()//ボタン
        print(button.layer.masksToBounds)// ->false
        
        let textField = UITextField()//テキストの表示・編集
        print(textField.layer.masksToBounds)// ->true
        
        let switch = UISwitch()//オン・オフスイッチ
        print(switch.layer.masksToBounds)// ->false
        
        let segmentedControl = UISegmentedControl()//セグメントによる選択肢表示
        print(segmentedControl.layer.masksToBounds)// ->false
        
        let stepper = UIStepper()//段階式値の加算・減算
        print(stepper.layer.masksToBounds)// ->false
        
        let slider = UISlider()//スライダー
        print(slider.layer.masksToBounds)// ->false
        
        let datePicker = UIDatePicker()//日付・時刻のピッカー
        print(datePicker.layer.masksToBounds)// ->false
        
        let refreshControl = UIRefreshControl()//更新コントロール
        print(refreshControl.layer.masksToBounds)// ->false
        
        let pageControl = UIPageControl()//ページ表示
        print(pageControl.layer.masksToBounds)// ->false
```
## タブバー系 
```swift          
        let tabBar = UITabBar()//タブバー
        print(tabBar.layer.masksToBounds)// ->false
        
        let navigationBar = UINavigationBar()//ナビゲーションバー
        print(navigationBar.layer.masksToBounds)// ->false
        
        let toolbar = UIToolbar()//ツールバー
        print(toolbar.layer.masksToBounds)// ->false
        
        let searchBar = UISearchBar()//検索バー
        print(searchBar.layer.masksToBounds)// ->false
```

## masksToBoundsの初期値が異なるUIViewサブクラス
- UITextView
- UIScrollView
- UIPickerView
- UITableView
- UICollectionView
- UITextField

これらのクラスはmasksToBoundsの初期値がtrueになっていますね。
よってサブビューのコンテンツをはみだして表示したい場合や影の描画をする場合は**masksToBoundsをfalseにする**必要があります

# 最後に
masksToBoundsの初期値がtrueになってるということは、境界矩形外の描画は推奨されていないと思いますが、クラスによる初期値の違いは理解しておく必要があると思います。
他にもプロパティの初期値がクラスによって異なる場合はあると思いますので、知っておくとバグの早期発見などにも役立つと思います。