[解決済み] Swift の拡張機能でメソッドをオーバーライドする
質問
私は、必要なもの(ストアドプロパティやイニシャライザ)だけをクラス定義に入れ、それ以外はすべて独自の
extension
のようなものです。
extension
でグループ化し、論理ブロックごとに
// MARK:
も同様です。
例えばUIViewのサブクラスでは、レイアウト関連の拡張機能、イベントの購読と処理などの拡張機能を持つことになります。これらの拡張機能では、必然的にいくつかのUIKitのメソッドをオーバーライドする必要があります。
layoutSubviews
. この方法で問題に気づいたことはありませんでした -- 今日まで。
例えば、このクラス階層を考えてみましょう。
public class C: NSObject {
public func method() { print("C") }
}
public class B: C {
}
extension B {
override public func method() { print("B") }
}
public class A: B {
}
extension A {
override public func method() { print("A") }
}
(A() as A).method()
(A() as B).method()
(A() as C).method()
出力は
A B C
. それは私にはほとんど意味がありません。プロトコル拡張は静的にディスパッチされると書いてありましたが、これはプロトコルではありません。これは普通のクラスで、メソッドの呼び出しは実行時に動的にディスパッチされると思います。明らかに
C
は、少なくとも動的にディスパッチされて
C
?
から継承を外すと
NSObject
を作成し
C
をルートクラスとすると、コンパイラは次のような文句を言います。
declarations in extensions cannot override yet
というのは、すでに読んだことがあります。しかし、どのようにして
NSObject
をルートクラスとして使用すると、状況は変化するのでしょうか?
両方のオーバーライドをクラス宣言に移動させると
A A A
を移動させると、予想通り
B
が生成されます。
A B B
移動のみ
A
が生成されます。
C B C
を静的に型付けしたものでさえ、私には全く意味がありません。
A
を生成します。
A
-を出力するようになりました。
を追加することで
dynamic
キーワードを定義またはオーバーライドすることで、「クラス階層内のその時点から下」の望ましい動作が得られるようです...
この質問を投稿するきっかけとなったのは、この例から少し離れたところにあるのですが、例を変えてみましょう。
public class B: UIView {
}
extension B {
override public func layoutSubviews() { print("B") }
}
public class A: B {
}
extension A {
override public func layoutSubviews() { print("A") }
}
(A() as A).layoutSubviews()
(A() as B).layoutSubviews()
(A() as UIView).layoutSubviews()
これで
A B A
. ここで、UIViewのlayoutSubviewsをどう考えてもダイナミックにすることができない。
両方のオーバーライドをクラス宣言に移すと、次のようになります。
A A A
また、Aのみ、Bのみでも、やはり
A B A
.
dynamic
は、私の問題を解決してくれました。
理論的には
dynamic
に、すべての
override
しかし、私はここで何か他の間違ったことをしているような気がするのです。
を使用することは本当に間違っているのでしょうか?
extension
は、私のようにコードをグループ化するために使用するのですか?
どのように解決するのですか?
拡張機能がオーバーライドできない/してはいけない。
Apple の Swift Guide に記載されているように、エクステンションの機能 (プロパティやメソッドなど) を上書きすることはできません。
拡張機能は、型に新しい機能を追加することはできますが、既存の機能を上書きすることはできません。
コンパイラは、Objective-Cとの互換性のために、拡張機能でオーバーライドすることを許可しています。しかし、実際には言語指令に違反しているのです。
アイザック・アシモフの「"」を思い出したよ。 ロボット工学の三原則 ということです。
拡張機能 (
構文糖
) は、それ自身の引数を受け取る独立したメソッドを定義します。に対して呼び出される関数、すなわち
layoutSubviews
は、コードがコンパイルされたときにコンパイラが知っているコンテキストに依存します。UIView は NSObject を継承した UIResponder を継承しています。
そのため、拡張機能でのオーバーライドは許可されていますが、そのようなことはすべきではありません。
.
つまり、グループ化することは悪いことではありませんが、拡張機能ではなくクラスでオーバーライドする必要があります。
ディレクティブの注意点
を使用することができます。
override
スーパークラスのメソッド、すなわち
load()
initialize()
を、Objective-C互換のメソッドであれば、サブクラスの拡張子で使用することができます。
そのため、なぜ
layoutSubviews
.
すべての Swift アプリは、Swift 専用のランタイムを可能にする純粋な Swift 専用のフレームワークを使用する場合を除き、Objective-C ランタイム内で実行されます。
Objective-Cのランタイムは、一般的に2つのクラスのメインメソッドを呼び出すことがわかりました。
load()
と
initialize()
は、アプリのプロセスでクラスを初期化する際に自動的に使用されます。
について
dynamic
モディファイア
から アップルデベロッパーライブラリ (アーカイブ.org)
を使用することができます。
dynamic
修飾子を使用すると、Objective-C ランタイムを通じてメンバーへのアクセスが動的にディスパッチされることを要求できます。
Swift API が Objective-C ランタイムによってインポートされるとき、プロパティ、メソッド、添え字、またはイニシャライザーの動的ディスパッチは保証されません。 Swift コンパイラは、Objective-C ランタイムをバイパスして、コードのパフォーマンスを最適化するために、メンバアクセスを仮想化またはインライン化することがあります。 ????
そこで
dynamic
を適用することができます。
layoutSubviews
->
UIView Class
はObjective-Cで表現され、そのメンバーへのアクセスは常にObjective-Cのランタイムを使用して使用されるからです。
そのため、コンパイラが許可している
override
と
dynamic
.
関連
-
[解決済み] swiftにおけるconvenience initとinitの違いは何ですか、より良い明示的な例
-
Swift タイプの表現は、より多くの文脈がないと曖昧である。
-
フォールスルーの使用方法概要
-
[解決済み] Error: this class is not key value coding-compliant for key tableView.' [重複] を修正する方法。
-
[解決済み] SwiftからObjective-Cのコードを呼び出すにはどうしたらいいですか?
-
[解決済み] Swiftで#pragmaマーク?
-
[解決済み] Swift Betaのパフォーマンス:配列のソート
-
[解決済み] Swiftでindexとelementでループを反復させる方法
-
[解決済み] Swiftの@selector()?
-
[解決済み] Swiftのプロトコルでオプションのメソッドを定義するには?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] テスト
-
[解決済み] UILabelにスペース/パディングを追加する
-
[解決済み] SwiftUIのFacebookログイン。FacebookのIDをビューに戻すには?
-
[解決済み] Fatal error.とは何ですか?Unexpectedly found nil while unwrapping an Optional value" とはどういう意味ですか?
-
[解決済み] SwiftでString.Indexはどのように動作するのか
-
[解決済み] テキストファイルからの文字列の読み込みと書き込み
-
[解決済み】preferredStatusBarStyleが呼び出されない。
-
[解決済み】Autolayout - UIButtonの固有サイズにタイトルインセットが含まれない
-
[解決済み】コンパイラーエラー。Objective-C のセレクタを持つメソッドは、同じ Objective-C セレクタを持つ以前の宣言と競合しています。
-
[解決済み】Swiftで列挙型の値の名前を取得する方法は?