Android から Swift へ

## Java vs Swift

| Java | Swift |
|:-----------|:------------|
| import package.hoge | import framework |
| class Xyz extends SomeClass | class Xyz : SomeClass |
| interface Abc  |  protocol Abc |
| class Xyz extends Someclass implements Abc | class Xyz: SomeClass, Abc |
| int mProperty; | var mProperty: Int |
| Xyz() // constructor | init() |
| Xyz obj = new Xyz() | var obj: Xyz = Xyz() |
| void doWork(String srg) | func doWork(arg: String) -> Void  |
| obj.doWork(arg); | obj.doWork(arg) |

## Playground
Ruby でいう irb. Swift の実験に使える

## Variable & Constants
- var 変数
- let 定数

型を明示的に宣言する必要は無い。コンパイラが推測する

`var mProperty = ""`

### Optional 
その型になれたらなる.　なれなかったら、nilが代入される.
OptionalはSwiftをよりタイプセーフで丈夫にする.

```
var intStr = "123" // "str"
var myInt:Int? = intStr.toInt() //nilが入ることもある
```

Optional型を非Optional型と同じようには扱えない。演算とかしようとするとランタイムエラー。  
-> そのため、これをunwrap する必要がある。

1. Froce Unwrap.  `unwrapped!.call()` 呼び出し前に ! を付与. もしnilならランタイムエラー
1. Optional Chaining. `unwrapped?.call()` 呼び出し前に ? を付与. もしnilならnilが返る
1. Optional Binding. if 文とかに入れて自動的にアンラップする

## Method
特徴

- 複数の値を返すことができる
- デフォルトパラメータ名。オーバーロードを簡単に
- Arrayを使わない可変引数
- 引数に関数 (クロージャ)

## Class
### 値渡しと参照渡し
- 独自クラスは参照渡し。 プリミティブ、struct, enum は値渡し
- Javaと違い、String, Array, Dictionary などは値渡し。
- NSString, NSDictionary, NSArray などは参照渡し


## StoryBoard, ViewController

| Android | iOS |
|:-----------|:------------|
|RelativeLayout |AutoLayout, Constraints|
|layout-land, portrait| Size Classes|
|setContentView |StoryBoard内のViewController選択|
|findViewByIdからのsetOnXXXListener|IBOutletでfindView, IBActionでonClick|
| LifyCycle onCreate, onCreateView| viewDidLoad() |
|onStart|viewWillApear|
|onResume|viewDidAppear|
|onPause |viewWillDisappear |
|onStop|viewDidDisappear|

IBOutlet・・StoryBoardのWidgetへ繋げるプロパティ
IBAction・・Widgetのイベントが発生した時に呼ばれるメソッド

## Segue
Segue・・一つのシーンから他への遷移を指定するためのConnectionタイプ
Action Segue ・・ Connection Inspector より対象ボタンのSegueを指定するだけ
Manual Segue・・上記アクションにさらにTouchDownリスナをを登録し、SegueにIdentifierを付ける。ViewController内でperformSegueWithIdentifierを呼ぶ.

### データ付きSegue
元クラスで

```
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    var identifier = segue.identifier
    var destVc = (segue.destinationViewController as PresentedViewController)
    destVc.data = "some data from presented vc: \(identifier)"
}
```
受け取りクラスで

```
var data: String?
override func viewDidLoad() {
    if let tmp = data {
        println("received data: \(tmp)")
    }
}

``` 

### 戻るボタンの実装
NavigationController を RootView にセットするだけ。自動でBackが付与される


## Master/Detail なList

StoryBoard に TableViewController を追加

### UITableViewControllerを使った時の基本雛形

```
import UIKit

class MasterTableViewController: UITableViewController {
    var items = ["item1", "item2", "item3"]
    
    // テーブル数のカウント. 初期化
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items.count
    }
    
    // 各行のViewをセット
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCellWithIdentifier("mycell") as UITableViewCell
        cell.textLabel.text = self.items[indexPath.row]
        return cell
    }
    
    // 各業をタップした際の挙動
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        self.performSegueWithIdentifier("detail", sender: indexPath.row)
    }
    
    // Detail へ遷移するSegueの定義
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        var destVC = segue.destinationViewController as UIViewController
        destVC.navigationItem.title = self.items[sender as Int]
    }

    // Bar Button Item 選択時のIBAction
    @IBAction func doAdd(sender: AnyObject) {
        self.items.append("item\(self.items.count + 1)")
        self.tableView.reloadData()
    }
}
```

- TableView の Cell に identifier を追加
- Detailへ行く Segue に detail を追加
- NavigationControllerをXCodeのEditorからEmbed in する
- TableView の Navigation Item にBarButtonItemを追加

### ViewControllerでUITableViewを使った時の基本雛形

- StoryBoard内でViewController へ TableView の datasource, delegate をそれぞれ登録
- UITableViewController ではなく、通常のViewControllerを継承
- UITableViewDataSource, UITableViewDelegate を impelemnt
- 上記と同じ処理を記述


## Tab Bar Controller

- 2つのViewControllerを作成
- Tab Bar ControllerをSotryBoard上で生成
- Command キーでViewControllerを複数指定し、Editor -> Embed in -> Tab Bar Controller

## Alert
ボタン押した時にアラートを出す

```
    var alert = UIAlertController(title:"My title", message: "My message", preferredStyle: UIAlertControllerStyle.Alert)
    var actionCancel = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: {action in
        // do nothing
    })
    var actionOk = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: {action in
        println((alert.textFields![0] as UITextField).text)
    })
    alert.addAction(actionCancel)
    alert.addAction(actionOk)
    alert.addTextFieldWithConfigurationHandler({textField in
        textField.backgroundColor = UIColor.yellowColor()
        textField.placeholder = "enter text, i.e., Do Ra Me"
    })
    self.presentViewController(alert,animated: true, completion: nil)
```

独自Viewのアラートを作る場合はNavigationにくるんだViewControllerを生成し,  
そのSegueをPresent as Popover として選択し, Anchorを起動元のボタンにセットする

```
    self.performSegueWithIdentifier("mypopover", sender: nil)
```

## Application Resource
[Makeappicon](http://makeappicon.com/) で一括で各サイズのアイコンを生成した方が良さそう。

その他画像サイズはベースからx2, x3 のものも突っ込んでおけばいいみたい。

## Localize 文字列
Supporting Files に Localizable.strings を作ってkey=value形式で保存

```
"app_name"="Hello iPhone";
```

コード上で

```
NSLocalizedString("app_name", comment: "")
```

## Text Field
リターンを押したらキーボードを閉じる

StoryBoard のText Field の Outlets, delegate をViewControllerにセット

```
class ViewController: UIViewController, UITextFieldDelegate {
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
}
``` 

## Action Sheet
複数選択ダイアログ的な使い方が可能

```
    var actionSheet = UIAlertController(title: "Action (from bar button item)", message: "Choose an Action", preferredStyle: UIAlertControllerStyle.ActionSheet)
    var actionCancel = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: {action in
        //nothing
    })
    var actionNormal1 = UIAlertAction(title: "Action 1", style: UIAlertActionStyle.Default, handler: {action in
        self.logText("actionNormal1")
    })
    var actionDestruct = UIAlertAction(title: "Destruct", style: UIAlertActionStyle.Destructive, handler: {action in
        self.logText("actionDestruct")
    })
    actionSheet.addAction(actionCancel)
    actionSheet.addAction(actionNormal1)
    actionSheet.addAction(actionDestruct)
    
    self.presentViewController(actionSheet, animated: true, completion: nil)
```

## UIPickerView
AndroidでいうSpinner

配置したPickerViewにViewControllerに対してDelegate.  
ViewController側で UIPickerViewDataSource, UIPickerViewDelegate をimplelment  
コードで動的にPickerViewの中身を作る

```
    // returns the number of columns to display
    func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
        return 2
    }

    // returns the # of rows in each component.
    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return 10
    }
    
    // returns the title of each row
    func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
        return "(\(component),\(row))"
    }
    
    // on selected event
    func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        println("\(self.mPickerView.selectedRowInComponent(0))")
        println("\(self.mPickerView.selectedRowInComponent(1))")
        println("\(component), \(row)")
    }
```

## WebView
WebView設置後、Outletとdelegateを登録  
URLとHTML文字列でのロード

```
    func showWebPage(#url: String) {
        var req = NSURLRequest(URL: NSURL(string: url)!)
        self.mVewbView.loadRequest(req)
    }
    func showWebPage(#htmlString: String) {
        self.mVewbView.loadHTMLString(htmlString, baseURL: nil)
    }
```
 
各種イベントを捕捉するにはdelegate

```
class ... UIWebViewDelegate {
    func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
        // do something, like re-direct or intercept etc.
        return true;
    }
    
    func webViewDidStartLoad(webView: UIWebView) {
        // do something, e.g., start UIActivityViewIndicator
        self.mActivityIndivator.startAnimating()
    }
    func webViewDidFinishLoad(webView: UIWebView) {
        self.mActivityIndivator.stopAnimating()
    }
    func webView(webView: UIWebView, didFailLoadWithError error: NSError) {
        self.mActivityIndivator.stopAnimating()
        var alert = UIAlertController(title: "error", message: error.localizedDescription, preferredStyle: UIAlertControllerStyle.Alert)
        alert.addAction(UIAlertAction(title: "Close", style: UIAlertActionStyle.Cancel, handler: nil))
        self.presentViewController(alert, animated: true, completion: nil)
    }
}
```

## ScrollView
内包する全てのウィジェットを選択し、Embeded in -> ViewでContainerを作る  
そのContainerに対しさらにEmbeded in -> ScrollView でScrollViewを生成  
ScrollView の Constraints の 横Margin をゼロにセット  


## UserDefault
NSData, NSString, NSNumber, NSDate, NSArray, NSDictionary など保存可能

```
    let STORAGE_KEY = "key"
    let userDefaults = NSUserDefaults.standardUserDefaults()

    // UserDefault
    func saveUserdefault(data: AnyObject, forKey: String) {
        userDefaults.setObject(data, forKey: forKey)
        userDefaults.synchronize()
    }
    
    func retrieveUserdefault(key: String) -> String? {
        var obj = userDefaults.stringForKey(key)
        return obj
    }
    
    func deleteUserDefault(key: String) {
        self.userDefaults.removeObjectForKey(key)
    }
```