Swift のクラスとプロトコルの書き方及び Objective-C の動作


相互運用性により、Objective-C の動作を組み込んだ Swift コードを書くことができます。Objective-C クラスをサブクラス化し、Objective-C プロトコルを宣言して採用し、Swift コードを書くときに Objective-C の他の機能を利用できます。これは、Objective-C のよく知られた、確立された動作に基づいてクラスとプロトコルを作成し、Swift の現代的で強力な言語機能でそれらを強化できることを意味します。


Objective-C のクラスからの継承


Swift では、Objective-C クラスのサブクラスを定義できます。Objective-C クラスから継承した Swift のクラスを作成するには、コロン(:) を Swift のクラスの名前の後に続け、その後に Objective-C クラスの名前を続けます。


    << SWIFT >>

  1. import UIKit
  2. class MySwiftViewController: UIViewController {
  3.        // define the class
  4. }


Swift のサブクラスは、Objective-C のスーパークラスによって提供されるすべての機能を取得します。


スーパークラスのメソッドの独自の実装を提供するには、override 修飾子を使用します。コンパイラは、Swift のメソッド名と一致する、オーバーライドされた Objective-C メソッドの名前を自動的に推測します。 @objc(name) 属性を使用して、対応する Objective-C シンボルを明示的に指定できます。


Swift クラスが Objective-C 実行環境からの動作を必要とする多くの新しいメソッドまたはプロパティを導入する場合、そのクラスの宣言で @objcMembers 属性を使用します。@objcMembers 属性をクラスに適用すると、@objc 属性がすべての Objective-C 互換メンバに暗黙的に追加されます。と言うのも、@objc 属性を適用すると、アプリのコンパイルされたサイズが増え、パフォーマンスに悪影響を与える可能性があるため、各メンバーが @objc 属性を適用する必要がある場合にのみ宣言に @objcMembers 属性を適用します。


NSCoding


NSCoding プロトコルでは、準拠型が必須イニシャライザ init(coder:) と必須メソッド encode(with:) を実装する必要があります。NSCoding を直接採用するクラスでは、このメソッドを実装しなければなりません。1つ以上のカスタムイニシャライザまたは初期値のない全てのプロパティを持つ NSCoding を採用するクラスのサブクラスでも、このメソッドを実装しなければなりません。


ストーリーボードからロードされたり、NSUserDefaults クラスまたは NSKeyedArchiver クラスを使用してディスクにアーカイブされたオブジェクトの場合、このイニシャライザの完全な実装を提供しなければなりません。ただし、このようにしてインスタンス化することが予想される、またはインスタンス化できない型のイニシャライザを実装する必要はありません。


プロトコルの採用


Objective-C プロトコルは Swift プロトコルとして import され、それは、もしあればクラスのスーパークラスの名前が続く、コンマで区切られたリストの中でクラスによって採用されます。


    << SWIFT >>

  1. class MySwiftViewController: UIViewController, UITableViewDelegate,
    UITableViewDataSource
    {
  2.        // define the class
  3. }


Swift のコードで単一のプロトコルに準拠する型を宣言するには、その型として直接プロトコル名を使用します(Objective-C での id<SomeProtocol> と比較して)。Swift コードで複数のプロトコルに準拠する型を宣言するには、SomeProtocol & AnotherProtocol(Objective-C の id<SomeProtocol,AnotherProtocol> と比較して) という形式から取ったプロトコルコンポジションを使用します。


    << SWIFT >>

  1. var textFieldDelegate: UITextFieldDelegate
  2. var tableViewController: UITableViewDataSource & UITableViewDelegate


注意: クラスとプロトコルの名前空間は Swift で統一されているため、Objective-C の NSObject プロトコルは Swift の NSObjectProtocol に再マッピングされます。


Objective-C プロトコルの要件を満たすために Swift のイニシャライザ、プロパティ、サブスクリプト、またはメソッドを使用すると、コンパイラはオーバーライドされたメソッドの場合と同様に、要件に一致する名前を自動的に推測します。@objc(name) 属性を、対応する Objective-C シンボルを明示的に指定するために使用できます。


イニシャライザとデイニシャライザを書く


Swift コンパイラは、イニシャライザが初期化されていないクラスのプロパティをそのままにしないようにして、コードの安全性と予測可能性を向上させます。さらに、Objective-C とは異なり、Swift では、呼び出すべき個別のメモリ割り当てメソッドがありません。Objective-C クラスを使用している場合でも、Swift の固有の初期化構文を使用できます。Swift は、Objective-C 初期化メソッドを Swift イニシャライザに変換します。独自のイニシャライザの実装の詳細については、Swift プログラミング言語(Swift 4.0.3)イニシャライザを参照してください。


クラスの割り当てを解除する前に追加のクリーンアップを実行したい場合は、dealloc メソッドの代わりにデイニシャライザを実装できます。Swift のデイニシャライザは、インスタンスの割り当て解除が起こる直前に自動的に呼び出されます。Swift は、サブクラスのデイニシャライザを呼び出した後、スーパークラスのデイニシャライザを自動的に呼び出します。Objective-C クラスを使って作業しているとき、または Swift クラスが Objective-C クラスから継承しているとき、Swift はクラスのスーパークラスの dealloc メソッドをさらに呼び出します。独自のデイニシャライザの実装の詳細については、Swift プログラミング言語(Swift 4.0.3)デイニシャライザ を参照してください。


Objective-C API で Swift クラス名を使用する


Swift クラスは、Objective-C コードから使用した場合でも、コンパイルされたモジュールに基づいて名前空間を持ちます。すべてのクラスがグローバルの名前空間の一部であり、同じ名前であってはならない Objective-C とは異なり、Swift クラスは、それらが常駐するモジュールに基づいて曖昧さをなくすことができます。たとえば、MyFramework という名前のフレームワーク内の DataManager という名前の Swift クラスの完全修飾名は MyFramework.DataManager です。Swift アプリのターゲットはモジュール自体なので、MyGreatApp という名前のアプリ内の Observer という名前の Swift クラスの完全修飾名は MyGreatApp.Observer です。


Swift のクラスが Objective-C コードで使用されているときに、名前空間を保持するために、Swift クラスは完全修飾名で Objective-C 実行時環境に公開されます。したがって、Swift クラスの文字列表現で動作する API を操作する場合は、クラスの完全修飾名を含めなければなりません。たとえば、ドキュメントベースの Mac アプリを作成する場合、アプリの Info.plist ファイルに NSDocument サブクラスの名前を提供して下さい。Swift では、アプリまたはフレームワークの名前から派生したモジュール名を含め、ドキュメント・サブクラスのフルネームを使用しなければなりません。


以下の例では、NSClassFromString(_:) 関数を使用して、その文字列表現からクラスへの参照を取得します。Swift クラスを取得するには、アプリの名前を含む完全修飾名が使用されます。




Interface Builder との統合


Swift のコンパイラは Swift クラス用の Interface Builder の機能を有効にする属性を含んでいます。Objective-C の場合と同様に、Swift でアウトレット、アクション、およびライブレンダリングを使用できます。



アウトレットとアクションでの作業


アウトレットとアクションを使用すると、Interface Builder でユーザインタフェース・オブジェクトにソースコードを接続することができます。Swift でアウトレットとアクションを使用するには、プロパティまたはメソッド宣言の直前に @IBOutlet または @IBAction を挿入します。アウトレット・コレクションを宣言するには、同じ @IBOutlet 属性を使用し、型の配列を指定するだけです。


Swift でアウトレットを宣言するときにはアウトレットの型を、暗黙に開封された optional にする必要があります。このようにして、ストーリーボードは実行時に、初期化した後に、アウトレットを接続させることができます。あなたのクラスが、ストーリーボードや xib ファイルから初期化されるときは、アウトレットが接続されていると仮定できます。


たとえば、以下の Swift コードはアウトレット、アウトレット・コレクション、およびアクションを持つクラスを宣言します。


    << SWIFT >>

  1. class MyViewController: UIViewController {
  2.        @IBOutlet weak var button: UIButton!
  3.        @IBOutlet var textFields: [UITextField]!
  4.        @IBAction func buttonTapped(_ sender: UIButton?) {
  5.                print("button tapped!")
  6.        }
  7. }


ライブレンダリング


Interface Builder でライブな、インタラクティブなカスタムビューの設計を可能にするために @IBInspectable@IBDesignable の2つの異なる属性を使用できます。UIView クラスまたは NSView クラスから継承するカスタムビューを作成すると、クラス宣言の直前に @IBDesignable 属性を追加することができます。(インスペクタ·ペイン内のビューのカスタムクラスを設定することで) Interface Builder にカスタムビューを追加した後、Interface Builder はキャンバス内にビューをレンダリングします。


また、ユーザー定義した実行時属性と互換性のある型とプロパティに @IBInspectable 属性を追加することもできます。Interface Builder にカスタムビューを追加した後は、インスペクタでこれらのプロパティを編集できます。


    << SWIFT >>

  1. @IBDesignable
  2. class MyCustomView: UIView {
  3.        @IBInspectable var textColor: UIColor
  4.        @IBInspectable var iconHeight: CGFloat
  5.        /* ... */
  6. }


プロパティ属性の指定


Objective-C ではプロパティは、プロパティの動作についての追加情報を指定する潜在的な属性の範囲を持っています。Swift では、別の方法でこれらのプロパティ属性を指定します。


Strong と Weak


Swift のプロパティは、デフォルトでは strong (強い) です。プロパティがその値として格納されたオブジェクトへの弱い参照を持つことを示すために、weak のキーワードを使用します。このキーワードは、optional のクラス型であるプロパティのためにだけ使用できます。詳細については、属性 を参照してください。


読み/書き可能と読み取り専用


Swift では、readwritereadonly 属性はありません。格納されたプロパティを宣言する場合、let を使うと読み取り専用になり、var を使うと読み/書き可能になります。計算されたプロパティを宣言する場合、getter のみを提供すると読み取り専用になり、getter と setter 両方を提供すると読み/書き可能になります。詳細については、Swift プログラミング言語(Swift 4.0.3)プロパティ を参照してください。


コピーの意味


Swift では、Objective-C の copy プロパティ属性は @NSCopying に変換されます。プロパティの型は NSCopying プロトコルに準拠していなければなりません。詳細については、Swift プログラミング言語(Swift 4.0.3)属性 を参照してください。


コアデータ管理オブジェクトサブクラスの実装


コアデータは NSManagedObject クラスのサブクラス内のプロパティの基本的な格納および実装を提供します。コアデータはまた、対多の関係からオブジェクトを追加または削除するために使用するインスタンスメソッドの実装も提供しています。@NSManaged 属性を使用して、コアデータが実行時に宣言の格納と実装を提供することを Swift コンパイラに通知して下さい。


コアデータモデルの属性または関係に対応する、管理オブジェクトサブクラス内の各プロパティまたはメソッド宣言に @NSManaged 属性を追加して下さい。例えば、文字列属性 "name" と多対多関係 "friends" を持つ "Person" というコアデータの実体を考えてみましょう。


coredataeditor_2x


NSManagedObject サブクラス、Person の対応する Swift コードを生成するために、"Editor" メニューから "Create NSManagedObject Subclass ..." を選択してください。


    << SWIFT >>

  1. // Person+CoreDataClass.swift
  2. import CoreData
  3. class Person: NSManagedObject {
  4.         // Insert code here to add functionality to your managed object subclass
  5. }
  6. // Person+CoreDataProperties.swift
  7. extension Person {
  8.         @NSManaged var name: String
  9.         @NSManaged var friends: NSSet
  10. }


namefriends プロパティはどちらも @NSManaged 属性で宣言され、コアデータが実行時にその実装と格納を提供することを示します。


コアデータモデルの実体で使用する NSManagedObject の Swift のサブクラスを構成するには、Xcode でモデル実体インスペクタ(model entity inspector) を開き、Class フィールドにクラス名を入力し、Module フィールドのドロップダウンリストから"現在の製品モジュール"(Current Product Module) を選択して下さい。


coredatanamespace_2x


プロトコルの宣言


Swift では、Objective-C クラスが準拠できるプロトコルを定義できます。Objective-C クラスが採用できる Swift プロトコルを作成するには、protocol 宣言を @objc 属性でマークします。


    << SWIFT >>

  1. import UIKit
  2. @objc protocol MyCustomProtocol {
  3.         var people: [Person] { get }
  4.         func tableView(_ tableView: UITableView, configure cell: UITableViewCell,
    forPerson person: Person)
  5.         @objc optional func tableView(_ tableView: UITableView, willDisplay cell:
    UITableViewCell, forPerson person: Person)
  6. }


プロトコルは、Objective-C クラスがプロトコルに準拠するために実装しなければならないすべてのイニシャライザ、プロパティ、サブスクリプト、およびメソッドを宣言します。オプションのプロトコル要件は、@objc 属性でマークし、optional 修飾子を付けなければなりません。


Objective-C クラスは、必要なメソッドを実装することによって、Objective-C プロトコルと同じ方法で Swift で宣言されたプロトコルに準拠できます。


<<OBJECTIVE-C>>
  1. @interface MyCustomController: UIViewController <MyCustomProtocol>
  2. @property (nonatomic, strong) NSArray<Person *> *people;
  3. @end
  4. @implementation MyCustomController
  5. @synthesize people;
  6. - (void)tableView:(UITableView *)tableView
  7.                 configure:(UITableViewCell *)cell
  8.                 forPerson:(Person *)person
  9. {
  10.       // Configure cell
  11. }
  12. @end




前:Objective-C の API との相互作用 次:Cocoa フレームワークでの作業
目次
Xcode 9 の新機能

Swift:はじめに
Swift Programming Language
Swift Blog より

  • はじめに(Part I)
  • 基本設定
  • Swift 環境の設定
    Swift のインポートプロセスの理解
  • 相互運用性(Part II)
  • Objective-C API との相互作用
  • 初期化
  • クラスファクトリメソッドとコンビニエンスイニシャライザ
    失敗可能な初期化
    プロパティへのアクセス
    メソッドでの作業
  • id の互換性
  • Any のダウンキャスト
    動的なメソッドの参照
    認識されないセレクタと optional の連鎖
  • ヌル可能性 (Nullabity) と optionals
  • ヌル可能性のない (nonnullable) オブジェクトに Optional をブリッジする
    プロトコルで修飾されたクラス
    軽量級の汎用
    拡張機能
  • クロージャ
  • self をキャプチャする時の強い循環参照を回避する
  • オブジェクトの比較
  • Hash する
  • Swift の型の互換性
  • Objective-C で Swift インターフェースの構成
    動的な送出を要求
  • セレクタ
  • Objective-C メソッドの安全でない呼び出し
    キーとキーパス
  • Swift のクラスとプロトコルの書き方及び Objective-C の動作
  • Objective-C のクラスからの継承
  • NSCoding
    プロトコルの採用
    イニシャライザとデイニシャライザを書く
    Objective-C API で Swift クラス名を使用する
  • Interface Builder との統合
  • アウトレットとアクションを使った作業
    ライブレンダリング
  • プロパティ属性の指定
  • Strong と Weak
    読み/書き可能と読み取り専用
    コピーの意味
    コアデータ管理オブジェクトサブクラスの実装
    プロトコルの宣言
  • Cocoa フレームワークでの作業
  • Foundation
  • ブリッジ型
  • 名前の変更された型
  • 文字列

    配列
    セット
    Dictionary
  • Core Foundation
  • 再マッピングされた型
    メモリ管理オブジェクト
    管理されないオブジェクト
    統合ログオン
    Cocoa 構造体
  • Cocoa デザインパターンの採用
  • デリゲート化
    遅延した初期化
  • エラー処理
  • エラーの catch と処理
    エラーを Optional の値に変換する
    エラーを throw する
    カスタムエラーの Catch と処理
    キー値の監視
    ターゲット・アクション
    シングルトン
    Introspection(内省)
  • 連載
  • ローカライズ
    自動解放プール
    API の利用
    コマンドライン引数の処理
  • C の API との相互作用
  • 原始的な型
  • グローバル定数
  • import された定数の列挙体と構造体
  • 関数
  • 可変個引数の関数
  • 構造体
  • 型メンバとして関数を import
    列挙型
    Option のセット
    ユニオン
    ビットフィールド
    名前のない構造体と union のフィールド
  • ポインタ
  • 定数ポインタ
    可変ポインタ
    自動解放ポインタ
    関数ポインタ
    バッファポインタ
    ヌルポインタ
    ポインタの計算
    データ型サイズの計算
    1回限りの初期化
  • プリプロセッサの指令
  • 簡単なマクロ
    複雑なマクロ
    条件付きコンパイルブロック
  • うまく組み合わせる(part III)
  • 同じプロジェクトでの Swift と Objective-C
  • 「うまく組み合わせる」概観
  • 同じアプリターゲット内からコードを import
  • Objective-C から Swift への import
    Swift から Objective-C への import
  • 同じフレームワークターゲット内からコードを import
  • Objective-C から Swift への import
    Swift から Objective-C への import
    外部フレームワークの import
  • Objective-C からの Swift の使い方
  • Objective-C ヘッダでの Swift クラスまたはプロトコルの参照
    Objective-C クラスで採用可能な Swift プロトコルを宣言
    Objective-C の実装での Swift プロトコルの採用
    Objective-C から使用できる Swift のエラー型の宣言
  • Objective-C インターフェイス用に Swift 名をオーバーライド
  • クラスファクトリメソッド
    列挙型
    Objective-C 宣言を洗練する
    Swift で Objective-C インターフェイスを使用できないようにする
    Objective-C API へ利用可能性情報の追加
    プロダクトモジュールの命名
    トラブルシューティングのヒントと注意
  • 移行(Part IV)
  • Objective-C から Swift への移行
  • 移行のための Objective-C コードの準備
  • 移行プロセス
  • はじめる前に
    作業中に
    見終わったら
    トラブルシューティングのヒントと注意
  • 更新履歴
  • マニュアルの更新履歴












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)