Swift

【GPT監修】Swift言語入門 – 初心者向けの基本文法ガイド

テルプロ

Swift言語の基礎文法をゼロから学び直したいなぁ。

GPTくん

そんな人に向けて、今回の講座を作ってみたよ。

本記事を読むことで
  1. GPT監修の講座でSwiftの基礎文法を効率的に学べる
  2. シンプルな解説と例文により、初学者でもスムーズに理解できる

Swiftの紹介

Swiftとは? – 現代のiOSアプリ開発言語

Swiftは、Appleが2014年に開発したプログラミング言語です。

iOS、macOS、watchOS、tvOSなど、Appleの各プラットフォームでアプリケーションを開発するために使用されます。

Objective-Cに代わる新しい言語として登場し、現代のプログラミング言語の特徴を持ちながら、開発者に優れたパフォーマンス安全性を提供します。

Swiftを使用する理由

Swiftの主な利点は以下の通りです。

  1. 速度:Swiftは高速な実行速度を持ち、Objective-Cと比較しても優れたパフォーマンスを発揮します。
  2. 安全性:Swiftは安全なプログラミングをサポートし、コンパイル時にエラーを検出することで、ランタイムエラーのリスクを軽減します。
  3. 簡潔な構文:Swiftの構文はシンプルで直感的であり、コードの可読性と保守性が向上します。
  4. Playground:SwiftのPlayground機能を利用すれば、コードをリアルタイムで試すことができ、迅速な開発が可能です。
  5. オープンソース:Swiftはオープンソースプロジェクトであり、開発者コミュニティの協力によって継続的に改善されています。

Swiftと他のプログラミング言語の違い

Swiftは、他のプログラミング言語と比較していくつかの違いがあります。

  1. Objective-C:SwiftはObjective-Cと比較して、より簡潔で安全な構文を持ちます。また、SwiftはC言語との互換性を持たないため、より純粋なオブジェクト指向プログラミング言語となっています。
  2. Java:SwiftはJavaと同様に、静的型付け言語ですが、型推論によって型宣言を省略できる場合があります。また、Swiftはオプショナル型を持ち、null安全なプログラミングをサポートしています。
  3. Python:SwiftはPythonと比較して、より高速な実行速度を持っています。一方で、SwiftはPythonよりも厳密な型チェックが行われるため、より安全なコードが書けます。ただし、SwiftはPythonほど簡潔ではありません。

Swift言語入門 – 初心者向けの基本文法ガイド

本コンテンツでは、初心者向けにSwift言語の基本文法を解説します。

シンプルで分かりやすい説明を心がけ、具体的な例を交えて解説していくので、初心者でも安心して理解することができます。一緒に楽しみながら学んでいきましょう。

では早速、本編に入っていきます!

変数と定数

変数と定数は、データを格納するための場所です。

変数は値が変わる可能性があるデータを格納するのに適しており、定数は一度設定された値が変わらないデータを格納するのに適しています。

// 変数の宣言と初期化
var 変数名: データ型 = 初期値

// 定数の宣言と初期化
let 定数名: データ型 = 初期値

例:

// 整数型の変数「age」を宣言し、25を代入
var age: Int = 25

// 文字列型の定数「greeting」を宣言し、"こんにちは、Swift!"を代入
let greeting: String = "こんにちは、Swift!"

基本的なデータ型

Swiftにはいくつかの基本的なデータ型があります。

以下に、よく使われるデータ型を示します。

  1. Int: 整数。例: 42, -7
  2. Double: 倍精度浮動小数点数。例: 3.14, -0.001
  3. Float: 単精度浮動小数点数。例: 3.14, -0.001
  4. Bool: 真偽値。true または false
  5. String: 文字列。例: “Hello, World!”
  6. Character: 文字。例: ‘A’, ‘あ’

条件分岐と繰り返し

条件分岐と繰り返しは、プログラムの流れを制御するための構文です。これらの構文を使って、条件に応じた処理や繰り返し処理を実装できます。

if文:条件によって実行するコードを切り替える

// 変数の宣言と初期化
var 変数名: データ型 = 初期値

// 定数の宣言と初期化
let 定数名: データ型 = 初期値

例:

var temperature: Int = 30

if temperature > 25 {
    print("暑いですね。")
} else {
print("涼しいですね。")
}

for-inループ: 範囲内の各値に対してコードを実行する

for 変数 in 範囲 {
    // 範囲内の各値に対して実行するコード
}

例:

// 1から5までの数字を表示する
for number in 1...5 {
    print(number)
}

whileループ: 条件が真(true)である限りコードを実行する

while 条件式 {
    // 条件式が真(true)である間実行するコード
}

例:

var counter: Int = 1

while counter <= 5 {
    print(counter)
    counter += 1
}

関数:コードを再利用可能なブロックにまとめる

関数とは、特定のタスクを実行するために名前を付けて定義し、呼び出すことができるコードのブロックです。関数は入力パラメータを受け取り、実行後に値を返すことができます。

関数の定義:

func 関数名(仮引数名: データ型) -> 戻り値の型 {
    // 関数本体
    return 戻り値
}

例:

// 2つの数を足し算して結果を返す関数
func addNumbers(number1: Int, number2: Int) -> Int {
    let result = number1 + number2
    return result
}

// 関数を呼び出し、結果を定数に格納
let sum = addNumbers(number1: 5, number2: 3)
print(sum) // 出力: 8

クラスと構造体:カスタムデータ型を作成する

クラスと構造体は、プロパティとメソッドを持つカスタムデータ型を作成するために使用されます。クラスは他のクラスからプロパティとメソッドを継承できますが、構造体は継承できません。

クラスの定義:

class クラス名 {
    // クラスのプロパティとメソッド
}

構造体の定義:

struct 構造体名 {
    // 構造体のプロパティとメソッド
}

例:

// クラスの定義
class Dog {
    var name: String
    var age: Int
    
    func bark() {
        print("\(name)はワンワンと吠える!")
    }
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

// 構造体の定義
struct Point {
    var x: Int
    var y: Int
    
    func description() {
        print("座標は (\(x), \(y)) です。")
    }
}

// クラスのインスタンス化
let dog = Dog(name: "ポチ", age: 3)
dog.bark() // 出力: ポチはワンワンと吠える!

// 構造体のインスタンス化
let point = Point(x: 2, y: 3)
point.description() // 出力: 座標は (2, 3) です。

プロパティとメソッド:データと機能を関連付ける

プロパティは、クラスや構造体に関連付けられたデータであり、メソッドは、クラスや構造体に関連付けられた関数です。

プロパティの宣言:

class クラス名 {
    var プロパティ名: データ型
}

メソッドの宣言:

class クラス名 {
    func メソッド名(仮引数名: データ型) -> 戻り値の型 {
        // メソッド本体
        return 戻り値
    }
}

例:

class Circle {
    var radius: Double
    
    init(radius: Double) {
        self.radius = radius
    }
    
    func area() -> Double {
        return Double.pi * radius * radius
    }
    
    func circumference() -> Double {
        return 2 * Double.pi * radius
    }
}

let circle = Circle(radius: 5)
print("円の面積: \(circle.area())") // 出力: 円の面積: 78.53981633974483
print("円の周囲の長さ: \(circle.circumference())") // 出力: 円の周囲の長さ: 31.41592653589793

イニシャライザ:オブジェクトの初期化

イニシャライザは、クラスや構造体のインスタンスが作成されるときに呼び出される特別なメソッドです。イニシャライザは、オブジェクトの初期状態を設定します。

イニシャライザの宣言:

class クラス名 {
    init(仮引数名: データ型) {
        // イニシャライザの本体
    }
}

例:

class Car {
    var make: String
    var model: String
    var year: Int
    
    init(make: String, model: String, year: Int) {
        self.make = make
        self.model = model
        self.year = year
    }
    
    func description() {
        print("この車は \(year)年式の\(make) \(model) です。")
    }
}

let car = Car(make: "トヨタ", model: "カローラ", year: 2020)
car.description() // 出力: この車は 2020年式のトヨタ カローラ です。

継承:クラスのプロパティとメソッドを引き継ぐ

クラスは、他のクラスからプロパティとメソッドを継承することができます。この機能を利用して、コードの再利用性を高めることができます。

継承の宣言:

class 子クラス名: 親クラス名 {
    // 子クラスのプロパティとメソッド
}

例:

class Vehicle {
    var speed: Double = 0.0
    
    func description() {
        print("速度: \(speed) km/h")
    }
}

class Bicycle: Vehicle {
    var hasBasket = false
}

class Car: Vehicle {
    var numberOfDoors = 4
}

let bicycle = Bicycle()
bicycle.hasBasket = true
bicycle.speed = 15.0
bicycle.description() // 出力: 速度: 15.0 km/h

let car = Car()
car.numberOfDoors = 4
car.speed = 100.0
car.description() // 出力: 速度: 100.0 km/h

プロトコル:特定のプロパティやメソッドが実装されることを要求する

プロトコルは、指定されたプロパティとメソッドを実装することを約束するものです。これにより、異なる型で共通の機能を実装することができます。

プロトコルの宣言:

protocol プロトコル名 {
    // プロトコルが要求するプロパティとメソッドの宣言
}

// プロトコルに準拠する型の宣言
struct 型名: プロトコル名 {
// プロトコルで要求されたプロパティとメソッドの実装
}

例:

// プロトコルの定義
protocol Drawable {
    var color: String { get }
    func draw()
}

// プロトコルに準拠する構造体
struct Circle: Drawable {
    var radius: Double
    var color: String
    
    func draw() {
        print("半径: \(radius) の色: \(color) の円を描画します。")
    }
}

struct Rectangle: Drawable {
    var width: Double
    var height: Double
    var color: String
    
    func draw() {
        print("幅: \(width), 高さ: \(height) の色: \(color) の四角形を描画します。")
    }
}

let circle = Circle(radius: 5, color: "赤")
circle.draw() // 出力: 半径: 5 の色: 赤 の円を描画します。

let rectangle = Rectangle(width: 4, height: 6, color: "青")
rectangle.draw() // 出力: 幅: 4, 高さ: 6 の色: 青 の四角形を描画します。

エラーハンドリング:実行時のエラーを取り扱う

Swiftでは、エラーを取り扱うための特別な構文が用意されています。エラーは、Errorプロトコルに準拠する型で表現されます。

エラーの定義:

enum エラー名: Error {
    case エラーケース1
    case エラーケース2
    // ...
}

エラーを投げる関数:

func 関数名() throws -> 戻り値の型 {
    // エラーを投げる場合
    throw エラー名.エラーケース
    // エラーがない場合
    return 戻り値
}

エラーを捕捉する:

do {
    try 関数名()
} catch エラー名.エラーケース1 {
    // エラーケース1の処理
} catch エラー名.エラーケース2 {
    // エラーケース2の処理
}

例:

enum ValidationError: Error {
    case tooShort
    case tooLong
}

func validateUsername(_ username: String) throws {
    if username.count < 4 {
        throw ValidationError.tooShort
    }
    if username.count > 20 {
        throw ValidationError.tooLong
    }
}

let username = "abc"

do {
    try validateUsername(username)
    print("ユーザー名は有効です。")
} catch ValidationError.tooShort {
    print("ユーザー名が短すぎます。")
} catch ValidationError.tooLong {
    print("ユーザー名が長すぎます。")
}

オプショナル:値が存在しない可能性がある変数の扱い

Swiftでは、値が存在しない可能性がある変数に対して、オプショナル型を使用します。オプショナル型は、値が存在するかどうかに関わらず、型安全を保証します。

オプショナル型の宣言:

var 変数名: データ型? = 値またはnil

オプショナル型のアンラップ:

if let アンラップ済み変数名 = オプショナル変数名 {
    // 値が存在する場合の処理
} else {
    // 値が存在しない場合の処理
}

例:

var age: Int? = 25

if let unwrappedAge = age {
    print("年齢は \(unwrappedAge) 歳です。")
} else {
    print("年齢が不明です。")
}
// 出力: 年齢は 25 歳です。

age = nil

if let unwrappedAge = age {
    print("年齢は \(unwrappedAge) 歳です。")
} else {
    print("年齢が不明です。")
}
// 出力: 年齢が不明です。

クロージャ:無名関数を定義する

クロージャは、名前がなく独立した関数です。クロージャは、変数や定数に格納でき、引数として渡すことができます。

クロージャの定義:

{
    (仮引数名: データ型) -> 戻り値の型 in
    // クロージャ本体
}

例:

let addNumbers = { (number1: Int, number2: Int) -> Int in
    return number1 + number2
}

let result = addNumbers(3, 5)
print(result) // 出力: 8

func performOperation(_ operation: (Int, Int) -> Int, number1: Int, number2: Int) -> Int {
    return operation(number1, number2)
}

let subtractNumbers = { (number1: Int, number2: Int) -> Int in
    return number1 - number2
}

let result2 = performOperation(subtractNumbers, number1: 8, number2: 3)
print(result2) // 出力: 5

ジェネリクス:型をパラメータ化する

ジェネリクスは、型をパラメータ化することで、コードの再利用性を高めるための機能です。ジェネリクスは関数、クラス、構造体、プロトコルに使用できます。

ジェネリクスの宣言:

func 関数名<ジェネリック型>(引数名: ジェネリック型) -> ジェネリック型 {
    // 関数本体
}

例:

func identity<T>(_ value: T) -> T {
    return value
}

let intIdentity = identity(42) // 42
let stringIdentity = identity("Hello, world!") // "Hello, world!"

ガード文:条件を満たさない場合に早期リターン

ガード文は、条件を満たさない場合に早期リターンするために使用されます。これにより、ネストされた条件分岐を減らし、コードの可読性を向上させることができます。

ガード文の使用:

func 関数名() {
    guard 条件 else {
        // 条件を満たさない場合の処理
        return
    }
    // 条件を満たす場合の処理
}

例:

func greet(person: [String: String]) {
    guard let name = person["name"] else {
        print("名前がありません。")
        return
    }
    print("こんにちは、\(name)さん!")
}

greet(person: ["name": "Yuki"]) // 出力: こんにちは、Yukiさん!
greet(person: [:]) // 出力: 名前がありません。

拡張機能:既存の型に新しい機能を追加する

拡張機能は、既存の型に新しいプロパティ、メソッド、イニシャライザ、サブスクリプト、ネスト型、プロトコル準拠を追加することができます。

これにより、既存の型を変更することなく、新しい機能を追加できます。

拡張機能の宣言:

extension 型名 {
    // 新しい機能の実装
}

例:

extension Int {
    var isEven: Bool {
        return self % 2 == 0
    }
}

print(2.isEven) // 出力: true
print(3.isEven) // 出力: false

非同期処理:タスクを並行して実行する

Swiftでは、非同期処理を実現するために、DispatchQueueを使用することが一般的です。これにより、タスクを並行して実行し、効率的なプログラムを作成できます。

非同期処理の例:

import Dispatch

func downloadImage() {
    print("画像のダウンロードを開始します。")
    DispatchQueue.global().async {
        // 長時間かかる処理
        DispatchQueue.main.async {
            print("画像のダウンロードが完了しました。")
        }
    }
}

downloadImage()

まとめ

今回は【ChatGPT監修のSwift文法講座】をご紹介しました。

これらの知識を踏まえ、実践的なプロジェクトを始めてみましょう。コミュニティやドキュメントを活用しながら、必要な機能や設計パターンを学んでいくことが重要です。

Swiftの知識を活用し、多くのプロジェクトに取り組むことで、独自の開発スタイルや問題解決能力を磨くことができます。

今後も、Swiftプログラミングの世界を楽しみ、自分の可能性を広げていってください。

最後までご覧いただきありがとうございました。ではまた!

ABOUT ME
テルプロ
東京都在住のアプリエンジニア。大学では、ソフトウェア開発の研究に取り組む。長期のエンジニアインターンシップを経て、実務スキルを磨き、現在はフリーランスエンジニアとしても活動中。メインはモバイルアプリ開発。IT関連の記事監修も行い、技術の共有と普及に励んでいます。 監修実績(レバテックフリーランス
Flutter関連の書籍を出版しました!