2015/03/09更新

[Swift] Swiftの言語仕様に入門する

このエントリーをはてなブックマークに追加            

こんにちは、@yoheiMuneです。
2月末から1年ぶりにiPhoneアプリの制作を再開し、Swiftを書くようになりました。新しいプログラミング言語を学ぶのは、その言語の設計思想とかも見えてとても楽しいですね。
このブログでは、Swiftの各機能の実装例をたくさん残したいと思います。

画像

https://developer.apple.com/swift/




目次




Swift言語を学ぶために良いサイト

私はSwift言語の勉強に、書籍ではなくWebサイトの入門を利用しました。特に良かったサイトは以下のサイトです。

- 初心者のためのSwiftプログラミング入門

- Swiftに関する1550件の投稿 - Qiita


私はもともとObjective-Cを書いていたので、上記のようなサイトでも十分に学ぶことができました。もしプログラミング未経験の方であれば、本を買ってガッツリと勉強する方が良いと思います。

また上記の入門サイトでは言及されていないようなことで悩んだ場合には、Appleが以下で提供している言語仕様書を参考にしました。

- Swift - Resources - Apple Developer

なおこのブログで紹介しているスニペットは、初心者のためのSwiftプログラミング入門で勉強させていただきました。貴重な情報をありがとうございます。



Swiftに入門

それではさっそく、コードベースでSwiftに入門したいと思います。


変数定義

Swiftには、型の暗黙的定義と明示的な定義が存在します。
// 変数の定義(型を推定する)
var str = "Hello, playground"
var intValue = 1;

// 変数の定義(型を明示する)
var str2:String = "Good Night";

// 変数の定義
// 宣言の時点で型が不明なため、以下はエラーになります
//var type;

// 定数
let MAX_VALUE:Int = 999;


制御文

条件指定の部分で、括弧()が不要なことがSwiftの特徴です。またObjective-Cに比べると、かなり柔軟になりました。
// 制御文(if)
if str == "aaa" {
    NSLog("GOOD");
} else {
    NSLog("NOT GOOD");
}

// 制御文(switch)
switch intValue {
case 1:
    NSLog("value is 1");
case 2, 3, 4:
    NSLog("Value is 2, 3, or 4");
case 5...7:
    NSLog("Value is 5 to 7");
default:
    NSLog("Other Value");
}

// 制御文(for-in)
for index in 1...10 {
    NSLog("Value is \(index)");
}

// 制御文(for基本形)
var array = [1,2,3,4,5];
for var i = 0; i < array.count; i++ {
    NSLog("array[%d] = %d", i, array[i]);
}

// 制御文(while)
var i = 10;
while i > 0 {
    NSLog("i is %d", i--);
}

// 制御文(do-while)
var j = 10;
do {
    NSLog("j is \(j)");
} while j > 0


タプルというデータ型

Swiftでは複数データを保持するタプルというデータ形式がサポートされています。
// タプル
var person = (name:"Yohei", age:29);
person.name;
person.age;


関数

関数の書き方もなかなか独特ですが、慣れるとなんとなく良い感じがしてきます。Objective-Cよりも柔軟に記述できて良いです。
// 関数の定義(戻り値あり)
func add (num1:Int, num2:Int) -> Int {
    return num1 + num2;
}
var result = add(1, 2);

// 関数の定義(戻り値なし)
func sayHello (msg:String) {
// または func sayHello (msg:String) -> Void {
    NSLog("hello %@ !", msg);
}

// 関数の定義(引数の外部名)
func tax (price p:Int, rate r:Double) -> Int {
    return (Int)(Double(p) * (1.0 + r));
}
tax(price:1000, rate:0.08);

// 関数の定義(引数の外部名、ショートハンド)
func tax2 (#price:Int, #rate:Double) -> Int {
    return (Int)(Double(price) * (1.0 + rate));
}
tax2(price: 150, rate: 0.08);

// 関数(タプルを返却する)
func tax3(#price:Int) -> (total:Int, tax:Int) {
    var tax = Int(Double(price) * 0.08);
    var total = price + tax;
    return (total: total, tax: tax);
}

// 関数(引数のデフォルト値)
func tax4(#price:Int, rate:Double = 0.08) -> Int {
    return Int(Double(price) * (1.0 + rate));
}
tax4(price: 100);
tax4(price: 400, rate: 0.08);

// 関数(可変引数)
func addAll(#nums:Int...) -> Int {
    var total = 0;
    for num in nums {
        total += num;
    }
    return total;
}
addAll(nums: 1,2,3,4,5);

// 関数(inout引数)
func tax5(inout price:Int) {
    price = Int(Double(price) * 1.08);
}
var num = 1000;
tax5(&num);


クラス

クラスの書き方もObjective-Cから比べてとてもシンプルになりました。
// クラス定義
class Animal {
    var name = "Leon";
    func say () {
        NSLog("Hello, %@", name);
    }
};

// インスタンス化
var animal = Animal();
animal.name = "John";
animal.say();

// クラスの継承
class Dog : Animal {};
var dog:Dog = Dog();
dog.name = "Lazy";
dog.say();

// メソッドのオーバーライド
class Cat : Animal {
    override func say() {
        NSLog("Nya〜 by %@", name);
    }
}
var cat = Animal();
cat.say();

// イニシャライズ
class Bird : Animal {
    init (name aName:String) {
        super.init();
        self.name = aName;
    }
}
var bird = Bird(name: "kotori");
bird.say();

// Computedプロパティ
class Friend {
    var name:String
    var old:Int
    var age:Int {
        get {
            return old
        }
        set {
            if newValue > 0 {
                old = newValue
            }
        }
    }
    init(name:String, age:Int) {
        self.name = name;
        self.old = age;
    }
    func printData () {
        NSLog("%@ %d", self.name, self.age);
    }
}
var me = Friend(name: "Yohei", age:29)
me.printData();

// タイプメソッド、タイププロパティ
class Exchange {
    class var rate:Double {
        return 102.0;
    }
    class func DollarToYen(d:Double) -> Int {
        return Int(d * rate);
    }
    class func YenToDollar(y:Int) -> Double {
        return Double((y * 100) / Int(rate)) / 100
    }
}
Exchange.YenToDollar(300);

// クラスメソッド
class Rabbit {
    class func sayHello () {
        println("I am a rabbit!")
    }
}
Rabbit.sayHello()


配列

配列は、近年のLL言語の特性も持ち合わせていて、とっても使いやすいです。
// 配列の定義
var array1 = [Int]()
var array2:[Int] = [Int]()
var array3 = [1, 2, 3]
var array4:[Int] = [1, 2, 3]
var array5 = [Int](count:5, repeatedValue:10)

// ループ処理
for (index, value) in enumerate(array5) {
    NSLog("array5[%d]=%d", index, value)
}

// 配列同士の足し算
var array6 = array3 + array4
array6.count; // 6

// append
array6.append(10)

// insert
array6.insert(10, atIndex: 2)

// 最後を削除
array6.removeLast()

// 指定位置を削除
array6.removeAtIndex(1)

// 指定範囲を削除
array6.removeRange(2...4)

// すべて削除
array6.removeAll()

// 要素数
array6.count

// 最初の要素、最後の要素
array6.first
array6.last

// split
var keyword = "aaa bbb"
var terms = split(keyword) {$0 == " "}

// join
var term = "+".join(terms.map{$0})


辞書

Objective-CではNSDictionaryというKey-Value形式のデータ形式がありましたが、Swiftでは辞書形式をより簡単に利用できるようになりました。
// 定義
var dict1:[Int:Int] = [Int: Int]()
var dict2 = [1:"aaa", 2:"bbb", 3:"ccc"]

// for文
for (prop, value) in dict2 {
    NSLog("%d=%@", prop, value)
}

// remove
dict2.removeValueForKey(1)

// remove All
dict2.removeAll()

// keys
dict2.keys

// values
dict2.values

// 件数
dict2.count


構造体

LL言語ライクな書き方になりましたが、ちゃんとCの構造体もサポートしているようです。
struct Member {
    var age:Int
    var name:String
    
    func getData () -> String {
        return "[\(name):\(age)]"
    }
}
var member1 = Member(age: 10, name: "Tom")
var member2 = member1
member2.name = "Jack"
println(member1.getData()) // => Tom:10
println(member2.getData()) // => Jack:10


列挙型

区分値や属性値などの定義に便利な列挙型もサポートされています。Objective-Cから利用できるUITableViewCellStyleをSwiftではenumとして利用することができ、とても便利です。
enum BookType {
    case Sell
    case Rental
}
enum BookType2: Int {
    case Sell = 0
    case Rental = 1
}
var bookType = BookType.Sell;
var bookType2 = BookType2.Rental;
println(bookType)               //=> (Enum Value)
println(bookType2.rawValue)     //=> 1


関数を値で扱う、クロージャー

関数は引数として渡したり、変数に代入できたりします。関数を引数で受け取る関数の定義は、なかなか奇怪な書き方で、まだ慣れませんw。
func addValue (#number:Int) -> Int {
    return number + number
}
var fn = addValue
var fn2:(num:Int)->Int = fn

// クロージャー
func calc (#algo:(num:Int)->Int, #number:Int) -> Int {
    return algo(num: number)
}
calc(algo: fn, number: 10)
calc(algo: fn2, number: 10)

// 関数リテラル
calc(algo: {num in num + num}, number: 10);
calc(algo: {num in
    return num + num
}, number: 10);


プロトコル

Objective-Cでも大活躍のプロトコルは、Swiftでも同じく大活躍します。他の言語でいうところのインターフェース定義です。
protocol MyProtocol {
    func printData()
}
class PersonData: MyProtocol {
    var name:String = ""
    
    init(name:String) {
        self.name = name
    }
    
    func printData() {
        println(self.name)
    }
}


既存クラスの拡張

Swiftでは既に定義済みのクラスに機能を追加できます。JavaScriptの世界では勝手に機能を追加することは良くないお作法とされていますが、Swiftでは果たしてどんな扱いを受けるのでしょうか。
extension Int {
    func getTotal () -> Int {
        var total = 0
        for i in 1...self {
            total += i
        }
        return total;
    }
}
var num1 = 123
println(num1.getTotal())



最後に

Swiftで1アプリを作ってみた感想としては、Objective-Cで学んだことは全部生かすことができると思いました。UITableViewの使い方、Protocolの扱い、Enumの扱いなど、ほとんどは同じような使い方で、Objective-Cの時に学んだ知識を生かすことが出来ました。またSwiftのコードを書きつつ、Objective-Cで書かれた第3者のコードを利用するなどもでき、なかなか楽しい感じです。

Swiftでアプリを作ったところ、10個くらいノウハウとしてブログに書きたいことがたまりましたw。少しずつアウトプットできればと思います。

最後になりますが本ブログでは、フロントエンドのネタを中心に情報を発信しています。気になった方はぜひ、RSSTwitterをフォローして頂けますと幸いです ^ ^。

最後までご覧頂きましてありがとうございました!





こんな記事もいかがですか?

RSS画像

もしご興味をお持ち頂けましたら、ぜひRSSへの登録をお願い致します。