カテゴリー別アーカイブ: Swift

[Swift] クロージャ(Closures)のサンプル

objective-cのblocksに変わるものとしてSwiftではモダンなクロージャが導入されています。

 

簡単な例から


var closure = {(valueMap:Dictionary<String,Int>) -> Int in
    var total = 0
    for p in valueMap.values {
        total += p
    }
    return total
}

解説すると
dictionary を引数として Int を返すクロージャを宣言して 変数”closure”に格納しています。
なんだか構文がややこしいように見えますが”in”の前にパラメータ・戻り値、”in”の後に実装を書き、全体を{・・・}で囲っているだけです。
こんな構造
{ (引数) -> (戻り値) in
//実装
}
blocksに比べると随分と分かりやすい構文だと思います。

この変数に格納されたクロージャを使うときは


var populationDict:Dictionary<String,Int>  = [
    "kanazawa":10,
    "komatsu":100000,
    "nanao":50000
]

let population = closure(populationDict)

このように普通の関数呼び出しと同様に使えます。

 
 

呼び出し時にメソッドの型をコンパイラが分かっていたら
こんな感じでパラメータ、戻り値を省略してクロージャを記述できる


// クロージャを受け取る関数を宣言
func logCalcResult(calcFunc:(Double,Double) -> Double ,v1:Double,v2:Double) {
    // v1,v2をパラメータとして受け取った関数(calcFunc)を実行
    let calcResult = calcFunc(v1,v2)
    NSLog("calcResult \(calcResult)")
}

// パラメータ、戻り値を省略したクロージャをインラインで宣言してます
// ※{・・・}の部分
// 引き渡されるパラメータ $0、$1、・・・ って名前で参照
logCalcResult({ return $0 + $1} ,20 ,30)

 

trailing closure って機能も使えます
関数の最後のパラメータがクロージャだった時、引数ブロックの外側にブロックを宣言してクロージャを渡せる
(説明がわかりにくい!)


// こんなclosureを受け取る関数があったとして
func logText(closure:() -> String){
    NSLog(closure())
}

// 呼び出しの "()"の外側に { ... } を宣言してクロージャとして渡せる
logText(){
    return "trailing クロージャ!!"
}

上手く使うとカッコ良くかけますね。
 
 

クロージャなので”Capturing Values”も行われます。
※要するにクロージャが宣言された”環境”への参照をクロージャが保持しちゃう機能

たとえばこんな感じでクロージャを返す関数を用意して


// 月から日までを列挙するクロージャを返す関数
func weekNameEnumBuilder() -> () -> String {
    var weekday = -1
    let names = ["月","火","水","木","金","土","日"]
    
    return { () -> String in
    	//キャプチャしたweekdayをクロージャ内でインクリメント
        weekday++
        if (weekday == names.count) {
            weekday = 0
        }
        return names[weekday]
    }

}

このように実行するとweekdayがキャプチャされている事がわかりますね。


//キャプチャする値はweekNameEnumBuilderの実行時に個別に取得される。
//下記のように2回呼び出すとそれぞれ別の変数(weekday)をキャプチャしていることが分かる
let weekNamesA = weekNameEnumBuilder()
let weekNamesB = weekNameEnumBuilder()

NSLog("Capturing A-1: %@" , weekNamesA())
NSLog("Capturing A-2: %@" , weekNamesA())
NSLog("Capturing B-1: %@" , weekNamesB())
NSLog("Capturing B-2: %@" , weekNamesB())
NSLog("Capturing A-3: %@" , weekNamesA())
//  Capturing A-1: 月
//  Capturing A-2: 火
//  Capturing B-1: 月
//  Capturing B-2: 火
//  Capturing A-3: 水

 
  

注意しなければならない事が1点。
クロージャー内でselfとかの参照をしてしまうと selfからクロージャーへの参照とクロージャーからselfへの参照が発生し、循環参照となってしまうというobjective-cではおなじみの現象がswiftでも発生します。
この問題への解決方法としてもobjective-cと同じように弱参照を行うことになるのですが、Swiftのクロージャではキャプチャリスト(Capture List)という形でクロージャ宣言の直前にキャプチャする対象の参照方式を指定することができます。

下記サンプルの [unowned self] ってのがそれで、selfをunownedで参照するように指定しています。


class Doraemon {
    
    var poket = Dictionary<String,AnyObject>()
    
    init(){
        poket["タケコプター"] = "Takekoputer 9-inch,Late 2013"
    }

    // 引数にstringを受け取り、stringを返すクロージャを生成・返却する
    func checkPocket() -> (String) -> String {
    
        return {
            // キャプチャリストは  [参照方式 対象,参照方式 対象 ・・・] という形で記述する
            // この例では self を unowned で参照
            [unowned self] (itemname:String) -> String in
            
            if self.poket[itemname] {
                return "\(itemname)は持ってるよ。僕ドラえもん。"
            } else {
                return "\(itemname)は今修理中。"
            }
        }
    }
}

    
let dora = Doraemon()
let checkPocket = dora.checkPocket()
NSLog(checkPocket("どこでもドア"))
NSLog(checkPocket("タケコプター"))
// どこでもドアは今修理中。
// タケコプターは持ってるよ。僕ドラえもん。

 
 
 
あと、クロージャや関数を変数に格納する場合が多々あると思います。
その宣言方法をメモっておきます。

// クロージャ、関数を変数に格納する場合の宣言
var funcA:(String) -> (String)

funcA = {
    (a:String) -> String in
    return "hello \(a)"
}

// 実行
funcA("マサオ")


// オプショナル(Optional)だった場合
// 全体をカッコで囲ってオプショナルの指定を行う
var funcB:((String) -> (String))?

funcB = {
    (b:String) -> String in
    return "hello \(b)"
}

// 実行する時はこんな感じ
funcB!("タテオ")


// 戻り値が無かった場合
var funcC:(String) -> ()

funcC = {
    (c:String) in
    println("hello \(c)")
}

funcC("ヒロシ")

[Swift] ジェネリックス(Generics)のサンプル

objective-cで何で使えないんだよ、、、と常々思っていたGenericsもSwiftではもちろん使えます。
最近の開発言語では当たり前の機能ですね。

 

ジェネリックスな関数のサンプル

// 引数で与えられた要素を持ったSwift配列を返す
func toArray<T>(values:T...) -> Array<T> {
    var result = Array<T>()
    for v in values {
        result += v
    }
    return result
}


// こんなふうに呼び出すことが可能
// うーん、ジェネリックス!
let intArray = toArray(1,2,3,4,5,6,7)
let stringArray = toArray("A","B","C")

 
 

ジェネリックスなクラスのサンプル

// IntをキーとしたDictionaryを生成するBuilderクラス
// appendで要素を追加してbuildで作成
class IndexedDictionaryBuilder<T> {
    
    var array = Array<T>()
    
    func append(elm:T){
        array.append(elm)
    }
    
    func build() -> Dictionary<Int,T> {
        var result = Dictionary<Int,T>()
        for (index,elm) in enumerate(array) {
            result[index] = elm
        }
        return result
    }
}


// 使い方
// コンストラクタで型を指定
let builder = IndexedDictionaryBuilder<String>()
builder.append("アガシジィ")
builder.append("ビタエニアータ")
builder.append("エリザベサエ")

// buildするとコンストラクタで指定した型を値に持ったdictionaryを生成する    
let dict:Dictionary<Int,String> = builder.build()
for (key,value) in dict {
    NSLog("第\(key)位 \(value)")
}
// 第1位 アガシジィ
// 第2位 ビタエニアータ
// 第3位 エリザベサエ

 
構文も素直で使いやすいですね。

[Swift] Tuple(タプル)の使い方

タプルって馴染みの無いかたには何ぞや?というものですが、ScalaやPythonなどで多用する超ベンリな値です。
一言で言うと
 複数の値を持った構造体
なんです。
え?そんだけ?なんですけど、
メソッドの戻り値などで使うと今までシコシコ専用のResultクラスを作ったり、みっともなく配列で返したりしてたのがスッキリ解決!

宣言方法

// Tupleはジェネリック型なので下記の宣言だと <String,String,Int> なタプルとなります。
let tupleValue = ("お前の","カーチャン",67)

 
 
この要素へのアクセス方法いろいろ

// tupleの要素を取得する方法で簡単なのはインデックスを指定することだと思う
NSLog("\(tupleValue.0)\(tupleValue.1)\(tupleValue.2)才!!")
//・・ お前のカーチャン67才!!


// まとめて変数に取り出すこともできる
let (word1,word2,age) = tupleValue
NSLog("\(word1)\(word2)\(age)才ですか?")
//・・ お前のカーチャン67才ですか?


// 同様の書き方で必要な項目だけ取り出す場合
let (_,_,motherage) = tupleValue
NSLog("かーちゃん\(motherage)才")

 

SwiftのTupleは要素に名前を付ける事ができるんです。
わかりやすくなりますね。

// Swiftのtupleには要素に名前をつけることができる!
let comic = (title:"にんにくマン",volume:1)

// その場合、名前で参照することができて便利!
NSLog("漫画(A):%@ vol.%d",comic.title,comic.volume)
//・・ 漫画(A):にんにくマン vol.1


// もちろん普通に取り出すことも可能
NSLog("漫画(B):%@ vol.%d",comic.0,comic.1)

 

応用編としてswitchで条件分岐

//switchでの使い方
let gokuu = (name:"悟空",taillength:97)
let vegita = (name:"ベジータ",taillength:105)
let frieza = (name:"フリーザ",taillength:0)

for fighter in [gokuu,vegita,frieza] {
	// 尻尾の長さで判定
    switch fighter {
    case (let name,0):
        NSLog("\(name)、あなたはサイヤ人ではありませんね。。。")
    case (let name,let taillen) where taillen > 100:
        NSLog("\(name)、あなたはサイヤ人の王族ですね!!")
    case (let name,let taillen):
        NSLog("\(name)、あなたは普通のサイヤ人ですね?")
    }
}

 
簡単な複合値であればわざわざクラスを作る必要が無くなってコーディングスピードUP間違い無しです。

[Swift] Optionalの使い方

C#でのNullable、scalaのOptionのようなnull値(nil値)を許容する変数を示します。

いきなりですが、下記のコードはコンパイルできるでしょうか?

var text:String = nil

javaやobjective-cの考えかただと通りますよね。
でもswiftでは通りません。
Stringにはnilを代入できなのです。

でも無いことを示したいこともありますよね。
そんな時にOptionalを使います

var text:String? = nil

Stringの後に付けた”?”がオプショナルの宣言で、値が入ってるか入ってないか分からない変数を示します。
これはStringをラップしたString?という変数という認識で良いのではないかと思います。

このOptionalな値はそのままでは使えません。
ラップしている”中身”を取り出す必要があります。
その時に使うのが !(エクスクラメーションマーク)です

var textOpt:String? = "今日もいいお天気"
let text = textOpt!

この!によってアンラップするときにもし値が存在していなかったらどうなるか?
Swiftではエラーになります。

そこで値の有無をチェックしてから取り出す事となります。


var pockyDayOpt:Int? =  "1111".toInt()

// 判定は普通にifすればOK
if pockyDayOpt {
    var pockyDay = pockyDayOpt!
    NSLog("ポッキーの日:%d",pockyDay)
} else {
    NSLog("今年はポッキーの日を中止にします。")
}

まぁ分かりやすいですが、ちょっと面倒ですよね.
そこでこんな構文でチェックとアンラップを同時に行えます


if let pockyDay = pockyDayOpt {
    NSLog("ポッキーの日:%d",pockyDay)
}

ん?まだ面倒ですか?
確かにOptionがネストしていた場合ではifがネストしてしまいちょっと面倒臭いですね。
例えばこういった構造体があったとして


struct MainDish {
    var dishName:String?
}

struct LunchBox {
    var mainDish:MainDish?
}


// ハンバーグランチ
let lunchA = LunchBox(mainDish:MainDish(dishName:"ハンバーグ"))
// 見たことも無い不思議なおかずランチ
let lunchB = LunchBox(mainDish:MainDish(dishName:nil))
// 衝撃のおかず無しランチ
let lunchC = LunchBox(mainDish:nil)

// ランチをArrayに格納
let lunches = [lunchA,lunchB,lunchC]

LunchBoxのMainDishの名前を出力する場合を考えてみます。


// 普通に書いた場合
for lunch in lunches {
    if let mainDish = lunch.mainDish {
        if let dishname = mainDish.dishName {
            NSLog("今日のランチは \(dishname) だ! やっほ~い!")
        }
        else {
            NSLog("このおかず、、、何だろ?")
        }
    }
    else {
        NSLog("おかずが無いとか。。。")
    }
}

面倒ですね。。

Swiftにはこんな時に便利なOptional-Chainという機能があります。
例を見てもらった方が早そうです。


for lunch in lunches {
    if let dishname = lunch.mainDish?.dishName {
        NSLog("今日のランチは \(dishname) だ! やっほ~い!")
    } else {
        NSLog("まともなおかず食べたい。。。")
    }
}

maindish?.dishName と記述している部分がそれです。
これはmainDishに値が設定されている場合にのみ次のdishNameが評価されます。

ifで判定せずにこんな書き方もOK


let dishName:String? = lunch.mainDish?.dishName?.lowercaseString

 
 
最後に、関数・クロージャの変数がオプショナルだった場合はこのように宣言しますよ

// 全体をカッコで囲ってオプショナルの指定を行う
var funcOpt:((String) -> (String))?

funcOpt = {
    (text:String) -> String in
    return "hello \(text)"
}

// 実行する時はこんな感じ
funcOpt!("タテオ")

 
このOptional、Optional-Chainを使うことによってヌルポが発生する機会は激減することでしょう。

[Swift] 列挙型(Enum)の使い方

SwiftのEnumは強力です。

普通に宣言した場合


enum CameraMakers {
    case Canon , Nikon , Olympus , Panasonic , Sigma , Sony , Hasselblad , PhaseOne
}

// 使い方
// 素直に値を参照できる
var maker = CameraMakers.Nikon
// コンパイラが型を分かっていたらenum型を省略することも可能
maker = .Canon

 

Int値としての列挙型
割り当てられた値は”Raw Value”って呼ばれます


enum Weeks:Int {
    case Sunday = 1,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday
    
    // enumの中にも関数を書けるよ!
    func japaneseCaption() -> String {
        switch self {
            case .Sunday:return "日"
            case .Monday:return "月"
            case .Tuesday:return "火"
            case .Wednesday:return "水"
            case .Thursday:return "木"
            case .Friday:return "金"
            case .Saturday:return "土"
        }
    }
}

// RawValueの参照
NSLog("Tuesday : \(Weeks.Tuesday.rawValue)")
// ・・・ Tuesday : 3 って出力される

// Raw Valueからenumを求める事もできる
let wed:Weeks? = Weeks(rawValue:4);

enumの中に関数を書けるなんてビックリだよね。
 

Stringでも宣言可能


enum IOSDevices:String {
    case iPhone = "アイフォーン"
    case iPad = "アイパッド"
    case iPodTouch = "アイポッドタッチ"
}


// 型がStringなenumでもちゃんと動く
let iphone = IOSDevices(rawValue:"アイフォーン")
if let device = iphone {
    if device == IOSDevices.iPhone {
        NSLog("device is iphone")
    } else {
        NSLog("device is not iphone")
    }
} else {
        NSLog("device is None")
}

 

enumをswitchで判定する


let iphone = IOSDevices.fromRaw("アイフォーン")
if let device = iphone {
    switch device {
    case .iPhone:
        NSLog("device is iphone")
    case .iPad:
        NSLog("device is iPad")
    default:
        NSLog("device is something else.")
    }
}

 

SwiftのEnumのユニークで強力な機能は要素ごとに全く違う値(と呼んで良いのかもわからないけど)を持てる事です


// これは。。。なんと呼べば良いのか?
// discriminated unions とか tagged unions って言うものらしいけど。
enum Lens {
    case FixedFocalLens(String,Int,Double)
    case ZoomLens(String,Int,Int,Double)
}

//使い方
// FixedFocalLens
let ef50f18 = Lens.FixedFocalLens("EF",50,1.8)
let ef100f28L = Lens.FixedFocalLens("EF",100,2.8)

// ZoomLensの値
let ef70_200F4L = Lens.ZoomLens("EF",70,200,4.0)

// 求めた値をswitchで条件分けして出力してみる
let lenslist = [ef50f18,ef100f28L,ef70_200F4L]
for lens in lenslist {
    switch lens {
      case .FixedFocalLens(let name,let focallength,let aperture):
          NSLog("単焦点 \(name) \(focallength)mm F\(aperture)")
    
      // letやvarはパラメータ毎に書くと面倒なので下記のようにまとめて指定できる
      case let .ZoomLens( name, minfocallength, maxfocallength, aperture):
          NSLog("ズームレンズ \(name) \(minfocallength)-\(maxfocallength)mm F\(aperture)")
    }
}
// こんな感じで出力される
// 単焦点 EF 50mm F1.8
// 単焦点 EF 100mm F2.8
// ズームレンズ EF 70-200mm F4.0

これはenumの範疇を超えてるね

[Swift] クラス、プロトコルの宣言

クラス宣言はとてもシンプル

class クラス名:基底クラス {
	
	・・・実装

}

やっぱり構文はシンプルなのが一番

 
いろんな要素を詰め込んだクラスのサンプル


class Programmer {
    
    // プロパティの宣言
    // 普通に宣言
    var name = ""
    // ※今のところprivateな宣言は出来ないっぽい
    

    // セッター、ゲッターの指定
    var _company:String?
    var company:String? {
      get {
        return _company
      }
      set(newValue){
        _company = newValue
      }
    }
    //※ セッター、ゲッターの指定は他のプロパティから計算で求められたり、
    //  計算結果を他のプロパティに格納するような場合に使うと良いと思う。
    //  この例は良くないね。

    
    // 遅延評価するプロパティ
    // ※最初に参照された時に初期化される
    @lazy var skills = Array<String>()
    
    
    // ReadOnlyなプロパティ
    var displayName:String {
    	if let cmp = company {
        	return "\(name)@\(cmp)"
    	} else {
        	return "\(name)"
        }
    }

    
    // プロパティオブザーバー
    // プロパティの値が変更する前後に処理を行う
    var experienceYears:Int = 0 {
    	
    	// willSetではプロパティに値が設定される直前に処理を行うことができる
    	willSet(newValue){
        	NSLog("経験年数が\(experienceYears)から\(newValue)に変更されようとしています。")
    	}

    	// didSetでは値が登録された後に処理を行うことができる
    	didSet {
        	//didSetでは変更前の値が oldValue として参照できる
        	NSLog("経験年数が\(oldValue)から\(experienceYears)に変更されました!")
        	if (experienceYears > 100){
            	// 値を再設定することも出来る
            	NSLog("でも何かの間違いなので元に戻します。")
            	experienceYears = oldValue
        	}
    	}
    }
    


    // subscript
    // C#のインデクサ的なもの    
    subscript(index:Int) -> String {
        get{
            return skills[index]
        }
        set(newValue){
            if skills.count <= index {
                skills += Array(count:index - skills.count + 1,repeatedValue:"")
            }
            skills[index] = newValue
        }
    }
    // ※ subscript(row: Int, column: Int) のように複数のパラメータを受けるように宣言することも可能

    
    
    // タイププロパティ(Type - Property)
    // クラス変数、スタティックプロパティのように理解すればよいか?
    // ※ まだ対応されていないようです
    // class var dislike = "I hate Change Request!!"
    
    

    // イニシャライザの定義
    init(name:String){
        self.name = name
    }
    
    // コンビニエンス イニシャライザ
    convenience init(){
        // 自身のinitを呼び出す必要がある
        self.init(name:"(匿名)")
    }
    
    // デイニシャライザ(?)
    // デストラクタ的なやつ
    deinit {
        // ・・・リソースの開放を行う
    }
    


    // メソッドの定義
    // 普通ですね
    func skillCaption() -> String {
        var result = ""
        for skill in skills {
            result += " \(skill)"
        }
        return result
    }
    
    
    func program(){
        NSLog("やってもやっても終わらない!")
    }
    
}

 
このクラスprogrammerを継承


class SwiftProgrammer:Programmer{

    // initではsuperのinitを呼び出さないとエラーとなる
    init(name:String){
        super.init(name:name)

        skills.append("swift")
    }
    

    // オーバーライド
    override func program(){
        NSLog("Swiftだと仕事が早い!不思議!")
    }
    

    // プロパティのオーバーライド
    override var company:String? {
    	get {
        	return "SwiftCompany-" + (_company ? _company! : "")
    	}
    	set(newValue){
        	super.company = newValue
    	}
    }
}

  

 
プロトコル
もうobjective-cとか気にせずにインターフェースって呼べばいいのにね。


// プロトコルの宣言
protocol Agiler {
    
    // プロパティの宣言
    var canRefactoring:Bool { get set }
    
    // メソッドの定義
    func scrum() -> String
    
}

// プロトコルの実装
class AgileProgrammer:Programmer,Agiler{
    
    init(name:String){
        canRefactoring = false
        super.init(name:name)
    }
    
    
    // protocol[Agiler]の実装
    
    var canRefactoring:Bool
    
    func scrum() -> String {
        return "スクラム"
    }
    
}

 

クラスのインスタンスを生成するときはnewとか不要



    let programmerA = Programmer()
    programmerA.company = "りんごコンピュータ"
    programmerA.experienceYears  = 5
    programmerA.experienceYears  = 200
    programmerA[0] = "swift"
    programmerA[1] = "objective-c"
    
    NSLog("A displayName:\(programmerA.displayName) skills:\(programmerA.skillCaption()) career:\(programmerA.experienceYears)")
    
    
    // コンビニエンスイニシャライザを使ってインスタンス化
    let programmerB = Programmer(name:"まさお")
    NSLog("B displayName:\(programmerB.displayName)")
    
    // 継承されたクラスをインスタンス化
    let programmerC = SwiftProgrammer(name:"ひろし")
    programmerC.company = "ゴーグル"
    NSLog("C displayName:\(programmerC.displayName)")

インスタンスのメモリはARCによって管理されるので明示的な廃棄処理は不要です。

[Swift] 関数・メソッドの宣言

関数やメソッドの宣言方法についてまとめてみました。

 

関数の基本形は下記みたいな感じです

引数は 名称:型 で指定
戻り値の型を “->” で指定


func laughText(text:String) -> String {
    return text + "(笑)"
}

// 引数も戻り値も無い時
func logNow() {
    NSLog("現在時刻:%@",NSDate.date())
}

 

パラメータ名の宣言ってのも出来ます


// 外部パラメータ名(下記だとvalueFirst,valueSecond)と
// 内部パラメータ名(下記だとvalue1,value2)をそれぞれ個別に宣言。
func calcPair(valueFirst value1:Double ,valueSecond value2:Double ) -> Double {
    return value1 + value2
}

// これを呼び出すときには
let v = calcPair(valueFirst: 1, valueSecond: 50)

objective-cのメソッド呼び出しのようですね。
 

ちなみに内部と外部で同じ名前とする場合には#(シャープ)を指定すればOK


// この場合は内部・外部ともに同じ名前が使われる
func calcPair2( #valueFirst:Double , #valueSecond:Double ) -> Double {
    return valueFirst + valueSecond
}

 

In-Outパラメータ
引数のポインタ渡し的なやつ


func arrangeTwo(inout largeVal:Int ,inout smallVal:Int){
    if (largeVal < smallVal){
        let t = smallVal
        smallVal = largeVal
        largeVal = t
    }
}

//呼び出すときは&を付けて変数を引き渡します
var valA:Int = 50
var valB:Int = 70
arrangeTwo(&valA,&valB)
NSLog("valA\(valA) valB:\(valB)")

 

可変長パラメータ
型の後ろに “…” と余韻(?)を残すことで可変長引数になる


func totalNumbers(numbers:Double...) -> Double {
    var result:Double = 0
    for v in numbers {
        result += v
    }
    return result
}

//呼び出し方
let totalnum = totalNumbers(1,2,3,4,5,6,7,8,9)
NSLog("total:\(totalnum)")

  

 
Swiftは関数もscala等と同様にfirst-classなので引数に直接渡せちゃいます。


// 引数 calcFunc -- Doubleを2つ引数で受け取りってDoubleを返すメソッド
// 引数 v1,v2  -- 計算対象のDouble値
func logCalcResult(calcFunc:(Double,Double) -> Double   ,v1:Double,v2:Double) {
    // v1,v2を引数として関数(calcFunc)を実行
    let calcResult = calcFunc(v1,v2)
    NSLog("calcResult \(calcResult)")
}


//呼び出し方
logCalcResult(calcPair,12,33)

 

同様に戻り値として関数を返す事もできます


func goodmorning(l:String) -> (String)->(String) {
    
    func sayEnglish(name:String) -> String {
        return "Good morning,\(name) "
    }
    func sayJapanese(name:String) -> String {
        return "\(name) おはよ〜 "
    }
    
    // 戻り値として関数sayEnglish or sayJapanese を返す
    if (l == "english"){
        return sayEnglish
    }
    else {
        return sayJapanese
    }
}

// 使い方
// 戻り値の関数を変数に格納
var speakfunc = goodmorning("english")
// 実行
NSLog(speakfunc("たろう"))
// ・・・ Good morning,たろう

 
関数型言語のように関数が通常の変数同様の扱いとなっているのが今風で良いですね。

[Swift] ループ制御 (繰り返し処理)

Swiftのループ構文をまとめてみました。
 

forループ


// 普通のCスタイルなループ
for var i = 0 ; i < 10 ; i++ {
    // do something
    NSLog("for statement i:\(i)")
}

// Rangeを使った for-in ループ
// "..<"で終端-1までの数値範囲を示すことができる
for i in 0..<10 {
    // 0〜9でループ
    NSLog("for-in statement i:\(i)")
}

// "..." の時は終端の数値も含める
for i in 0...10 {
    // 0〜10でループ
    NSLog("for-in statement2 i:\(i)")
}

 

次はwhileを使ったループ


// whileループ
// ごく一般的な書き方ですね。
var counter = 0
while counter < 3 {
    // do something
    NSLog("while statement counter:\(counter)")
    counter++
}

// do-whileも一般的な文法
counter = 3
do {
    // 最初の1回は無条件で実行される
    NSLog("do-while statement counter:\(counter)")
    counter++
} while counter < 3

 
 

Swiftのループは break、continue にも対応しています。


// nilはスキップ(continue)して999で終了(break)しています
var total = 0
let list:Array<Int?> = [1,2,nil,4,5,6,-1,999]
for v in list {
    if let intVal = v {
        if (intVal == 999) {
            break
        }
        
        total += intVal
    }
    else {
        continue
    }
}
NSLog("total: \(total)") // total: 17

 

ラベル付きのループにも対応しています。
[ラベル名]: for
のようにループの前にコロンで区切ってラベルを定義します。


let programmers = [
    ("まさし",["サボりぐせ","C#","java"]),
    ("ひろし",["Swift","Oracle","VPN"])
    ]
// ラベル付きのループ
programmersLoop: for (name,skills) in programmers {
    for skill in skills {
        if (skill == "サボりぐせ") {
            NSLog("%@さん、あなたは帰ってください。",name)
            // 外側のループに対してcontinue 
            // 便利!
            continue programmersLoop
        }
        NSLog("%@さん、あなた %@も出来るんですね!",name,skill)
    }
}

これは便利ですね。
この例ではforにラベルを付けているけど、whileでももちろんOK

[Swift] Dictionaryの使い方

SwiftのDictionaryを使ってみた。
よくあるHashmap的なやつね。
 

宣言はこんな具合


// 空Dictionaryの宣言
var emptydictionaly = Dictionary<String,Int>()

// Dictionalyの宣言
// ※型は省略可能です
var populationDict:Dictionary<String,Int>  = [
    "kanazawa":10,
    "komatsu":100000,
    "nanao":50000
]

 

保存している値へのアクセス方法


// 値の取得
// Dictionalyから値を求めるとoptionalな値が帰ってくる
let kanazawaOpt = populationDict["kanazawa"]
NSLog("kanazawa population:%d",kanazawaOpt!)


// 値の追加
populationDict["kaga"] = 60000
populationDict.updateValue(38000,forKey:"suzu")


// 値の上書き
// こんな素直な書き方も可能だけど
populationDict["kanazawa"] = 1000000

// updateValueを使うと変更前の値をOptionalで取得できる
if let oldvalue = populationDict.updateValue(460000,forKey:"kanazawa") {
    NSLog("old kanazawa population:%d",oldvalue)
}


// 要素の削除
// nilを入れることで要素が削除される
populationDict["nanao"] = nil

// removeValueForKeyを使うと削除と同時に古い値を取得できる
if let oldvalue = populationDict.removeValueForKey("komatsu") {
    NSLog("old komatsu population:%d",oldvalue)
}


// ちなみにletでDictionalyを宣言すると要素を変更することができない
// ※arrayではletでも上書きできちゃう。。
let immutableDict = ["A":1]
// ↓でエラーとなる
//immutableDict["A"] = 2

 

要素の列挙、ループ処理


var totalPopulataion = 0

// for-each的なループ
// キーと値を一緒に取得
for (city,population) in populationDict {    
    totalPopulataion += population
}
NSLog("合計:\(totalPopulataion)")


// キーのみを求めてループ
for city in populationDict.keys {
    NSLog("city:\(city)")
}

 

Dictionalyは構造体(Structure)なので値型!
なので下記では複写元と複写先では違う値が取得される


// 参照を別の変数に代入して値を書き換える
populationDict["kanazawa"] = 460000
var copiedDict = populationDict
copiedDict["kanazawa"] = 90000

// でも元の値は書き換わっていない
NSLog("populationDict:%d copiedDict:%d",populationDict["kanazawa"]!,copiedDict["kanazawa"]!)
// ・・・ populationDict:460000 
//        copiedDict    :90000

 

[Swift] コレクション(Array)のループ速度比較

下記の3パターンで速度比較を行ってみた
・パターンA
 Cスタイルなループカウンタを使ったforループ
 objective-cでは遅かったが。。。

・パターンB
 enumerateを使ったfor-inループ
 要素のループと同時にindexを求めることが可能
 きっと遅いな。これは。

・パターンC
 for-inループ(objective-cのFast Enumeration)
 直接indexは求めることが出来ないけどきっと速いはず

実行時間を取るためにこんな関数を用意して


func currentTime() -> Double {
    return ((CFAbsoluteTimeGetCurrent() as Double) * 1000.0)
}

下記のコードで検証しました


// 10万要素の配列を作成
// こういったデータもSwiftでは簡単に作成できます。
let testValues = Array(count:100000,repeatedValue:2)

var total = 0,startTime=0.0,interval=0.0

// パターンA
// Cスタイルなforループ
total = 0
startTime = currentTime()
for var i = 0; i < testValues.count; i++ {
    total += testValues[i]
}
interval = currentTime() - startTime
NSLog("patttern-A takes \(interval)ms total:\(total)")

// パターンB
// enumerateを使った for-in ループ
// scalaの zipWithIndex みたいなやつ
total = 0
startTime = currentTime()
for (index,v) in enumerate(testValues){
    total += v
}
interval = currentTime() - startTime
NSLog("patttern-B takes \(interval)ms total:\(total)")


// パターンC
// indexを求めない for-in ループ(foreachだね)
total = 0
startTime = currentTime()
for v in testValues {
    total += v
}
interval = currentTime() - startTime
NSLog("patttern-C takes \(interval)ms total:\(total)")

結果は速い順で a > c > b の結果となった
実際の計測結果はまだいろいろ問題がありそうなので伏せておきますが、
一番速かったAを100%とした場合Bが159%、Cが123%の実行時間でした。
※これは処理順を変えても同様だった

予想通りenumerate を使ったループが一番遅かった。
予想と違ったのはパターンCよりパターンAが速かった事。objective-cでは要素をインデックスによって求めると遅かったけどSwiftでは気にしなくていいみたい。

AとBでは約1.6倍の処理速度差があるので、大量データの処理時には気をつけたほうが良いかもね。

(2014-09-19追記)
XCode6.0.1で再検証すると、パターンAとCではほとんど差が無くなりました。
それでも2〜3%ほどパターンAの方が速いですが、コードの見やすさを考えると積極的にパターンCを使って良いのではないかと。