web-dev-qa-db-ja.com

SwiftのrecursiveDescriptionメソッド?

Swiftで[self.view recursiveDescription]を使用する方法はありますか?この方法を使用しようとしていますが、次のエラーが発生します。

'UIView' does not have a member named 'recursiveDescription'

助言がありますか?

37
Vik Singh

Swift)からプライベート/ドキュメント化されていないObjective-C API(UIView-recursiveDescriptionメソッドなど)にアクセスするには、次のようにします。

  1. プライベートメソッドが定義されているクラスに新しいObjective-Cカテゴリを作成します(例:UIView)。
  2. ヒットはいブリッジヘッダーの構成についてXcodeから尋ねられた場合。 (プロジェクトにすでにブリッジヘッダーがある場合、この手順はスキップされます)。
  3. カテゴリの実装ファイル(.m)は削除できます。
  4. カテゴリヘッダーでプライベートメソッドを宣言します。

    // UIView+Debugging.h
    
    @interface UIView (Debugging)
    - (id)recursiveDescription;
    @end
    

これで、ブレークポイントを設定し、LLDBに再帰的な説明を出力できます。

po view.recursiveDescription() as NSString
11
bernhard

Lldbでビュー階層を表示する場合は、カテゴリやブリッジヘッダーなどを追加する必要はありません。 Objective-Cコードをデバッグする場合、通常、(lldb)プロンプトで次のコマンドを使用します。

po [[UIWindow keyWindow] recursiveDescription]

ただし、Swiftフレームで一時停止している場合、lldbはSwift式を予期することがあります。ただし、exprpo省略形実際にはexpression)を呼び出しています)

expr -l objc++ -O -- [[UIWindow keyWindow] recursiveDescription]

IOS 8でビューコントローラーの階層を表示すると、次のように同じパターンが発生します。

po [UIViewController _printHierarchy]

または、Swift frame:

expr -l objc++ -O -- [UIViewController _printHierarchy]

WWDC 2018 Xcodeを使用した高度なデバッグ では、次の行を含むテキストファイル~/.lldbinitを作成して、エイリアスexprを定義することにより、この複雑なpoc構文から離れることを提案しています。

command alias poc expression -l objc -O --

その後、次のようなことができます:

poc [UIViewController _printHierarchy]

Xcode 8がビューデバッガーを導入したことは注目に値します(クリック view debug button )は、ビュー階層を分析するよりインタラクティブな方法を提供し、ビュー階層のLLDB recursiveDescriptionの必要性をほとんど排除します。詳細については、WWDC 2016ビデオ Xcodeによるビジュアルデバッグ を参照してください。確かに、上に示したrecursiveDescription手法にフォールバックしなければならないこともありますが、ほとんどの場合、ビューデバッガーはこれをはるかに自然で直感的なプロセスにします。

Xcode 9では、このビューデバッガーが拡張され、関連するビューコントローラーも含まれるようになりました。

enter image description here

84
Rob

Swift 2.0では、次のように実行できます:

_po view.performSelector("recursiveDescription")
_

(iOS10 Beta3でテスト済み)Swift 3.0では、これは少し複雑です:

po let s = view.perform("recursiveDescription"); print(s)

66
Ron
po view.value(forKey: "recursiveDescription")!
25
rob mayoff

最初にカテゴリを追加します@interfaceなし@implementationブリッジヘッダー内。

@interface UIView (Debug)
- (id)recursiveDescription;
- (id)_autolayoutTrace;  // This one is even sweeter
@end

次に、コンソールで

po self.recursiveDescription() as NSString
po self._autolayoutTrace() as NSString

ここでの鍵はas NSStringないas String

8
CopperCash
expression -l objc -O -- [`self.view` recursiveDescription]

UIKitはObjective-Cフレームワークにあるため、Objective-C形式で入力する必要があります。

再帰的記述は、デバッグ目的でのみ存在します。これはパブリックAPIの一部ではないため、Swiftでは使用できません

また、Swiftは厳密な言語であり、厳密に定義されていない関数を呼び出すことはできません。

Objective-C、これは動的言語なので、このような関数を呼び出すことができます。

したがって、Objective-C構文でこの式を評価するようにデバッガーに指示する必要があります

そしてそれを行う方法は、オプション-l objcで式を使用することです

-O、poと同じようにデバッグの説明も必要であることをデバッガーに通知します-これ以上オプションがないことを示します。

Put [self.view]ビューをバックティックに配置する必要があります。

[`self.view`]

バックティックは、最初に現在のフレームでこれの内容を評価し、結果を挿入してから、残りを評価することができる前処理ステップのようなものです。

私の答えは、Xcodeとlldbを使用したWWDC 2018 Session 412の高度なデバッグからのものです。

3
ManuelMB

そのメソッドを使用して、UIViewのカテゴリの宣言をブリッジヘッダーに追加します。

1
newacct

@ Rob Mayoff'sanswer に基づいて構築:

extension UIView {

   /**
    Wrapper for useful debugging description of view hierarchy
   */
   var recursiveDescription: NSString {
       return value(forKey: "recursiveDescription") as! NSString
   }

}
1