はじめに
Swiftは、iOSアプリとOS Xアプリを開発するための新しいプログラミング言語です。C言語とObjective-Cに基づいていますが、C言語の互換性に関する制約の一部はありません。Swiftは安全なプログラミングパターンを採用し、最新の機能を追加することで、プログラミングをより簡単で、柔軟で、楽しいものにしています。インターフェースは、広く人々に愛されているCocoaフレームワークとCocoa Touchフレームワークに基づいており、ソフトウェア開発の新しい方向性を示しています。

Swiftは長年にわたって開発されてきました。Appleは、既存のコンパイラ、デバッガ、フレームワークを基盤として利用してきました。ARC(Automatic Reference Counting、自動参照カウント)により、メモリ管理が簡素化されています。フレームワークスタックは常にCocoaに基づいていました。Objective-Cは、ブロック、コレクションリテラル、モジュールをサポートするように進化し、現代的な言語のフレームワークを詳細を知らなくても使用できるようにしました。こうした基盤作業のおかげで、Appleソフトウェア開発に新しいプログラミング言語を導入することができました。
Objective-C開発者は、Swiftに既視感を覚えるでしょう。SwiftはObjective-Cの名前付きパラメータと動的オブジェクトモデルを採用しています。Cocoaフレームワークとの相互運用性とmix-and-matchを提供します。これらの基盤の上に、Swiftは多くの新機能と、手続き型およびオブジェクト指向の機能を組み合わせた機能を導入しています。
Swiftは、プログラミング初心者にも親しみやすい言語です。Swiftは工業製品レベルの品質を備えたシステムプログラミング言語ですが、スクリプト言語のように親しみやすいものです。Playgroundをサポートしており、プログラマはSwiftコードの一部を試して、アプリをいちいちビルドして実行しなくても、すぐに結果を確認できます。
Swiftは、現代のプログラミング言語の思想と、Appleのエンジニアリング文化の知恵を統合しています。コンパイラはパフォーマンス向けに最適化され、言語は開発向けに最適化されており、互いに妥協する必要はありません。"Hello, world"から学び始め、システム全体へと移行できます。これらすべてにより、SwiftはAppleソフトウェア開発者にとっての革新の源となっています。
Swiftは、iOSアプリとOS Xアプリを開発するための素晴らしい方法であり、今後も新機能の導入を推進し続けます。あなたがSwiftを使って何かを作り出すのを待ちきれません。
Swift入門
新しい言語の学習は、"Hello, world"を表示することから始めるべきです。Swiftでは、それは1行です。
println("Hello, world")
C言語またはObjective-Cのコードを書いたことがあるなら、この構文は見覚えがあるでしょう。Swiftでは、これは完全なプログラムです。入出力や文字列処理のために、別途ライブラリをインポートする必要はありません。グローバルスコープのコードがプログラムのエントリポイントとなるため、main()関数を書く必要もありません。また、各文の後にセミコロンを書く必要もありません。 この入門チュートリアルは、プログラミングタスクを完了するための十分な情報を提供します。まだ理解できないことがあっても心配する必要はありません。説明されなかったことは、すべて本書の後半で詳しく説明されます。
注意:ベストプラクティスとして、この章をXcodeのPlaygroundで開くことができます。Playgroundを使用すると、コードを編集して結果をすぐに確認できます。
単純な値
let を使用して定数を定義し、var を使用して変数を定義します。定数の値はコンパイル時に指定する必要はありませんが、少なくとも1回は代入する必要があります。つまり、定数を使用して値を名付けることができ、一度決定すればよい値を複数の場所で使用できます。
var myVariable = 42 myVariable = 50 let myConstant = 42
注意:ここでの定数の定義は、関数型プログラミング言語における変数に似ており、一度代入すると変更できません。どんどん使いましょう。体に良いです。
定数または変数は、代入される値と同じ型を持つ必要があります。したがって、型を厳密に定義する必要はありません。値を指定すれば定数または変数を作成でき、コンパイラにその型を推論させることができます。上記の例では、初期化値が整数であるため、コンパイラはmyVariableが整数型であると推論します。
注意:型は変数名に結び付けられており、静的型付け言語に属します。これは静的最適化に役立ちます。PythonやJavaScriptなどとは異なります。 初期化値が十分な情報を提供しない場合(または初期化値がない場合)は、変数名の後にコロンで区切って型を書くことができます。
let imlicitInteger = 70 let imlicitDouble = 70.0 let explicitDouble: Double = 70
値が他の型に暗黙的に変換されることは決してありません。値を別の型に変換する必要がある場合は、必要な型のインスタンスを明示的に構築します。
let label = "The width is " let width = 94 let widthLabel = label + String(width)
文字列に値を含める、さらに簡単な方法があります。値を小括弧で書き、その前にバックスラッシュを置きます。例:
let apples = 3 let oranges = 5 let appleSummary = "I have \(apples) apples." let fruitSummary = "I have \(apples + oranges) pieces of fruit."
配列と辞書を作成するには角括弧 "[]" を使用し、その要素にアクセスするには角括弧内にインデックスまたはキーを指定します。
var shoppingList = ["catfish", "water", "tulips", "blue paint"] shoppingList[1] = "bottle of water" var occupations = [ "Malcolm": "Captain", "Kaylee": "Mechanic", ] occupations["Jayne"] = "Public Relations"
空の配列または空の辞書を作成するには、初期化構文を使用します。
let emptyArray = String[]() let emptyDictionary = Dictionary<String, Float>()
型情報を推論できない場合は、空の配列を "[]" と書き、空の辞書を "[:]" と書くことができます。たとえば、型が分かっている変数を設定したり、関数に引数を渡したりする場合です。
shoppingList = [] //去购物并买些东西
制御フロー
条件制御には if と switch を使用します。ループには for-in、for、while、do-while を使用します。小括弧は必須ではありませんが、本体の中括弧は必須です。
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScores += 3
} else {
teamScores += 1
}
}
teamScore
if 文では、条件はブール式でなければなりません。つまり、if score { ... } は誤りであり、暗黙的に0と比較することはできません。 if と let を組み合わせて、値の欠落を防ぐことができます。これらの値はオプショナルです。オプショナル値は、値を含むか、値がまだ存在しないことを示す nil を含むことができます。型の後に疑問符 "?" を書くと、その値がオプショナルであることを示します。
var optionalString: String? = "Hello"
optionalString == nil
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}
注意:オプショナル値が nil の場合、条件は false となり、中括弧内のコードはスキップされます。それ以外の場合、オプショナル値はアンラップされて定数に代入され、アンラップされた値がコードブロック内で利用可能になります。
switch は、さまざまなデータ型とさまざまな比較をサポートしており、整数や等価テストだけに限定されません。
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."
}
注意:
一致するケースを実行した後、プログラムは switch から抜け出し、次のケースを実行し続けることはありません。したがって、switch を抜けるために break は不要です。
for-in を使用して辞書の各要素を反復処理できます。各キーと値のペアを使用するための名前のペアを指定します。
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
}
}
}
while を使用して、条件が変わるまでコードブロックを繰り返し実行できます。ループの条件を末尾に置くと、ループが少なくとも1回は実行されることを保証できます。
var n = 2
while n < 100 {
n = n * 2
}
n
var m = 2
do {
m = m * 2
} while m < 100
m
ループ内でインデックスを保持できます。".." を使用してインデックスの範囲を表すか、初期値、条件、増分を明示的に宣言します。これら2つのループは同じことを行います:
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 を使用して関数を宣言します。関数を呼び出すには、関数名の後に小括弧でパラメータリストを指定します。-> を使用して、パラメータ名と戻り値の型を区切ります。
func greet(name: String, day: String) -> String {
return "Hello \(name), today is \(day)."
}
greet("Bob", "Tuesday")
タプルを使用して複数の値を返すことができます。
func getGasPrices() -> (Double, Double, Double) {
return (3.59, 3.69, 3.79)
}
getGasPrices()
関数は可変個の引数を受け取ることができ、それらは配列に収集されます。
func sumOf(numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
sumOf()
sumOf(42, 597, 12)
関数はネストできます。ネストされた関数は、その関数が定義されている関数の変数にアクセスできます。ネストされた関数を使用してコードを整理し、長すぎたり複雑になりすぎたりするのを防ぐことができます。
func returnFifteen() -> Int {
var y = 10
func add() {
y += 5
}
add()
return y
}
returnFifteen()
関数は第一級の型です。つまり、関数は別の関数を返すことができます。
func makeIncrementer() -> (Int -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)
関数は他の関数をパラメータとして受け取ることができます。
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, 7, 12]
hasAnyMatches(numbers, lessThanTen)
関数は実際にはクロージャの特別な場合です。名前を付けずにクロージャを書くことができ、中括弧の中に置くだけです。in を使用して、パラメータと戻り値を本体から区切ります。
numbers.map({
(number: Int) -> Int in
let result = 3 * number
return result
})
クロージャを書く際には、いくつかのオプションがあります。クロージャの型が既知の場合(たとえばコールバックとして使用される場合)、パラメータと戻り値、またはその両方を省略できます。単一ステートメントのクロージャは、値を直接返すことができます。
numbers.map({number in 3 * number})
パラメータは名前ではなく番号で参照できます。これは非常に短いクロージャで特に便利です。関数の最後の引数として渡されるクロージャは、括弧の直後に置くことができます。
sort([1, 5, 3, 12, 2]) { $0 > $1 }
オブジェクトとクラス
class を使用してクラスを作成できます。プロパティの宣言は、クラスのコンテキスト内にあることを除けば、定数または変数の宣言と同じです。メソッドと関数も同じように書きます。
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
クラス名の後に小括弧を付けることで、クラスのインスタンスを作成できます。ドット構文を使用して、インスタンスのプロパティとメソッドにアクセスします。
var shape = Shape() shape.numberOfSides = 7 var shapeDescription = shape.simpleDescription()
このバージョンの Shape クラスには、重要なものが欠けています。インスタンスを作成する際にクラスを設定するためのイニシャライザです。イニシャライザを作成するには init を使用します。
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A Shape with \(numberOfSides) sides."
}
}
注意:self は、name プロパティと name パラメータを区別するために使用します。イニシャライザの宣言は関数と同じですが、クラスのインスタンスを作成します。各プロパティは、宣言内またはイニシャライザ内で値を代入する必要があります。
deinit を使用してデイニシャライザを作成し、オブジェクトが破棄されるときのクリーンアップ処理を実行します。
サブクラスには、スーパークラスの名前をコロンで区切って記述します。標準のルートクラスを継承する場合に宣言は不要なので、スーパークラスを省略できます。
サブクラスのメソッドは、override をマークすることでスーパークラスの実装をオーバーライドできます。override を付けずにオーバーライドした場合、コンパイラはエラーとみなします。また、コンパイラは、override とマークされていないのにスーパークラスのメソッドをオーバーライドしているメソッドも検出します。
class Square: NamedShape {
var sideLength: Double
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 4
}
func area() -> Double {
return sideLength * sideLength
}
override func simpleDescription() -> String {
return "A square with sides of length \(sideLength)."
}
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()
注意:プロパティは getter と setter を持つことができます。
class EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 3
}
var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
sideLength = newValue / 3.0
}
}
override func simpleDescription() -> String {
return "An equilateral triangle with sides of length \(sideLength)."
}
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
triangle.perimeter
triangle.perimeter = 9.9
triangle.sideLength
perimeter の setter では、新しい値の名前は newValue です。set の後に括弧で別の名前を指定することで、競合しない名前を提供できます。
注意:EquilateralTriangle のイニシャライザには、次の3つの異なるステップがあります:
- プロパティの値を設定する
- スーパークラスのイニシャライザを呼び出す
- スーパークラスで定義されたプロパティの値を変更し、追加の処理を行うために、メソッド、getter、setterもここで使用できます。
計算プロパティが必要ないが、値を設定した後に処理を実行したい場合は、willSet と didSet を使用します。例えば、次のクラスは三角形の辺の長さが長方形の辺の長さと等しいことを保証します。
class TriangleAndSquare {
var triangle: EquilaterTriangle {
willSet {
square.sideLength = newValue.sideLength
}
}
var square: Square {
willSet {
triangle.sideLength = newValue.sideLength
}
}
init(size: Double, name: String) {
square = Square(sideLength: size, name: name)
triangle = EquilaterTriangle(sideLength: size, name: name)
}
}
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
triangleAndSquare.square.sideLength
triangleAndSquare.triangle.sideLength
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
triangleAndSquare.triangle.sideLength
クラスのメソッドと関数には重要な違いがあります。関数のパラメータ名は関数内でのみ使用されますが、メソッドのパラメータ名はメソッドの呼び出しにも使用できます(最初のパラメータを除く)。デフォルトでは、メソッドには同名のパラメータがあり、呼び出し時にはそのパラメータ自体が使われます。メソッド内部で使用するために、2番目の名前を指定できます。
class Counter {
var count: Int = 0
func incrementBy(amount: Int, numberOfTimes times: Int) {
count += amount * times
}
}
var counter = Counter()
counter.incrementBy(2, numberOfTimes: 7)
オプショナル値を扱うとき、メソッドやプロパティと同様に、演算子の前に「?」を書くことができます。「?」の前の値がすでにnilの場合、「?」以降はすべて自動的に無視され、式全体はnilになります。また、オプショナル値がアンラップされ、「?」以降はアンラップされた値として扱われます。どちらの場合も、式全体の値はオプショナル値です。
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") let sideLength = optionalSquare?.sideLength
列挙型と構造体
enum を使用して列挙型を作成します。クラスや他の名前付き型と同様に、列挙型はメソッドを持つことができます。
enum Rank: Int {
case Ace = 1
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescrition() -> String {
switch self {
case .Ace:
return "ace"
case .Jack:
return "jack"
case .Queen:
return "queen"
case .King:
return "king"
default:
return String(self.toRaw())
}
}
}
let ace = Rank.Ace
let aceRawValue = ace.toRaw()
上記の例では、raw値の型が Int であるため、最初のraw値だけを指定できます。後続のraw値は順番に割り当てられます。文字列や浮動小数点数を列挙型のraw値として使用することもできます。
toRaw と fromRaw 関数を使用して、raw値と列挙値を変換できます。
if let convertedRank = Rank.fromRaw(3) {
let threeDescription = convertedRank.simpleDescription()
}
列挙型のメンバー値は実際の値であり、他の方法で書かれたraw値ではありません。実際には、場合によってはraw値が存在します。それは、提供しない場合です。
enum Suit {
case Spades, Hearts, Diamonds, Clubs
func simpleDescription() -> String {
switch self {
case .Spades:
return "spades"
case .Hearts:
return "hearts"
case .Diamonds:
return "dismonds"
case .Clubs:
return "clubs"
}
}
}
let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()
上記でHeartsメンバーを参照する2つの方法に注意してください。hearts定数に代入するとき、列挙メンバー Suit.Hearts は完全名で参照されます。定数の型が明示されていないためです。switch 内では、self の値が既知であるため、列挙メンバーは .Hearts で参照されます。どちらの方法でも、都合のよいほうをいつでも使用できます。
struct を使用して構造体を作成します。構造体は、メソッドやイニシャライザを含む、クラスと同じ多くの動作をサポートします。大きな重要な違いは、コード間の受け渡しは常にコピー(値渡し)であり、クラスは参照渡しであることです。
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \
(suit.simpleDescription())"
}
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
<p><strong>注意:</strong>
列挙型のメンバーはインスタンス値(関連値)を持つことができます。同じ列挙メンバーのインスタンスは異なる値を持つことができます。インスタンスを作成するときに値を割り当てます。関連値とraw値の違い:列挙型のraw値はすべてのインスタンスで同じであり、列挙型を定義するときにraw値を提供します。
例えば、サーバーから日の出と日の入りの時刻を取得する必要があるとします。サーバーは同じ情報または何らかのエラーメッセージを返すことができます。
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)"
}
注意:日の出と日の入りの時刻は、実際には ServerResponse の部分一致によって選択されます。
参考資料
Apple Swiftプログラミング言語入門チュートリアル:http://gashero.iteye.com/blog/2075324
The Swift Programming Language:https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/