プロパティ

プロパティは、値を特定のクラス、構造、または列挙に関連付けます。格納されたプロパティはインスタンスの一部として定数値と変数値を格納しますが、計算されたプロパティは値を(格納するのではなく)計算します。計算されたプロパティは、クラス、構造、および列挙によって提供されます。格納されたプロパティは、クラスと構造体によってのみ提供されます。

格納および計算されたプロパティは、通常、特定のタイプのインスタンスに関連付けられています。ただし、プロパティをタイプ自体に関連付けることもできます。このようなプロパティはタイププロパティと呼ばれます。

さらに、プロパティオブザーバーを定義して、プロパティの値の変化を監視できます。これには、カスタムアクションで応答できます。プロパティオブザーバーは、自分で定義した格納済みプロパティに追加したり、サブクラスがスーパークラスから継承したプロパティに追加したりできます。

プロパティラッパーを使用して、複数のプロパティのゲッターとセッターでコードを再利用することもできます。

格納されたプロパティ

格納されたプロパティは、特定のクラスまたは構造のインスタンスの一部として格納される定数または変数です。格納されたプロパティは、var キーワードにより変数として格納されたプロパティまたは let キーワードにより定数の格納されたプロパティのいずれかです。

struct FixedLengthRange {
    var firstValue: Int    // 変更できる
    let length: Int     // 初期化後は変更できない
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// the range represents integer values 0, 1, and 2
rangeOfThreeItems.firstValue = 6
// the range now represents integer values 6, 7, and 8

定数の構造体インスタンスの格納されたプロパティ

構造体のインスタンスを作成し、そのインスタンスを定数に割り当てると、インスタンスが可変プロパティとして宣言されていても、インスタンスのプロパティを変更することはできません。

let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// rangeOfFourItems は定数として定義される
rangeOfFourItems.firstValue = 6
// rangeOfFourItems は定数のため、firstValue は変数として定義されているが、変更できない

遅延格納プロパティ

遅延格納ロパティは、その初期値が使用されている最初の時間まで計算されません。宣言の前に lazy 修飾子を記述することにより、遅延格納プロパティを示します。

注意

インスタンスの初期化が完了するまで初期値が取得されない可能性があるため、レイジープロパティは常に var 変数として宣言する必要があります。定数プロパティは、初期化が完了する前に常に値を持つ必要があるため、遅延として宣言することはできません。

遅延プロパティは、プロパティの初期値が、インスタンスの初期化が完了するまで値がわからない外部要因に依存している場合に役立ちます。または必要になるまで実行する必要のない、複雑で計算量の多いセットアップが必要な場合にも役立ちます。

以下の例では、遅延格納プロパティを使用して、複雑なクラスの不要な初期化を回避しています。この例では、DataImporterおよびDataManagerと呼ばれる2つのクラスを定義していますが、どちらも完全には表示されていません。

class DataImporter {
    // 外部ファイルからデータを取り込むが、初期化に時間がかかる
    var filename = "data.txt"
    // データ取得処理
}

class DataManager {
    lazy var importer = DataImporter()
    var data = [String]()
    // データ管理の実装部分
}

let manager = DataManager()
manager.data.append("Some data")
manager.data.append("Some more data")
// この時点でDataImporter のインスタンスはまだ作成されていない

print(manager.importer.filename)
// importer が初めて使用されたので、この時点でインスタンスが作られる

注意

lazy修飾子でマークされたプロパティが複数のスレッドによって同時にアクセスされ、プロパティがまだ初期化されていない場合、プロパティが1回だけ初期化される保証はありません。

格納プロパティとインスタンス変数

Objective-Cの経験がある場合、クラスインスタンスの一部として値と参照を格納する2つの方法が提供されていることをご存知でしょう。プロパティに加えて、インスタンス変数をプロパティに格納されている値のバッキングストアとして使用できます。

Swiftはこれらの概念を単一のプロパティ宣言に統合します。Swiftプロパティには対応するインスタンス変数がなく、プロパティのバッキングストアには直接アクセスしません。このアプローチにより、さまざまなコンテキストで値にアクセスする方法についての混乱が回避され、プロパティの宣言が1つの明確なステートメントに簡略化されます。名前、タイプ、メモリ管理特性など、プロパティに関するすべての情報は、タイプの定義の一部として1つの場所で定義されます。

計算プロパティ

格納プロパティに加えて、クラス、構造体、および列挙体は、実際には値を格納しない計算プロパティを定義できます。代わりに、他のプロパティと値を間接的に取得および設定するためのゲッターとオプションのセッターを提供します。

// ポイントのx座標とy座標をカプセル化
struct Point {
    var x = 0.0, y = 0.0
}

// サイズをカプセル化
struct Size {
    var width = 0.0, height = 0.0
}

// 原点とサイズで長方形を定義
struct Rect {
    var origin = Point()
    var size = Size()
    // センター: 計算プロパティ
    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        set(newCenter) {
            origin.x = newCenter.x - (size.width / 2)
            origin.y = newCenter.y - (size.height / 2)
        }
    }
}

// 新しいRect変数を作成
var square = Rect(origin: Point(x: 0.0, y: 0.0),
                  size: Size(width: 10.0, height: 10.0))
// 計算プロパティでセンターが計算される
let initialSquareCenter = square.center
// センターに新しい値を設定
square.center = Point(x: 15.0, y: 15.0)
// セッターにより原点プロパティが計算・設定される
print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// Prints "square.origin is now at (10.0, 10.0)"

セッターの短縮宣言

struct AlternativeRect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        set {
            // 既定の newValue が使用できる
            origin.x = newValue.x - (size.width / 2)
            origin.y = newValue.y - (size.height / 2)
        }
    }
}

ゲッターの短縮宣言

ゲッターの本体全体が単一の式である場合、ゲッターは暗黙的にその式を返します。

struct CompactRect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            // 暗黙的に Point を返すため、return が不要。
            Point(x: origin.x + (size.width / 2),
                  y: origin.y + (size.height / 2))
        }
        set {
            origin.x = newValue.x - (size.width / 2)
            origin.y = newValue.y - (size.height / 2)
        }
    }
}

読み取り専用の計算プロパティ

ゲッターはあるがセッターがない計算プロパティは、読み取り専用の計算プロパティと呼ばれます。読み取り専用の計算プロパティは常に値を返し、ドット構文を介してアクセスできますが、別の値に設定することはできません。

注意

読み取り専用の計算プロパティを含む計算プロパティは、値が固定されていないため、var キーワードを使用して変数プロパティとして宣言する必要があります。

getキーワードとその中括弧を削除すると、読み取り専用の計算プロパティの宣言を簡略化できます。

struct Cuboid {
    var width = 0.0, height = 0.0, depth = 0.0
    var volume: Double {
        get {
              return width * height * depth
        }
    }
}

// 上記は、次のように getキーワードとその中括弧を削除し、
// 読み取り専用の計算プロパティの宣言を簡略化できます。
struct Cuboid {
    var width = 0.0, height = 0.0, depth = 0.0
    var volume: Double {
        return width * height * depth
    }
}

プロパティオブザーバー

プロパティオブザーバーは、プロパティの値の変化を観察して応答します。プロパティオブザーバーは、新しい値がプロパティの現在の値と同じであっても、プロパティの値が設定されるたびに呼び出されます。

プロパティオブザーバーは、遅延格納プロパティを除き、定義した格納プロパティに追加できます。また、サブクラス内のプロパティをオーバーライドすることにより、プロパティオブザーバーを継承されたプロパティ(格納または計算されたもの)に追加できます。オーバーライドされていない計算されたプロパティのプロパティオブザーバーを定義する必要はありません。計算されたプロパティのセッターで値の変化を観察して応答できるためです。プロパティのオーバーライドはオーバーライドで説明します。

プロパティでこれらのオブザーバーのいずれかまたは両方を定義することができます。

  • willSet 値が格納される直前に呼び出されます。
  • didSet 新しい値が格納された直後に呼び出されます。

willSetオブザーバーを実装すると、新しいプロパティ値が定数パラメーターとして渡されます。willSet実装の一部として、このパラメーターの名前を指定できます。実装内でパラメーター名と括弧を記述しない場合、パラメーターはのデフォルトのパラメーター名 newValue で使用可能になります。

同様に、didSetオブザーバーを実装すると、古いプロパティ値を含む定数パラメーターが渡されます。パラメータに名前を付けるか、デフォルトのパラメータ名oldValueを使用できます。didSetオブザーバ内のプロパティに値を割り当てると、新しい値に置き換わります。

注意

スーパークラスプロパティのwillSetおよびdidSetオブザーバーは、スーパークラス初期化子が呼び出された後、サブクラス初期化子でプロパティが設定されたときに呼び出されます。スーパークラスのイニシャライザーが呼び出される前に、クラスが独自のプロパティを設定している間は呼び出されません。

イニシャライザーデリゲーションの詳細については、「値型のイニシャライザーデリゲーションおよび「クラス型のイニシャライザーデリゲーションを参照してください。

ここでの例だwillSetdidSet、アクションでは。次の例では、と呼ばれる新しいクラスを定義しStepCounterます。これは、人が歩くときに行う歩数の合計を追跡します。このクラスは、歩数計やその他の歩数計からの入力データと一緒に使用して、日常業務中の人の運動を追跡することができます。

// 人が歩くときに行う歩数の合計を追跡する例
class StepCounter {
    var totalSteps: Int = 0 {
        willSet(newTotalSteps) {
            print("About to set totalSteps to \(newTotalSteps)")
        }
        didSet {
            // oldValue はデフォルトのパラメータ名
            if totalSteps > oldValue  {
                print("Added \(totalSteps - oldValue) steps")
            }
        }
    }
}

let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// willSet が呼ばれる: About to set totalSteps to 200
// didSet が呼ばれる: Added 200 steps

注意

オブザーバーを持つプロパティを入出力パラメーターとして関数に渡すと、常にオブザーバーwillSetdidSetオブザーバーが呼び出されます。これは、入出力パラメーターのコピーインコピーアウトメモリモデルが原因です。値は常に、関数の最後でプロパティに書き戻されます。イン・アウトパラメータの動作の詳細な議論については、イン・アウトパラメータを参照。

プロパティラッパー

プロパティラッパーは、プロパティの格納方法を管理するコードとプロパティを定義するコードの間の分離層を追加します。たとえば、スレッドセーフチェックを提供するプロパティや、基になるデータをデータベースに格納するプロパティがある場合は、すべてのプロパティにそのコードを記述する必要があります。プロパティラッパーを使用する場合、ラッパーを定義するときに管理コードを1回記述し、それを複数のプロパティに適用することでその管理コードを再利用します。

プロパティラッパー を定義するには、プロパティwrappedValueを定義する struct、enum、またはクラスを作成します。以下のコードでは、このTwelveOrLess構造により、ラップする値に常に12以下の数が含まれることが保証します。より大きな数を格納するように要求すると、代わりに12が格納されます。

@propertyWrapper
struct TwelveOrLess {
    private var number: Int
    init() { self.number = 0 }
    var wrappedValue: Int {
        get { return number }
        set { number = min(newValue, 12) }
    }
}

注意

上記の例の宣言は、変数numberをprivateとしてマークします。これにより、TwelveOrLessの実装でのみnumberが使用されます。他の場所で記述されたコードは、wrappedValueのゲッターとセッターを使用して値にアクセスし、直接numberを使用することはできません。privateの詳細については、「アクセス制御」を参照してください。

// プロパティーラッパーの例
// プロパティーラッパー 名 "@TwelveOrLess"をプロパティの前に記述する
struct SmallRectangle {@TwelveOrLess 
    @TwelveOrLess var height: Int
    @TwelveOrLess var width: Int
}

var rectangle = SmallRectangle()
print(rectangle.height)
// Prints "0"

rectangle.height = 10
print(rectangle.height)
// Prints "10"

rectangle.height = 24
print(rectangle.height)
// Prints "12"

// プロパティラッパーを使用しないと、SmallRectangleは次のようになります。
struct SmallRectangle {
    private var _height = TwelveOrLess()
    private var _width = TwelveOrLess()
    var height: Int {
        get { return _height.wrappedValue }
        set { _height.wrappedValue = newValue }
    }
    var width: Int {
        get { return _width.wrappedValue }
        set { _width.wrappedValue = newValue }
    }
}

ラップされたプロパティの初期値の設定

上記の例のコードは、TwelveOrLessの定義で初期値 number を指定することにより、ラップされたプロパティの初期値を設定します。このプロパティラッパーを使用するコードでは、ラップされたプロパティに別の初期値を指定できません。たとえば、「SmallRectangle」は、heightまたはwidth の初期値を与え得ることができません。初期値の設定やその他のカスタマイズをサポートするには、プロパティラッパーでイニシャライザーを追加する必要があります。

// ラップされた初期値を設定する例
@propertyWrapper
struct SmallNumber {
    private var maximum: Int
    private var number: Int

    var wrappedValue: Int {
        get { return number }
        set { number = min(newValue, maximum) }
    }

    init() {
        maximum = 12
        number = 0
    }
    // 追加したイニシャライザー
    init(wrappedValue: Int) {
        maximum = 12
        number = min(wrappedValue, maximum)
    }
    // 追加したイニシャライザー
    init(wrappedValue: Int, maximum: Int) {
        self.maximum = maximum
        number = min(wrappedValue, maximum)
    }
}

初期化とイニシャライザーの構文の詳細については、初期化を参照。

プロパティにラッパーを適用し、初期値を指定しない場合、Swiftはinit()イニシャライザーを使用してラッパーを設定します。例えば:

struct ZeroRectangle {
    @SmallNumber var height: Int
    @SmallNumber var width: Int
}

var zeroRectangle = ZeroRectangle()
print(zeroRectangle.height, zeroRectangle.width)
// Prints "0 0"

heightとwidthをラップするインスタンスSmallNumberは、SmallNumber()を呼び出すことによって作成されます。イニシャライザーのコードは、ゼロと12のデフォルト値を使用して、初期ラップ値と初期最大値を設定します。プロパティラッパーは、前述のSmallRectangleで使用したTwelveOrLess例のように、すべての初期値を提供します。その例とは異なり、SmallNumberは、プロパティの宣言の一部としてこれらの初期値の書き込みもサポートしています。

プロパティの初期値を指定すると、Swiftはinit(wrappedValue:)イニシャライザーを使用してラッパーを設定します。例えば:

struct UnitRectangle {
    @SmallNumber var height: Int = 1
    @SmallNumber var width: Int = 1
}

var unitRectangle = UnitRectangle()
print(unitRectangle.height, unitRectangle.width)
// Prints "1 1"

カスタム属性の後に括弧で引数を記述すると、Swiftはそれらの引数を受け入れるイニシャライザを使用してラッパーを設定します。たとえば、初期値と最大値を指定すると、Swiftはinit(wrappedValue:maximum:)イニシャライザーを使用します。

struct NarrowRectangle {
    @SmallNumber(wrappedValue: 2, maximum: 5) var height: Int
    @SmallNumber(wrappedValue: 3, maximum: 4) var width: Int
}

var narrowRectangle = NarrowRectangle()
print(narrowRectangle.height, narrowRectangle.width)
// Prints "2 3"

narrowRectangle.height = 100
narrowRectangle.width = 100
print(narrowRectangle.height, narrowRectangle.width)
// Prints "5 4"

プロパティラッパーに引数を含めることで、ラッパーに初期状態を設定したり、ラッパーの作成時に他のオプションをラッパーに渡したりできます。この構文は、プロパティラッパーを使用する最も一般的な方法です。属性に必要な引数はすべて提供でき、それらはイニシャライザーに渡されます。

プロパティラッパー引数を含める場合、割り当てを使用して初期値を指定することもできます。Swiftは割り当てをwrappedValue引数のように扱い、指定した引数を受け入れるイニシャライザを使用します。例えば:

struct MixedRectangle {
    @SmallNumber var height: Int = 1
    @SmallNumber(maximum: 9) var width: Int = 2
}

var mixedRectangle = MixedRectangle()
print(mixedRectangle.height)
// Prints "1"

mixedRectangle.height = 20
print(mixedRectangle.height)
// Prints "12"

heightをラップするSmallNumberインスタンスは、SmallNumber(wrappedValue: 1) を呼び出すことによって作成されます。これは、デフォルトの最大値12を使用します。widthをラップするインスタンスは、SmallNumber(wrappedValue: 2, maximum: 9)を呼び出すことによって作成されます。

プロパティラッパーから値を投影する

ラップされた値に加えて、プロパティラッパーは投影された値を定義することで追加機能を公開できます。たとえば、データベースへのアクセスを管理するプロパティラッパーは、flushDatabaseConnection()メソッドに投影された値を公開できます。投影された値の名前は、ドル記号($)で始まることを除いて、ラップされた値と同じです。コードは$で始まるプロパティを定義できないため、投影された値は定義したプロパティに干渉することはありません。

上記のSmallNumberの例では、プロパティを大きすぎる数値に設定しようとすると、プロパティラッパーが数値を調整してから保存します。以下のコードは、プロパティラッパーが新しい値を格納する前にプロパティの新しい値を調整したかどうかを追跡するために、SmallNumber構造体にprojectedValueプロパティを追加します。

@propertyWrapper
struct SmallNumber {
    private var number: Int
    var projectedValue: Bool
    init() {
        self.number = 0
        self.projectedValue = false
    }
    var wrappedValue: Int {
        get { return number }
        set {
            if newValue > 12 {
                number = 12
                projectedValue = true
            } else {
                number = newValue
                projectedValue = false
            }
        }
    }
}
struct SomeStructure {
    @SmallNumber var someNumber: Int
}
var someStructure = SomeStructure()

someStructure.someNumber = 4
print(someStructure.$someNumber)
// Prints "false"

someStructure.someNumber = 55
print(someStructure.$someNumber)
// Prints "true"

プロパティラッパーは、投影された値として任意の型の値を返すことができます。この例では、プロパティラッパーは、数値が調整されたかどうかにかかわらず、1つの情報のみを公開するため、そのブール値を予測値として公開します。より多くの情報を公開する必要があるラッパーは、他のデータ型selfのインスタンスを返すことができます。または、ラッパーのインスタンスを投影された値として公開するために戻ることができます。

プロパティゲッターやインスタンスメソッドなど、タイプの一部であるコードから投影されたにアクセスする場合、他のプロパティにアクセスする場合と同様に、プロパティ名の前のselfを省略できます。次の例のコードは、ラッパーのheightwidth を投影された値 $heightおよび$width として参照しています。

enum Size {
    case small, large
}

struct SizedRectangle {
    @SmallNumber var height: Int
    @SmallNumber var width: Int

    mutating func resize(to size: Size) -> Bool {
        switch size {
        case .small:
            height = 10
            width = 20
        case .large:
            height = 100
            width = 100
        }
        return $height || $width
    }
}

プロパティラッパーの構文は、getterとsetterを持つプロパティの単なるシンタックスシュガーであるため、他のプロパティへのアクセスと同じように hightとwidth にアクセスします。たとえば、コードのresize(to:) はheightwidth にプロパティラッパーを使用しアクセスします。resize(to:) を呼び出す場合、.large の switch case は長方形の高さと幅を100 に設定します。ラッパーはこれらのプロパティの値が12を超えないようにし、投影値を true に設定して、値を調整したことを記録します。終わりにreturn文で $height と $width をチェックし、そしてプロパティラッパーがどちらかを調整したかどうかを決定します。

グローバル変数とローカル変数

プロパティの計算と監視に関する上記の機能は、グローバル変数ローカル変数でも使用できます。グローバル変数は、関数、メソッド、クロージャー、またはタイプコンテキストの外部で定義される変数です。ローカル変数は、関数、メソッド、またはクロージャコンテキスト内で定義される変数です。

前の章のグローバル変数とローカル変数はすべて格納された変数です。格納されたプロパティのような格納された変数は、特定のタイプの値のストレージを提供し、その値を設定および取得できます。

計算する変数を定義し、保存された変数のオブザーバーをグローバルスコープまたはローカルスコープで定義することもできます。計算する変数は、値を格納するのではなく計算し、計算するプロパティと同じ方法で書き込まれます。

注意

グローバル定数と変数は、遅延格納プロパティと同様に、常に遅延計算さます。遅延格納プロパティとは異なり、グローバル定数と変数はlazy修飾子でマークする必要はありません。

ローカル定数と変数が遅延計算されることはありません。

タイププロパティ

インスタンスプロパティは、特定のタイプのインスタンスに属するプロパティです。そのタイプの新しいインスタンスを作成するたびに、他のインスタンスとは別に、独自のプロパティ値のセットがあります。

また、そのタイプの1つのインスタンスではなく、タイプ自体に属するプロパティを定義することもできます。作成したそのタイプのインスタンスの数に関係なく、これらのプロパティのコピーは1つしかありません。これらの種類のプロパティは、タイププロパティと呼ばれます

タイププロパティは、すべてのインスタンスが使用できる定数プロパティ(Cの静的定数など)や、すべてにグローバルな値を格納する変数プロパティなど、特定のタイプのすべてのインスタンスに共通の値を定義するのに役立ちます。(Cの静的変数に似ている)。

格納するタイププロパティは、変数または定数にすることができます。計算するタイププロパティは、計算するインスタンスプロパティと同じように、常に変数プロパティとして宣言されます。

注意

格納されたインスタンスプロパティとは異なり、格納されたタイププロパティには常にデフォルト値を与える必要があります。これは、型自体に、初期化時に格納されたタイププロパティに値を割り当てることができる初期化子がないためです。

格納するタイププロパティは、最初のアクセス時に遅延初期化されます。これらは、複数のスレッドから同時にアクセスされた場合でも、1回だけ初期化されることが保証されており、lazy修飾子でマークする必要はありません。

タイププロパティの構文

CとObjective-Cでは、タイプに関連付けられた静的定数と変数をグローバル静的変数として定義します。ただし、Swiftでは、タイププロパティはタイプの定義の一部として、タイプの外側の中括弧内に記述され、各タイププロパティは、サポートするタイプに明示的にスコープされます。

staticキーワードを使用してタイププロパティを定義します。クラスタイプの計算タイププロパティの場合、class代わりにキーワードを使用して、サブクラスがスーパークラスの実装をオーバーライドできるようにすることができます。以下の例は、格納および計算されたタイププロパティの構文を示しています。

struct SomeStructure {
    // 格納するタイププロパティ
    static var storedTypeProperty = "Some value."
    // 計算するタイププロパティ
    static var computedTypeProperty: Int {
        return 1
    }
}
enum SomeEnumeration {
    // 格納するタイププロパティ
    static var storedTypeProperty = "Some value."
    // 計算するタイププロパティ
    static var computedTypeProperty: Int {
        return 6
    }
}
class SomeClass {
    // 格納するタイププロパティ
    static var storedTypeProperty = "Some value."
    // 計算するタイププロパティ
    static var computedTypeProperty: Int {
        return 27
    }
    // オーバーライドできる計算するタイププロパティ
    class var overrideableComputedTypeProperty: Int {
        return 107
    }
}

注意

上記の計算タイププロパティの例は、読み取り専用の計算タイププロパティの場合ですが、計算インスタンスプロパティと同じ構文で読み取り/書き込み計算タイププロパティを定義することもできます。

タイププロパティのクエリと設定

タイププロパティは、インスタンスプロパティと同様にドット構文で、クエリ・セットされます。ただし、タイププロパティは、そのタイプのインスタンスではなく、タイプで照会および設定されます。例えば:

// 格納するタイププロパティへのアクセス
print(SomeStructure.storedTypeProperty)
// Prints "Some value."
SomeStructure.storedTypeProperty = "Another value."
print(SomeStructure.storedTypeProperty)
// Prints "Another value."

// 計算するタイププロパティへのアクセス
print(SomeEnumeration.computedTypeProperty)
// Prints "6"
print(SomeClass.computedTypeProperty)
// Prints "27"

以下の例では、いくつかのオーディオチャネルのオーディオレベルメーターをモデル化する構造の一部として、2つの格納されたタイププロパティを使用しています。各チャンネルには、整数のオーディオレベル010があります。

次の図は、これらのオーディオチャネルの2つを組み合わせてステレオオーディオレベルメーターをモデル化する方法を示しています。チャネルのオーディオレベルが0の場合、そのチャネルのライトはどれも点灯しません。オーディオレベルが10の場合、そのチャネルのすべてのライトが点灯します。この図では、左チャネルの現在のレベルは9であり、右チャネルの現在のレベルは7です。../_images/staticPropertiesVUMeter_2x.png

上記のオーディオチャネルは、AudioChannel構造のインスタンスによって表されます。

struct AudioChannel {
    static let thresholdLevel = 10
    static var maxInputLevelForAllChannels = 0
    var currentLevel: Int = 0 {
        didSet {
            if currentLevel > AudioChannel.thresholdLevel {
                // cap the new audio level to the threshold level
                currentLevel = AudioChannel.thresholdLevel
            }
            if currentLevel > AudioChannel.maxInputLevelForAllChannels {
                // store this as the new overall maximum input level
                AudioChannel.maxInputLevelForAllChannels = currentLevel
            }
        }
    }
}

AudioChannelは、その機能をサポートするために2つの保存されたタイプのプロパティを定義します。最初のthresholdLevelは、オーディオレベルが取り得る最大しきい値を定義します。thresholdLevelは、すべてのAudioChannelインスタンスで定数値10になります。オーディオ信号がより大きい値で受信された場合、このしきい値10に制限されます。

2番目のタイプのプロパティは、maxInputLevelForAllChannelsと呼ばれる変数格納プロパティです。これは AudioChannelインスタンスによって受信された最大入力値を追跡します。最初は初期値0です。

AudioChannel は、格納されたインスタンスのプロパティcurrentLevelを定義します。これは、チャネルの現在のオーディオレベルを 0〜10のスケールで表します。

currentLevelプロパティには、currentLevel が設定されるたびに currentLevelをチェックするプロパティオブザーバdidSetがあります。このオブザーバーは次の2つのチェックを実行します。

  • currentLevelの新しい値が許可された値thresholdLevelより大きい場合、プロパティオブザーバーはcurrentLevelを上限のthresholdLevelに設定します。
  • currentLevelの新しい値が、任意の AudioChannelインスタンスにより以前受信された値よりも大きいの場合、プロパティオブザーバは、maxInputLevelForAllChannels タイププロパティに新しいcurrentLevelの値を格納します。

注意

これら2つのチェックの最初のチェックでは、didSetオブザーバーはcurrentLevel異なる値に設定します。ただし、これによってオブザーバーが再度呼び出されることはありません。

ステレオサウンドシステムのオーディオレベルを表すために、あなたは2つの新しいオーディオチャンネル leftChannel と rightChannelをAudioChannel から作成することができます。

var leftChannel = AudioChannel()
var rightChannel = AudioChannel()

あなたがcurrentLevelにチャンネルを7に設定した場合、あなたはそれを見ることができるmaxInputLevelForAllChannelsタイプのプロパティが 7 に等しくなるように更新されます:

leftChannel.currentLevel = 7
print(leftChannel.currentLevel)
// Prints "7"
print(AudioChannel.maxInputLevelForAllChannels)
// Prints "7"

あなたがcurrentLevelにチャンネルを11に設定しようとした場合、あなたは右チャンネルのcurrentLevelプロパティが、最大値に 10 に制限され、maxInputLevelForAllChannels タイププロパティが 10 に等しくなるように更新されます:

rightChannel.currentLevel = 11
print(rightChannel.currentLevel)
// Prints "10"
print(AudioChannel.maxInputLevelForAllChannels)
// Prints "10"

投稿者: admin

Free Software Engineer

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です