LoginSignup
120
119

More than 5 years have passed since last update.

Swift Tour(ツアー)

Last updated at Posted at 2014-06-15

The Swift Programming Language をまとめるトップ

// Playground で動作の確認をしながら試すとよいと思います
// まずは Hello world から
println("Hello, world")
print("print は改行が無い ")
println("こんにちは")
println("行:" + String(__LINE__))
println("列:" + String(__COLUMN__))
// ファイル名: __FILE__ 
// 関数やメソッド名: __FUNCTION__ 
// などのリテラル表現がある

/**
  * 値につてい 
  */

// var と let がある
// var が 変数
// let が 定数(最初の一度しか定義できない)

var myVariable = 42
myVariable = 50
let myConstant = 42

// myConstant = 50
// myConstant は定数なので値を代入しようとするとエラーになる

// 変数や定数に定義するときは必ず "型" を持たせなければならない
// 型を持つ事でオブジェクトとしてその型を操作できる

// ただ、毎回明示的に型を定義する必要はない
// 以下、implicit(明示にしない場合)と explicit(明示する場合)とがある

let implicitInteger = 70
let implicitDouble = 70.0
// コンパイラーが代入される値を infer "推論" して型を決定する

let explicitDouble: Double = 70
// 明示する時は、型の名前の後に型を ":" コロンを使う

// let explicitFloat: Float = 4
// explicitFloat

// 実際の値をコンバートしたい時は、明示的に型を指定することもできる

let 表記 = "幅は"
let  = 94
let 幅表記 = 表記 + String()
// 幅 Int型 なので、 "+" で文字列として繋ぐ時 String() を使って型を変換する

// \() を使った簡略形もある
let リンゴの数 = 3
let オレンジの数 = 5
let リンゴの所持数 = "私は \(リンゴの数) つ持っています。"
let フルーツの所持数 = "私は果物を \(リンゴの数 + オレンジの数)つ持っています。"

// ブラケット [] を使って配列や連想配列の定義ができる

var 買い物リスト = ["卵", "小麦粉", "ミルク"]

// インデックス 1 に追加
買い物リスト[1] = "バター"
買い物リスト

var アプリ = [
    "SnapDish": "料理好きSNS",
    "Retty": "外食好き実名SNS",
 ]
アプリ["Cookpad"] = "レシピ検索サービス"

// リテラルで直接値を代入して変数の値を操作できる


// 空の配列や連想配列を作成する時は、イニシャライザーを使う

// 明示的に型を指定する
let emptyArray = String[]()
let emptyDictionary = Dictionary<String, Float>()
// <String, Floag> は、"キー" に文字列型が入り "値" にFloat型が定義されているということ

// 型が推論できる場合(前に定義などされている場合)以下の様に [] や [:] を代入することができる
買い物リスト = []
アプリ = [:]

/******************************************************************
 * フロー制御について
 ******************************************************************/

// 条件分岐として、 if と switch がある
// ループは、for-in, for, while, do-while がある

let 個人の点数 = [75, 43, 103, 87, 12]
var チームの得点 = 0
for 点数 in 個人の点数 {
    if 点数 > 50 {
        チームの得点 += 3
    } else {
        チームの得点 += 1
    }
}

// 点数が 50 より大きい時は、+3 でそれ以外は +1 になりそのチーム得点は
チームの得点


// オプショナル値について

// "?" を型名の後に付ける
// nil値も持つ事ができる
// ObjCをやってる人にはありがたい話し
var オプショナル指定のある文字列: String? = "こんにちは"
オプショナル指定のある文字列 == nil
// "Hello" が定義されているので nil じゃない
// 従って false が返る

// Optional binding
// if 分の条件に一時的に定数を定義してその結果を評価する
var オプショナル名: String? = "清田史和"
var 挨拶 = "おはよう!"
// オプショナル名に値があるかチェックし
// 値があれば true を返し値を "名前" 定数に代入
// unwrap された値を持つ名前定数はそのブロック内でローカル定数として扱われる
if let 名前 = オプショナル名 {
    挨拶 = "おはよう! \(名前)"
} else {
    println("名前の値が nil です")
}

// オプショナル名を nil にしてみる


let vegetable = "red pepper"
switch vegetable {
    case "celery":
        let vegetableComment = "Add some raisins and make ants on a log."
    case "cucumber", "watercress":
        let vegetableComment = "That would make a good tea sandwich."
    case let x where x.hasSuffix("pepper"):
        let vegetableComment = "Is it a spicy \(x)?"
    default:
        let vegetableComment = "Everything tastes good in soup."
}

// case の条件には色々と書く事ができるのと break を書かなくても case の条件にマッチしたら、
// その case で switch を抜ける


// for-in を使って配列や連想配列を展開することができる

let 気になる数字 = [
    "素数": [2, 3, 5, 7, 11, 13],
    "フィボナッチ数": [1, 1, 2, 3, 5, 8],
    "平方数": [1, 4, 9, 16, 25],
]
var 最大数 = 0
for (種類, 数字s) in 気になる数字 {
    for 数字 in 数字s {
        if 数字 > 最大数 {
            最大数 = 数字
        }
    }
}
最大数
// 連想配列の場合、タプル (キー, 値) で受けることができる
// 配列の場合、要素を返して展開できる

// while と do-while は以下のようの書く
var n = 2
while n < 100 {
    n = n * 2
}

var m = 2
do {
    m = m * 2
} while m < 100
m
// do-while は必ず1回は処理が走る


// 範囲指定 .. または ... を使ってみる
var firstForLoop = 0
for i in 0..3 {
    firstForLoop += i
}
firstForLoop

var secondForLoop = 0
for var i = 0; i < 3; ++i {
    secondForLoop += 1
}
secondForLoop

// 上記二つは同じ
// .. を ... にしてみると最後の数も含むので回数が一つ増える

/******************************************************************
 * 関数とクロージャー
 ******************************************************************/

// 関数名(引数名: 型,,,) -> 戻値型 {...}
func 挨拶(名前: String, 曜日: String) -> String {
    return "こんにちは\(名前)さん、今日は \(曜日)."
}
挨拶("斉藤", "木曜日")

func getGasPrices() -> (Double, Double, Double) {
    return (3.59, 3.69, 3.79)
}

let(gas1, _, _) = getGasPrices()
gas1
// gas1 だけ定数で定義 _ (アンダースコア)は値を無するときに使えたりする

// 合計数を計算する関数をみてみる
// 引数の型に ... をつけることで複数の引数の値を配列で受ける事ができる
// numbersがローカル変数で配列になる
// Int...はInt型を保持した配列という意味になる
// ただ、.count が使えない(まだ理由は調べていない)
func sumOf(numbers: Int...) -> Int {
    var sum = 0
    numbers
    for number in numbers {
        sum += number
    }
    return sum
}
sumOf()
sumOf(42, 597, 12)


// 関数はネストできる

func 15を返す() -> Int {
    var y = 10
    func add() {
        y += 5
    }
    add()
    return y
}
15を返す()


// 関数型を返すこともできる
// (Int) -> Int 引数がIntで戻り値がIntの関数がこの関数の戻り値
func makeIncrementer() -> (Int) -> Int {
    var runningTotal = 0
    func addOne(number: Int) -> Int {
        runningTotal += number
        return runningTotal
    }
    return addOne
}
var increment = makeIncrementer()
increment(7)
// 7 を加算
increment(7)
// 更に 7 を加算 = 14
// runningTotal はキャプチャ値をしてして、関数内に保持することもできる


// 引数に関数を渡す事もできる
func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool {
    for item in list {
        if condition(item) {
            return true
        }
    }
    return false
}
func lessThanTen(number: Int) -> Bool {
    return number < 10
}
var numbers = [20, 19, 10, 12]
hasAnyMatches(numbers, lessThanTen)
// 10 より小さい値があれば true を返す

// 配列にはmapメソッドがある
// in を使って表現する
// { (引数) -> 戻り値型 in
//    ステートメント
// }

// 配列の値の数字を3倍にする
numbers.map({
    (number: Int) -> Int in
    let result = 3 * number
    return result
})
// map({}) 内で、配列を展開して、無名関数の型 (number: Int) -> Int の第一引数に値を渡し、in 以降がnumberとうローカル変数に3を掛けてInt型の値を返している

// 以下は偶数を返す
numbers.map({
    (number: Int) -> Int in
    return number%2 == 0 ? 0 : 1
})

var 倍された数 = numbers.map({ number in 3 * number })
倍された数

// { (引数1, 引数2) -> 戻り値型 in
//    ステートメント
// }
// 定数でも並び替えはできる
// 配列の定数の場合サイズ変わらなければ、その範囲以内は並び替え等自由
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

var 降順 = sort(names, { (s1: String, s2: String) -> Bool in
    return s1 < s2
    })

// 推論型
降順 = sort(names, { s1, s2 in return s1 > s2 } )

// $0, $1 を使って簡単に書くこともできる

降順 = sort(names, { $0 > $1 })

// テイリング(後置記法)もできる {} ブレス内が長い時等使う
降順 = sort(names) { $0 > $1 }

// 更に省略ができる
降順 = sort(names, >)

/******************************************************************
 * オブジェクトとクラス
 ******************************************************************/

// 定数と変数を使って宣言できる

class Shape {
    var numberOfSides = 0
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}

// クラス名に () を付けてインスタンスを生成する
// プロパティやメソッドには . ドットを使ってアクセスする
var shape = Shape()
shape.numberOfSides = 7
shape.simpleDescription()


// 形 は全てのプロパティに初期値がしていしてあるので、イニシャライザー init() を省く事ができる
// init() は return が無い
// 名前 は初期値が無いので、イニシャライザーで指定する事ができる
// 名前 をオプショナル(名前: String?)にしたら初期値の指定が無い時には nil が自動でセットされる
class  {
    var 辺の数: Int = 0
    var 名前: String
    init(名前: String) {
       self.名前 = 名前
    }
    func 説明() -> String {
       return "辺の数は \(辺の数)"
    }
}
// self.名前はイニシャライザーのローカル変数名の名前とプロパティ(メンバー変数)名前と区別するために付ける
// 初期化され時にはオプショナルを除く全てのプロパティが何らかの値を定義しておく必要がある
// deinit というのがあって、オブジェクトがリリースされる前に呼ばれる
// ファイルオープンとかしていたら、閉じたりするときにつかったりする


// サブクラス
// : コロンで繋いで書く
class 四角形:  {
    var 辺の長さ: Double

    init(辺の長さ: Double, 名前: String) {
        self.辺の長さ = 辺の長さ
        super.init(名前: 名前)
        // プロパティ名とローカル変数名がかぶらない時は基本プロパティには self をつけなくても大丈夫

        辺の数 = 4
    }

    func 面積() ->  Double {
        return 辺の長さ * 辺の長さ
    }

    // override を使ってスパークラスのメソッドをオーバーライド
    override func 説明() -> String {
        return "四角の辺の長さ \(辺の長さ)."
    }
}
let test = 四角形(辺の長さ: 5.2, 名前: "四角")
test.面積()
// オーバライドした 説明() が実行される
test.説明()


// プロパティの setter と getter 

class 正三角形:  {
    var 辺の長さ: Double = 0.0

    init(辺の長さ: Double, 名前: String) {
        // 正三角形のプロパティを辺の長さを定義して初期化
        self.辺の長さ = 辺の長さ
        // スパークラスを呼び出し名前を設定
        super.init(名前: 名前)
        // スーパークラスの辺の数を設定
        辺の数 = 3
    }

    var 周囲の長さ: Double {
        get {
             return 3.0 * 辺の長さ
        }
        // newValue として set される
        set {
            辺の長さ = newValue / 3.0
        }
        // 以下の様に明示的に newValue を指定する事ができる
        // set(新しい値) {
        //      辺の長さ = 新しい値 / 3.0
        // }
    }

    override func 説明() -> String {
        return "正三角形の辺の長さ \(辺の長さ)."
    }
}
var 三角形 = 正三角形(辺の長さ: 3.1, 名前: "三角形")
三角形.周囲の長さ
// 新たに周囲の長さを設定
三角形.周囲の長さ = 9.9
// 辺の長さも set 内で更新される
三角形.辺の長さ


// willSet / didSet を使って変更監視することできる

class 三角形と正方形 {
    var triangle: 正三角形 {
        willSet {
            square.辺の長さ = newValue.辺の長さ
        }
    }
    var square: 四角形 {
        willSet {
            triangle.辺の長さ = newValue.辺の長さ
        }
    }
    init(サイズ: Double, 名前: String) {
        square = 四角形(辺の長さ: サイズ, 名前: 名前)
        triangle = 正三角形(辺の長さ: サイズ, 名前: 名前)
    }
}
var triangleAndSquare = 三角形と正方形(サイズ: 10, 名前: "その他の形")
triangleAndSquare.square.辺の長さ
triangleAndSquare.triangle.辺の長さ
triangleAndSquare.square = 四角形(辺の長さ: 50, 名前: "大きくなった四角形")
triangleAndSquare.triangle.辺の長さ


// クラスメソッドと関数の違い

class Counter {
    var count: Int = 0
    // 外側の引数名をnumberOfTimesの様に命名することもできる
    func incrementBy(amount: Int, numberOfTimes times: Int) {
        count += amount * times
    }
}
var counter = Counter()

// 関数と違う点で第一引数名の省略がある
// 一般的に by, for, with とか使ってメソッド名第一引数の意味を表すので省くことがある
// (x) counter.incrementBy(amount:2, numberOfTimes: 7)
// nameOfTimesのように外側用の引数名をしていした場合、第一引数にも引数名を指定する必要がある
counter.incrementBy(2, numberOfTimes: 7)


// オプショナル値として型の後に ? 指定する事ができる
let optionalSquare: 四角形? = 四角形(辺の長さ: 2.5, 名前: "オプショナル四角形")
// ? の直前の型が nil の場合、その後は無視され nil を返す
// 値があれば、unwrapped(解除)して値を返す
let sideLength = optionalSquare?.辺の長さ

/******************************************************************
 * 列挙型と構造体
 ******************************************************************/

// クラスの定義のように enum 型名: 型 {...} で定義できる
enum Rank: Int {
    // caseは新しい行の始まりを意味する
    // 型が数字なので、最初 Ace に数字を定義すると
    // Ace が 1 なので、Two からは 2, 3, 4 と値が定義される
    case Ace = 1
    // (,)カンマ区切りで一行で書く事も出来る
    case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
    // 他のSwiftで使われている方と同様に最初の一文字は大文字で書く
    // 単数系で表記しより明白に分かる様にする
    case Jack, Queen, King
    // 振る舞いを定義できる
    // メンバー値の説明などするとよい
    func simpleDescription() -> String {
        switch self {
            case .Ace:
                return "ace"
            case .Jack:
                return "jack"
            case .Queen:
                return "queen"
            case .King:
                return "king"
            default:
                // switch でカバーできてないもの値を
                return String(self.toRaw())
        }
    }
}
let ace = Rank.Ace
ace.toRaw()

let three = Rank.Three
three.toRaw()

// toRaw と fromRaw があり値へと値からの変換ができる
if let convertedRank = Rank.fromRaw(3) {
    let threeDescription = convertedRank.simpleDescription()
}

// Suit (スーツ)はトラップのマークの事
// 型が明示的に指定しないこともできる
enum Suit {
    case Spades, Hearts, Diamonds, Clubs
    func simpleDescription() -> String {
        switch self {
            // self が既に既知なので .Spades の様に self を省く事ができる
            case .Spades:
                return "spades"
            case .Hearts:
                return "hearts"
            case .Diamonds:
                return "diamonds"
            case .Clubs:
                return "clubs"
        }
    }
}

// 型が明示的に指定されていないので、hearts には Suit.Hearts が参照される
let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()


// 構造体は struct を使って定義できる
// イニシャライザーやメソッドが定義できたりしてクラスの挙動に似ている
// クラスとの大きな違いは、構造体は値を複写しクラスはリファレンス渡す
struct Card {
    // Rankをプロパティに指定
    var rank: Rank
    // Suitをプロパティに指定
    var suit: Suit
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()


// メンバーに関連する値を持たせる事ができる
// ServerResonse に Reuslt と Error を定義し、それぞれの受け取る値の型を指定
enum ServerResponse {
    case Result(String, String)
    case Error(String)
}

let success = ServerResponse.Result("6:00 am", "8:09 pm")
let failure = ServerResponse.Error("Out of cheese.")

switch success {
    case let .Result(sunrise, sunset):
        let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."
    case let .Error(error):
        let serverResponse = "Failure...  \(error)"
}

/******************************************************************
 * プロトコルと拡張
 ******************************************************************/

// protocol を使って宣言ができる
// クラス、列挙型、構造体で利用できる
// プロトコールを継承した場合、その定義を継承した側で定義しなければならない
protocol ExampleProtocol {
     var simpleDescription: String { get }
     mutating func adjust()
}

class SimpleClass: ExampleProtocol {
     var simpleDescription: String = "A very simple class."
     var anotherProperty: Int = 69105
     func adjust() {
          simpleDescription += "  Now 100% adjusted."
     }
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription

struct SimpleStructure: ExampleProtocol {
     var simpleDescription: String = "A simple structure"
    // mutating を func の前に設定するとメソッド経由で構造体のプロパティをメソッドの実行終了とともに更新できる
     mutating func adjust() {
          simpleDescription += " (adjusted)"
     }
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription


// extension を使って数値型や既存にある型の拡張もできる
// ObjC のカテゴリのようなもの
extension Int: ExampleProtocol {
    var simpleDescription: String {
        return "The number \(self)"
    }
    mutating func adjust() {
        self += 42
    }
 }

// ExampleProtocol の simpleDescription を呼び出す事ができるようになる
7.simpleDescription

// インスタンスのプロトコル型で以下の様に定義することができる
// a インスタンスは anotherProperty をもっているが、ExampleProtocol で定義した定数は、 anotherProperty を呼び出す事ができない
let protocolValue: ExampleProtocol = a
protocolValue.simpleDescription
// protocolValue.anotherProperty  // コメントアウトするとエラーになる

// Protocol を使って Delegation の設定などもできる
// https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_354
120
119
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
120
119