Swift3入門

#はじめに
某プログラミング学習サイトの学習記録を記します。

#共通操作
・範囲選択：Shiftを押しながらクリック
・複数行コメントアウト：Command /


#01
・Xcodeでplaygraoundを新規作成する
・種類はBlankを選ぶ (他にはGame, Map, Single Viewがある)

#02
・下記について、C言語と同じ
　・コメント
　・print関数
　・文字列を""で囲むこと
　・文末が;であること
・実行形式の選択は、□または△を長押しすることで変更できる
　短く押すと実行される。
・右ペインに実行結果が表示される

#03：変数と定数
・変数：var
・定数：let

・例
　let msg:String; // 文字列型の定数msgを宣言
　msg = "hello";  // msgに"hello"を代入

　let msg = "hello"; // 型推論が行われmsgは文字列型となる

※：C言語と違い、

#04：データ型
・下記はC言語と同じ
　・Int：整数型
　・Float, Double
　・キャスト(型変換)
・Bool型：true / false

#05：演算
・下記はC言語と同じ
　・四則演算
　・単項演算子(+=, *= /= -=)
　・論理演算(&&, ||, !)
・文字列
　・+で連結　"hello " + "world" → "hello world"
　・\()で数値を文字に変換できる。()の中で演算できる。
　　(例) 変数yが15の時
　　　　"y is \(y)"     → "y is 15"
　　　　"2*y is \(2*y)" → "2*y is 30"

#06：分岐
・下記はC言語と同じ
　・分岐(if, else, if else)
　・比較(>, >=, <=, ==, !=)
　・条件演算子(条件文 ? 真 : 偽)

#07：switch
・switchの構文はC言語と同じ
　・default, breakもC言語と同じ
・caseの作り方
　・単一： (例) case 0:
  ・複数： (例) case 1, 2, 3:
　・範囲： (例) case 4...6:
　・範囲： (例) case 7..<9:    9を含まない
　・比較： (例) case let n where n > 20; 20超の場合
 
#08：while
・whileの構文はCと同じ
・C言語のdo whileと同じ機能が repeat whileで実現される
　repeat {
　　　実行文;
  } while (条件)

#09：for
・構文　for 変数　in データ範囲　{処理}
・例 for i in 0...5 {print(i); }
・break, continueはC言語と同じ。

#10：オプショナル型
・nil：空白の値
・nilを代入可能とするには、Optinal型とする必要がある
　(例) let s:String = nil; 　　　　　// ×
  (例) let s:Optinal<String> = nil; // ○
　(例) let s:String? = nil;         // ○

・nilの判定
　(例)if (s != nil) {
          print(s!); // unwrap
     }
・unwrap：変数の後ろに!を付けてOptinal型から値を取り出すこと
・Optinal Binding：unwrapを行う別の方法
　(例) if let value = s { 処理}
　　sがnilでない場合だけunwrapしてvalueに代入する
・さらに別の方法
　(例) print(s ?? "this is nnil");
　sがnilでなければsを、nilであれば文字列を表示する

#11：配列
・データの型を[]で囲う
　(例) var scores:[Int] = [50, 40];　　// 型を指定
　(例) var scores2 = [50, 40]; 　　　　// 型推論して省略

・配列の要素を制御する
　(例) score[0] = 30;

・配列の要素数を数える：count関数
　(例) score.count

・配列が空かどうかを調べる：isEmpty関数
　(例) score.isEmpty

・空の配列を作成する
　(例) var names = [String]();

・末尾への要素追加
　(例) names.append = "abc";
　(例) names += ["def"];

#12：タプル(異なる型のデータを扱える)
・(例) var items = ("apple", 5):
・(例) 読出：print(items.0);
・(例) 書込；items.1 = 3;
・変数名を宣言する
　(例) var items = ("apple", 5);
       let (product, amount) = items;
・一部だけを変数宣言する
　(例) var items = ("apple", 5);
       let (product, _) = items;
・初期化時に名前を付ける
　(例) var items = (product:"apple", amount:5);
       print(items.product);

#13：集合
・集合は、順序を持たず、値の重複を許さない
・宣言方法
　(例) var winners:Set<Int> = [3, 5, 8, 8];
  (例) var winners:Set = [3, 5, 8, 8]; // 型推論
　　　　print(winners); // [3, 5, 8]
・データを含むか判定する
　(例) winners.contais(3); // 3を含むならtrueを返す
・データを追加
　(例) winners.insert(10); // 10を追加
・データを削除
　(例) winners.remove(5);  // 5を削除
・データ数を数える
　(例) winners.count; // データ数を返す

・空集合の作成
　(例) let s = Set<Int>();
　　　 print(s.isEmpty);  // trueを返す
・演算
　(例) let a:Set = [1, 3, 5, 8]
　　 　let b:Set = [3, 5, 8, 9]
      print(a.union(b));       // 和集合：[5,8,3,1,9]を返す
      print(a.intersection(b)) // 直積　：[5,3,8]を返す 
      print(a.subtracting(b)); // 差　　：[1]を返す

#14：辞書(キーと値で管理するデータ)
・(例)キーが文字列、値が整数の場合
　var sales:Dictionary<String, Int> = ["MrA":300, "MrB":400]
  var sales = ["MrA":300, "MrB":400]; // 型推論
・値の代入
　(例) sales["MrB"] = 500;
・値の取出し
　(例) print("sales["MrB"] ?? "n.a.") // MrBが存在しなければ"n.a."
　　　// キーに対する値が存在しない場合はOptional型のnilが返ってくる
・データの追加
　(例) sales["MrC"] = 100; // MrCを追加(代入と同じ)
・データ数を数える
　(例) print(sales.count)
・一覧を出力
　(例) for (key, value) in sales {
　　　　　　print("\(key):\(value)")
　　　　}
・空の辞書を作成する
　(例) let d = [String:Int](); // キー：String, 値：Intの空の辞書
　　　　print(d.isEmpty);       // trueを返す

#15：関数
・引数と戻り値がなければC言語と同じ
・戻り値がある場合
　(例)
  func sayHi() -> String {  // 文字列を返す関数の宣言
　　　return "hi"　　　　　　// 戻り値
　}
　print(sayHi());           // 戻り値を印字

#16：引数
・関数名の後に(変数名：型)の形式で指定する
　(例) func sayHi(name: String) {
        print("hi \(name)")
      }
      sayHi(name: "A")  // 結果："hi A"
 
・変数名にラベルを付けることで、宣言時と違う変数名で実行する
　(例) func sayHi(from name: String) { // 変数nameにfromというラベルを付ける
         print("hi \(name)")
       }
    
      sayHi(from: "B")   // 結果："hi B"

・変数名のラベルを省略する
　(例) func sayHi(_ name: String) {
　　　　 print("hi \(name)")
　　　　}
　　　　sayHi("C")        // 結果："hi C"

・変数の初期値を決める
　(例) func sayHi(_ name: String = "D") {
         print("hi \(name)")
       }
      sayHi()  // 結果："hi D",　引数は初期値を使用する

#17：inoutキーワード
・引数を渡す際、アドレスを渡す場合にinoutキーワードが必要になる
　(例)
　　func add10(x:inout Int) {　// アドレス渡し
　　　x = x + 10;              // inoutキーワードがなければエラーとなる
　　　print(x)
　　}
　　var i = 10;
　　add10(x : &i); // アドレス渡し
　　print(i);      // 20

#18：class
・宣言
　(例) class User {　　　　　// classの宣言
　　　　let name:String　　　1/ propertyの定義
　　　　var score:Int
　　　　init() {　　　　　　// propertyの初期化
　　　　　self.name = "me"　// selfを使って代入
　　　　　self.score = 20
　　　　}
　　　}

・インスタンス化して利用
　(例)
　　let user:User = User(); // クラスUserのインスタンスuserを定義して初期値代入
　　print(user.name);       // インスタンスuserのnameを印字

#19：イニシャライザ
・インスタンス毎に違う値を持たせる
　(例) class User {
　　　　　let name:String;
　　　　　var score:Int
　　　　　init (name:String, score:Int) { // 引数：String型のnameとInt型のScore
　　　　　　　self.name = name;   // 引数nameをclassのnameに代入
　　　　　　　self.score = score;
　　　　　}
　　　}
　　　let tom = User(name:"tom", score:20);
　　　print(tom.name);       // 結果：tom
　　　print(tom.score);  　　// 結果：20

・変数名を省略
　　イニシャライザ：init(_ name :String, _ score:Int) 
　　インスタンス化：let tom = User("tom", 23);

・引数が渡されなかったときのイニシャライザを作成
　(例) class User {
　　　　　let name:String;
　　　　　var score:Int
　　　　　init (name:String, score:Int) { 
　　　　　　　self.name = name;   // 引数nameをclassのnameに代入
　　　　　　　self.score = score;
　　　　　}
　　　　　init () {  // 引数を指定しない場合のイニシャライザ
　　　　　　　self.name = "no name";   // 引数nameをclassのnameに代入
　　　　　　　self.score = 0;
　　　　　}
　　　}

　　　let noname = User();  // 引数を指定しない
　　　print(noname.name);   // "no name"
　　　print(noname.score

#20：計算プロパティ(動的に計算可能なプロパティ)
・クラス内の変数にはget関数とset関数を追加できる
　(例)
　　class User {
　　　　let name:String;
　　　　var score:Int
　　　　var level:Int {
　　　　　　get { 
　　　　　　　return Int(self.score/10) // levelの取得時、scoreの1/10を返す
          // return Int(score/10)    // 自明な場合は、selfを省略可能
　　　　　　}
　　　　　　set {
　　　　　　　if newValue >= 0 {        // 値をnewValueで受け取る
　　　　　　　　score = newValue * 5;   // 5倍してscoreに入力する
　　　　　　　}
           }
　　　}
　　　　// 戻り値だけの場合(getだけ)の場合の記述方法
　　　　//var Int {
　　　　//　return Int(score/10);
　　　　//}

     let u = User("MrA", 2);
　　　u.level = 5;
　　　print(u.score)  // 結果：50

#21：プロパティの値の変化前後
・willSet関数で変化前、didSet関数で変化後を監視できる
・(例)
　　class User {
　　　var score:Int {
　　　 willSet {  // 変化前
         print("\(score) -> \(newValue)")
　　　}
　　　didSet {　　// 変化後
　　　　　print("Changed: \(score - oldValue)")
　　　}
    }
　　let tom = User("tom", 2)
　　tom.score = 53     // "2 -> 53, Changed:51
　　tom.score = 20     // "53 -> 20, changed:-33

#22：メソッド
・func 関数名(引数)
・例
　class User {

　　let name:String
　　var score:Int
　　init(_ name : String, _ score:Int) {
　　　self.name = name;
　　　self.score = score;
　　}
　　func sayHi(_ msg:String) { // データ型の省略ｆｓ
　　　print("\(msg) \(name)")
　　}
　}
　let tom = User("tom", 2)
　tom.sayHi("hola");  // 結果："hola tom"

#23：クラスの継承
// 親クラス(スーパークラス)
Class User {
　let name:String;
　var score :Int;
　init(_ name:String, _ score:Int) {
　　self.name = name;
　　self.score = score;
　}

　func sayHi() {        // overrideを禁止したい場合は、「final func 関数名」とする
　　print("hi \(name)")
　}
}

// 子クラス(サブクラス)
class AdminUser:User  {   // class 子クラス名：親クラス名
　func sayHello() {
　　print("hello \(name)")
　}
　override func sayHi() {  // override：親クラスのメソッドを上書き
　　print("admin hi \(name)")
　}
}

let tom = User("tom", 23);
let bob = AdminUser("bob", 30);
print(bob.name);　　// 結果：bob
print(bob.score);  // 結果：30
bob.sayHi();      // 結果：admin hi bob
bob.sayHello();   // 結果：hello bob

#24：型プロパティ、型メソッド
・インスタンスではなく、クラスに直接関連するプロパティやメソッドはstaticを先頭に付ける
・(例)
Class User {
 let name:String;
　var score:Int;
　static var count = 0; // クラスから直接扱う
　init(_ name:Stirng, _ score:Int) {
　　self.name = name;
　　self.score = score;
　　User.count += 1;　// イニシャライザはインスタンスから呼ばれるので、型プロパティへのアクセスにはクラス名を付ける
　　}

　class func getInfo() {
　　// static funcにするとoverrideを禁止できる
　　print("\(count) instances);
}

class AdminUser:User {
　override class func getInfo() {
　　print("admin \(count) instances")
 }
}

User.getInfo();            // 結果：0
let a = User("a", 1);
User.getInfo();            // 結果：1

AdminUser.getInfo();       // 結果：1
let b = AdminUser("b", 2);
AdminUser.getInfo();       // 結果：2

#25：型キャスト

・(例)
class User {
　let name : String;
　init(_ name : String) {
　　self.name = name;
　}
}

class AdminUser : User{}

let tom = User("tom") 
let bob = AdminUser("bob")

// 配列として扱う
let users:[User] = [tom, bob];  
　// 「:[User]」は記述しなくても型推論してくれる
　// 親子クラスのため同じ種類として扱ってくれる

for user in users {
　// AdminUserの場合だけ表示する(1)
　if let u = user as? AdminUser // 「as?」で一語(スペース挿入禁止)
　　// as?で変換可能か調べる。失敗ならnilが返ってくる
　　// optional bindingを使う
    // 成功時はAdminUser型のuserがuに代入される
 　　print(u.name); // 結果：bob
　}

　// AdminUserの場合だけ表示する(2)
　if user is AdminUser {     // userがAdminUser型であるか確かめる
　　let u = user as! AdminUser // as!でunwarpしてくれる
      // AdminUser型のuserが返ってくる
 　　print(u.name); // 結果：bob
　}
}
// unwrap：optional型からデータを取り出すこと
// optional型：nilを格納できる型
// optional Binding：値がnilで内場合だけ値を取り出す

 #26：プロトコル
・クラスに対して、実装が必須なプロパティやメソッドを定義する
・(例)

protocol Printable { // プロトコル定義
　var type:String { get }  // 読み取り専用
　var count:Int {get set}　// 読み書き可能
　func printout()　　　　　　// 実装はクラスで行うので定義は不要

　// イニシャライザは不要
}

class User:Printable {
　let type = "Laser"
　let count = 0;
　let name:String;
　init(_ name:String) {
　　self.name = name
　}
　func printout() {
　　count += 1;
　　print("\(type) : \(count)")
　}
}

let a = User("a")
a.printout();  // 結果「Laser:1」
a.printout();  // 結果「Laser:2」
a.printout();  // 結果「Laser:3」
a.printout();  // 結果「Laser:4」

#27:エクステンションによる拡張
・既存の型に新しいプロパティやメソッドを追加する
・(例)
// String型を拡張し、文字列長を返す変数を追加する
extension String { // String型を拡張
　var length :Int { // lengthという変数を追加
　　return self.characters.count　// プロパティの一つであるcountを返す
　}
}

let msg = "hello"
print(msg.characters.count)  // String型の元々の文字列長の取得
print(msg.length);           // 新規に追加したlength変数による文字列長の取得

(例)
protocol Printable { // Printableのプロトコル(実装必須関数の定義)
　func printout()
}

extension Printable { // 既存のPrintableに
　func printout() {   // 関数printoutを追加
　　print("printing)
　}
}

// PrintableをUserクラスに適合させる
class User:Printable { // Printableのインスタンス
　let name:String
　init(_ name:String) {
　　self.name = name;
　} 
} // インスタンス内にprintout関数の実装が不要

let tom = User("tom")
tom.printout()



#28：参照型と値型
・Int, doubleなどは値型
・Classは参照型
(例)
class User {
　var name:String;
　init(_ name:String) {
　　self.name = name;
　}
}

var org = User("A)
var copy = org;
org.name = "B"
print(org.name)  // 結果：B
print(copy.name) // 結果：B

#29：構造体
・classと、ほぼ同じ機能を持つ。
・classが参照型であるのに対して構造体は値型である。
・classと違って継承が出来ない
・extension, protocolは使える
・メソッドでプロパティを変更するには、funcの前にmutatingを付ける

#30：：列挙型
・enum (型名) {
　　case 値1
　　case 値2
　}

・例
　enum Direction :Int {
　　case right = 1
　　case left = -1
　}
　print(Direction.rihgt.rawValue); // 値を取り出す
　var dir:Direction
　dir = .right // Direction.rightの省略形

　switch (dir) {
　　case .right: print("right");
　　case .left:  print("left");
　}

#31：ジェネリクス型
・データ型を汎用化させる
　関数名の後に<T>を追加し、データ型をTとする。

・func getData(x:Int) {   // 通常の書き方
・func getData<T>(x:T) {  // ジェネリクス型を使用
　print(x)
　}
　getData(x:"Hello") // 結果："Hello"
　getData(x:2.3)     // 結果："2.3"

#32：サブスクリプト
・サブスクリプト：インスタンスに対して、配列と同じようにインデックスを付ける
class Teams {
　var memvers = ["A", "B", "C"]; // サブスクリプトのアクセス対象のデータを用意
　subscript (index : Int) -> String {　// indexに使う値の型と返値の型を指定
　　get {　　　　　　　　　　　　　　　　　// サブスクリプトで取得する時の処理
　　　return members[index]　
　　}
　　set {　　　　　　　　　　　　　　　　　// サブスクリプトで設定する時の処理
　　　members.insert(newValue, at:index)　// 設定値をnewValueで取得できる
　　}
　}
}

var t = Team()
print(t[1]) // 結果："B"
t[3] = "D"
print(t[3]) // 結果："D"

#33:guard
・異常処理を分かりやすく書くための仕組み

・guardを使わない書き方
func test(_ msg:String?) { // StringのOptional型
　if let s = msg {　// nil判定
　　print(s)
　} else {
　　print("nil")
　}
}

・early return , early exitを使用する
func test(_ msg:String?) {
　if msg == nil {
　　print("nil")
　　return
　}
　print(msg!) // unwrapする
}

・guardを使う
func test(_ msg:String?) {
　　// msgがnilでなければsに代入、sならelse以下を処理する
　　guard let s = msg else { 
　　　print("nil")
　　　return　// guardの中では、returnを忘れるとエラーを出してくれる
　　}
　　print(s)
}

#34：例外処理

// 例外の種類を列挙型で定義
enum LoginError:Error { // プロトコルを使用する
　case emptyName
　case shortName
}

class User {
　let name:String
　init(_ name:String) {
　　self.name = name
　}

　// 例外が発生する可能性がある場合は関数名の後にthrowsを付ける
　func login() throws {　
　　// nameが空でないときは無処理。空の時の処理を定義する
　　guard name != "" else {
　　　throw LoginError.emptyName　// 例外を投げる
　　}
　　guard name.count > 5 else {
　　　throw LoginError.shortName
　　}
　　print("success")
　}
}

let a = User("AAAAA")   // 結果：short
let a = User("AAAAAA")  // 結果：Success
let a = User(")         // 結果：enter

// 例外が発生するときの書法
do {
　try a.login()
} catch LoginError.emptyName {
　print("enter")
} catch LoginError.shortName {
　print("short")
}

#35：Optional Chaining
・Optinal型が連続する場合に安全にnilチェックする
class User {
　var name:String? = "" // nameがoptional型の場合
}

let user:User? // Userがoptional型の場合(Optional型を短く宣言する)
user = User()
user?.name = "a"　// ※1
if let s = user?.name?.uppercased() { // ※1 ※2
　print(s)
}

// ※1：Optional Chaining:optional変数の後に?を付ける。
//      nilの場合はnilを、nilでなければその値を含むOptional型を返す
// ※2：Optional Binding

#36：暗黙的アンラップオプショナル　(Implicity Unwarpped Optional)
・通常のOptinal型
　var msg:String?　// Optional型(nilを取ることができる)
　msg = "a"

　if msg != nil { // nilチェック
　　print(msg!)   // Optional型をUnwap
　}

・暗黙的アンラップオプショナル(UnWrap不要)
　var msg:String!　// 末尾を「?」ではなく「!」にする
　msg = "a"

　print(msg)   // Unwrap不要(末尾の「!」不要)



#以上