Swiftの型について

## クラス、構造体、列挙型について
### Swift実践入門より引用

Swiftの型は、クラス、構造体、列挙型として定義できます。標準ライブラリの型の多くは構造体として定義されており、Cocoaのほとんどの型はクラスとして定義されています。 　クラス、構造体、列挙型の3つには、メソッドやプロパティなどの共通の要素が用意されています。本章では、これらの共通要素について説明します。それぞれに固有の要素については次章で解説します。

代表的な型を構成する要素は、型が持つ値を保存するプロパティと、型の振る舞いを表すメソッドの2つです。プロパティは型に紐付いた変数や定数と言い換えることができ、メソッドは型に紐付いた関数と言い換えることができます。この2つに加えて、型を構成する要素には、初期化を行うイニシャライザ、コレクションの要素を取得するサブスクリプト、型内に型を定義するネスト型があります。 　本章では、これらの型を構成する要素について説明します。

インスタンスとは型を実体化したものであり、型に定義されているプロパティやメソッドを持ちます。たとえば、String型の値"abc"はString型のインスタンスであり、append(_:)メソッドなどを持ちます。

```swift
struct 構造体名 {
     構造体の定義
 }

  クラス
 class クラス名 {
     クラスの定義
 }

  列挙型
 enum 列挙型名 {
     列挙型の定義
 }
```

型の内部でのインスタンスへのアクセス 　型の内部のプロパティやメソッドなどの中では、selfキーワードを通じてインスタンス自身にアクセスできます。 　次の例では、SomeStruct型のprintValue()メソッドで、インスタンス自身のvalueプロパティにアクセスするためにselfキーワードを使用しています。

```swift
struct SomeStruct {
     let value = 123

     func printValue() {
         print(self.value)
     }
 }
```

インスタンスそのものではなく、インスタンスのプロパティやメソッドにアクセスする場合、selfキーワードを省略できます。たとえばself.プロパティ名のようなプロパティへのアクセスは、単にプロパティ名に置き換えられます。次の例では、上記の例のself.valueをvalueに置き換えています。

```dart
struct SomeStruct {
     let value = 123

     func printValue() {
         print(value)
     }
 }
```

## 実行できるソースコード
Playgrandで実行できるようになっております。

### クラスについて
クラスは参照型で、継承をサポートしています。クラスは一つ以上のスーパークラスを持つことができ、そのスーパークラスの特性を引き継ぐことができます。

```swift
// クラスの定義
class SampleClass {
    var name: String
    var age: Int

    // 初期化メソッド
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

// クラスのインスタンス化
var sampleClass = SampleClass(name: "John", age: 20)

// クラスのプロパティにアクセス
print(sampleClass.name)  // "John"が出力される
print(sampleClass.age)   // 20が出力される
```

### 構造体について
構造体は値型で、継承をサポートしていません。構造体はプロパティとメソッドを持つことができます。

```swift
import UIKit

 // Structの定義
 struct SampleStruct {
     var name: String
     var age: Int
 }

 // Structのインスタンス化
 var sample = SampleStruct(name: "John", age: 20)

 // Structのプロパティにアクセス
 print(sample.name)  // "John"が出力される
 print(sample.age)   // 20が出力される
```

#### 列挙型
列挙型は値型で、継承をサポートしていません。列挙型は特定の範囲の値を表すことができ、それぞれの値はケースと呼ばれます。

```swift
import UIKit

 // Structの定義
 struct SampleStruct {
     var name: String
     var age: Int
 }

 // Structのインスタンス化
 var sample = SampleStruct(name: "John", age: 20)

 // Structのプロパティにアクセス
 print(sample.name)  // "John"が出力される
 print(sample.age)   // 20が出力される
```

#### イニシャライザ
イニシャライザは、クラス、構造体、または列挙型の新しいインスタンスを作成するための特別なメソッドです。イニシャライザは、インスタンスの初期設定を行い、それぞれのストレージプロパティに適切な初期値を設定します。

```swift
struct SampleStruct {
    var name: String
    var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}
```

#### staticの使用例
staticは、インスタンスではなく型自体に関連付けられたプロパティまたはメソッドを定義します。これは、その型のすべてのインスタンスで共有されます。

```swift
struct SampleStruct {
    static var sharedProperty = "Shared Property"

    static func sharedMethod() {
        print("This is a shared method.")
    }
}

print(SampleStruct.sharedProperty)  // "Shared Property"が出力される
SampleStruct.sharedMethod()  // "This is a shared method."が出力される
```

### ストアドプロパティ
ストアドプロパティは、特定のクラス、構造体、または列挙型のインスタンスに関連付けられた値を保持します。これらのプロパティは、値を「格納」するため、ストアドプロパティと呼ばれます。以下に、ストアドプロパティの使用例を示します。

もっとわかりやすく言うと、値を保持するプロパティと表現されます。

```swift
struct SampleStruct {
    var name: String  // ストアドプロパティ
    var age: Int     // ストアドプロパティ
}

var sample = SampleStruct(name: "John", age: 20)
print(sample.name)  // "John"が出力される
print(sample.age)   // 20が出力される
```

```swift
struct SampleStruct {
    var name: String {
        willSet(newName) {
            print("The name is about to change to \(newName).")
        }
        didSet(oldName) {
            print("The name has just changed from \(oldName) to \(name).")
        }
    }
    var age: Int
}

var sample = SampleStruct(name: "John", age: 20)
sample.name = "Jane"  // "The name is about to change to Jane."と"The name has just changed from John to Jane."が出力される
```

### プロパティオブザーバ
プロパティオブザーバは、プロパティの値が変更される前後にカスタムアクションを実行するための機能です。`willSet`は値が設定される前に呼び出され、`didSet`は新しい値が設定された後に呼び出されます。

```swift
struct SampleStruct {
    var name: String {
        willSet(newName) {
            print("The name is about to change to \(newName).")
        }
        didSet(oldName) {
            print("The name has just changed from \(oldName) to \(name).")
        }
    }
    var age: Int
}

var sample = SampleStruct(name: "John", age: 20)
sample.name = "Jane"  // "The name is about to change to Jane."と"The name has just changed from John to Jane."が出力される
```

### レイジーストアドプロパティ
レイジーストアドプロパティは、そのプロパティが初めてアクセスされるまで初期化が遅延されるプロパティです。`lazy`キーワードを使用して定義します。

```swift
struct SampleStruct {
    lazy var expensiveOperationResult: String = {
        print("Performing expensive operation...")
        // ここで高コストの操作を行う
        return "Result of expensive operation"
    }()
}

var sample = SampleStruct()
print(sample.expensiveOperationResult)  // "Performing expensive operation..."と"Result of expensive operation"が出力される
```

### コンピューテッドプロパティ
コンピューテッドプロパティは、値を格納するのではなく、計算によって値を生成するプロパティです。`get`と`set`キーワードを使用して定義します。

解説
```swift
プロパティ名: 型名 {
get {
         return文によって値を返す処理
     }

     set {
         値を更新する処理
         プロパティに代入された値には定数newValueとしてアクセスできる
     }
 }
```

使用例
```swift
struct SampleStruct {
    var name: String
    var age: Int
    var description: String {
        get {
            return "\(name) is \(age) years old."
        }
        set(newDescription) {
            // 新しい説明を解析して、nameとageを更新する
        }
    }
}

var sample = SampleStruct(name: "John", age: 20)
print(sample.description)  // "John is 20 years old."が出力される
```

### ゲッターについて
`get`(ゲッタ)は、ほかのストアドプロパティなどから、値を取得して、コンピューテッドプロパティの値として返す処理です。値を返すときは、`return`を使います。

### セッター
`set`(セッタ)は、プロパティに代入された値を使用して、他のプロパティなどを更新する処理です。

>セッタ内では、暗黙的に宣言されたnewValueという定数を通じて代入された値にアクセスできます。

## 最後に
Dartを普段書いているのですが、Swiftの学習もまたしてみたいと思い久しぶりに記事を書いてみました。Dartよりもコードやライフサイクルが独特なので、覚えるの大変です😅