Swift入門
いろいろありまして、先月からiOS開発をやらしていただくことになりました!
今までモバイルはAndroidを基本的にやらしていただいておりましたので、わからないことも多いですが、頑張っていこうと思います!
Swiftについてザッとまとめたことを書きたいと思います。
Swift の特徴
SwiftはPythonやRubyのようなインタプリタ系の言語に近い文法で記述できるので、CやC++ライクなObjective-C に比べると簡単に記述できる。また、Appleの発表によるとPythonやObjective-Cに比べてSwiftはかなり早い。
Swiftには、複数の戻り値、クロージャ、ジェネリクス、タイプインターフェース、名前空間といったイマドキな機能がある。
Swiftは安全でないコードが使用されないような設計になってる。変数は使用前に必ず初期化され、配列や整数はオーバーフローがチェックされ、メモリは自動的に管理されるらしい。
現在のiOSアプリ開発言語の主流である「Objective-C」と共存できる。そのため、開発者は適切だと感じる場合にSwiftを使って、複数の言語で書かれたアプリを作成することができる。
Swiftの構文
コメント、定数、変数、型について
// 一行コメント /* 複数行コメント */ var myVar = 42 myVar = 50 let myConst = 42 myConst = 1 // => error: cannot assign to 'let' value 'myConst' let implicitDouble = 70.0 let explicitDouble: Double = 70 let errorCode = 94 "error code: " + errorCode // => error: could not find an overload for '+' that accepts the supplied arguments println("error code: " + String(errorCode))
コメントはJavaとおなじ。
変数はvar、再代入不可な定数はletを使用。
Swiftはその他おおくの言語と同様に静的型付け言語。プログラム実行前に変数定義が必要。変数定義では代入する値の型から型が推論される。よってもちろん、推論する値がなえればエラーになる。
var message //型を推論できないのでエラーになる。 var message:String //明示的に型をつける
また、キャストについて値が暗黙に他の型に変換されることはない。他の型に変換する必要がある場合、明示的に所望の型のインスタンスを作る。
文字列処理
var name = "Swift" + " " + "Programming" name += " Language" countElements(name) let boyCount = 3 let girlCount = 5 println("There are \(boyCount + girlCount) children.")
文字列オブジェクトに文字列を追加するには+=演算子を使う。文字列の長さはグローバル関数countElementsで分かる。
文字列の空判定にはisEmptyなどがあり、文字列の比較には==や!=を使用するのでかなり直感的に書くことが出来る。
Stringのおもなプロパティは以下のとおり。
- isEmpty (空判定)
- hasPrefix (前方一致)
- hasSuffix (後方一致)
- lowercaseString (小文字変換)
- uppercaseString (大文字変換)
配列
var colours = ["red", "black", "white", "blue"] let names = String[]() // 空配列 colours[0] = "pink" colours += "grey" colours.count for colour in colours { println(colour) }
配列はブラケットを使って定義する。空の配列は、初期化子構文で定義する。
基本的に配列は多数の型は宣言できない。letを使うと定数の再代入不可の配列ができる。
配列の要素にアクセスするには、インデックスをブラケット中に書く。
配列の要素数はcountプロパティー。要素追加は+=演算子で、
要素をイテレートするにはfor-inを使う。直感的。
また、型定義と配列定義を同時にする場合は以下のようになる。
var array[Int] = [1,2,3,4] array[0] //0の範囲にアクセス array[0...1] // 範囲を指定してアクセス
要素操作のためのプロパティ、メッソドは以下のとおり。
- appendメッソド (末尾に要素追加)
- countプロパティ (要素数)
- isEmpty プロパティ (空判定)
- insertメッソド (指定インデックスに要素を挿入)
- removeAtIndexメソッド (指定インデックスの要素を削除)
- removeLastメッソド (末尾の要素を削除)
辞書
var petCounts = ["dog": 2, "cat": 3] var wordCounts = Dictionary<String, Int>() // 空ハッシュ wordCounts["dog"] = petCounts["dog"] wordCounts.count wordCounts.keys wordCounts.values for (pet, count) in petCounts { println(pet + ":" + String(count)) }
ハッシュはブラケットを使って、キーとバリューをコロン区切りにして定義する。
空ハッシュは、初期化子構文で定義する。
ハッシュの要素にアクセスするには、キーをブラケット中に書く。
ハッシュの要素をイテレートするにはfor-inを使う。
配列や変数同様、letで定義すると再代入不可、定義したときに型宣言せず要素も無ければエラーがでる。
よく使うプロパティ、メッソドは以下のとおり。
- indexForKeyメッソド (末尾に要素追加)
- countプロパティ (要素数)
- isEmptyプロパティ (空判定)
- valuesプロパティ (値を取得)
- removeAtIndexメッソド (指定インデックスの要素を削除)
- keysプロパティ (keyを取得)
タプル
複数の要素を組みとして持てる機能。異なる型でも可能。複数のことなるオブジェクトを関連ずけて一組として扱うためのデータ構造。
var fruit = {"apple", 100} fruit.0 //apple fruit.1 //100
タプルのプロパティ名を指定する場合は
var fruit = (name:"apple",price:100) fruit.name //apple fruit.price //100
また一部の要素のみをプロパティ名をつけて残りを省略することも可能。必要な要素のみを取り出す場合は、
var (_, price) = fruit price //100
この例ではpriceに100を代入している。このとき不要な要素はアンダースコアで代入を省略できる。
Optional Value 型
Swiftにはnil値を変数の中に許容できる型としてOptional Value型というものがある。Swiftでは基本的に変数にnil値は代入することができない。
また、??演算子は変数値がnilかどうかを判定して代入を実行することができる。変数がnilの場合は右辺を、変数がnilではない場合は左辺を代入する。
var str = "Hello, " var messsage = "Tanaka Junya" var message:String? = "Hello" message = nil var message2:String = message ?? "Hello" //"Helloが代入される"
また、アンラップという機能があり、nilチェックがアンラップ行こう必要なくなる。
構造体
構造体の初期値は()でかこって宣言し、それぞれのプロパティにたいして:で値をいれる。アクセスするには.を使用。
関数ももてる。
struct Programming { var name:String var number:Int } var programming:Programming = Programming(name:Python, number:1) println(programming.name)
列挙型
enumを使用して列挙型をつくることができる。
rawValueでプロパティにアクセスできる。構造体同様、関数ももてる。
enum Company:String{ case one = "Google" case two = "Microsoft" case three = "Apple" } println(Company.one.rawValue)
制御文
//'for' and 'if' for i in 0...10{ for j in 0...10{ if (i+j)%3==0{ print("⬜︎ ") } else if (i+j)%3==1{ print(" ") } else{ print("⬛︎ ") } } println() } //while var i:Int=0 while i<10{ var j:Int=0 while j<10{ print(j) j++ } println() i++ } //swich var service:Int = 0 switch service{ case 0: println("Google") case 1: println("Microsoft") case 2: println("Apple") default: println("CookBiz") }
if文の分岐条件部分は()の省略ができる。
また、定型文のような形でifでnilをチェックするやる方がある。
var optionalValue:String? = "Tokyo" if let local = optionalValue { println(local) }
この変数optionalValueは、String?で定義しているため、nilが入る可能性がある。この時、if文の条件式で定数localを宣言することによってnilをチェックしている。もし変数optionalValueがnilの場合はlocalにnilが代入されるためprint文がスキップされる。
またSwift1.2からは1つのif letで複数の変数のnilチェックが可能になった。
関数
func out(text:String) -> Int { println(text) var length:Int=countElements(text) return length } var len =out("Hello") println(len)
また、Swiftも引数にデフォルト値を代入することができ、戻り値にタプルを使用することで、複数の戻り値をつけることができる。型もそれぞれ違うものを指定可能。
クロージャは変数や定数に代入することができる関数のオブジェクトである。
var add = {(a:Int, b:Int) -> Int in return a + b } println(add(1,3))
クロージャはオブジェクトとして振舞うため、変数に代入することができる。実行時は変数に引数をわたす。
クロージャは関数の引数にも指定することができ、関数の引数として渡す利点は、開発者が処理を自由に変更できる点です。関数内部のロジックの変更や終了時のコールバックなど様々な利用方法がある。Javaでは、無名クラスを使い似た挙動を表現していた。
let names = ["Chris", "Alex","Ewa","Barry","Daniella"] var backwards = {(s1 : String, s2:String) -> Bool in return s1 -> s2 } sorted(names) sorted(names, backwards)
こちらの例はクロージャを使って文字列をソートしている例。
sorted関数にnamesをわたしてソートしている。sorted関数は引数が1つの場合は昇順でソートし、2つ目の引数を渡すとこれをソートの評価方法とする仕様。
この例では、backwards(降順)というクロージャをつくって引数としてわたし、ソートの挙動を変更している。
クラス
プロパティとメソッドを定義できる。
class Book{ var title:String var price:Int init(title: String, price:Int){ self.title = title self.price = price } func print(){ printIn("書籍情報: \(title) 価格 : \(price)園") } } var book = Book(title:"ハリーポッター", price:3200) book.print()
クラスの継承を行う場合、クラスの後にクラス名を指定し、: につづいて元となる親クラスを指定する。
class Ebook: Book{ var fomat:String init(title: String, price:Int, format:String){ self.format = format super.init(title: title, price: price) } override func print(){ println("書籍情報:\(title) 価格:\(price)円 配布形態:\(format)") } }
Bookクラスを継承したEbookクラス。formatプロパティが追加されていて、メソッドの内容も上書きされている。
上書きするメッソドにはoverrideをつけて宣言する。Javaでいう@Override。
Any型とAnyObject型
型を特定せずに操作できる仕組み。Any型は値、参照、関数など、すべてを表せる。
var any:[Any] = ["text", 123, 4.0]
値を取り出す時は、Any型では取り出せないのでisやasを使う。
AnyObject型はクラスのインスタンスを表す。AnyObject型はAny型にくらべて、範囲が限定される。
Cocoa-APIを使うときはよく登場し、APIを呼び出したときAnyObject型の配列をうけとることがある。(objective-cでは明示的に型付けされた配列を持っていないため)
型の検証と変換
型変換にはasが、型の検証のためにはisがある。
var any:[Any] = ["text",123] for object in any{ if object is String{ println("String") } }
as演算子、as?演算子、as!演算子はダウンキャスト(型変換)に使用。
class Lang{} class Japanese:Lang{} var lang:Lang = Japanese() var jp:Japanese = lang as! Japanese;
Lang型からダウンキャストしてJapanese型に変換している。
必ず成功するときにはas!を使う。
as?を使うと、型変換できない時にnilをかえし、実行時えらーを防ぐ。
asによるキャストは保証された変換の場合にのみしようできる。整数型を浮動小数型に変換する場合。
var value = 1 as Float class Lang{} class Japanese:Lang{} var jp:Japanese = Japanese() var lang:Lang = jp as Lang
アップキャスト時は明治的にasを使用しなくても良い。
値型と参照型
値型は変数への代入の際に、データを一意にコピーして保持する。Swiftでは文字列、配列、辞書、構造体、列挙型、タプルが該当する。
struct SItem{ var name:String var price:Int } var a = SItem( name:"Apple", price:100) var b = a.price println("\(a.price), \(b.price)")
ここでは、SItem構造体aを用意してbに代入しています。代入のあとa.priceを操作してもb.priceには影響しない。出力した結果は"50, 100"となりa,bがそれぞれ独立している。
参照型は、変数への代入の際にデータをコピーして保持できない。どこにデータがあるか、という参照のみを保存し、データを共有している。参照型には、クラスのインスタンスが該当する。
class CItem{ var name:String = "Apple" var price:Int } var x = CItem() var y = x x.price = 50 println("\(x.price), \(y.price)")
この例ではCItemクラスのインスタンスxを生成して、yに代入している。そのあとx.priceを100から50にへんこうしている。出力結果をみると、x.priceだけでなく、y.priceも50になっている。
データを共有したい、先の処理でも変更可能な状態を保持したい場合は参照型を使う。マルチスレッド環境のように複数のスレッドから操作するプログラムの場合は、意図しないタイミングで操作してデータが壊れないように値型を使う。
鬼重要。
プロトコルは構造体とクラスで利用でき、名前の決まったメソッドやプロパティごとに関する約束をプロトコルとよぶ。
class ViewController: UIViewController, UIWebViewDelegate{ }
この例ではViewControllerクラスをつくっている。親クラスにUIViewControllerをもち、UIWebViewDelegateプロトコルに適合させている。開発者が独自のプロトコルを宣言することもできる。
protocol MyProtocol{ func sayHello() -> String }
この例では、MyProtocolというプロトコルを宣言しており、sayHelloの実装を要求していることがわかる。
プロトコルはJavaのインターフェイスににているが、メソッドの実装のみを要求できるjavaと違いプロパティの宣言を実装クラスに要求することができる。
protocol MyProtocol{ var mustBeSettable: Int{ get set} var doesNotNeedToBeSettable: Int{get} } class MyClass: MyProtocol2 { var mustBeSettable:Int init(){ mustBeSettable = 0 } var doesNotNeedToBeSettable : Int{ return mustBeSettable + 100 } }
mustBeSettableプロパティの宣言が要求されているため、MyClassでもプロパティを用意して、initメッソドをで初期化。
プロパティの他に、構造体もプロトコルへの適合を宣言するなど、プロトコルは多くの機能を提供している。
くわしくはこちらdeveloper.apple.com
iOSがんばります!
ところでApple Musicめっちゃいいとおもいます!
つかれた