Swift中的recursiveDescription方法?

Vik*_*ngh 35 uiview ios uiview-hierarchy swift ios8

有没有办法在Swift中使用[self.view recursiveDescription]?我试图使用此方法,但我收到以下错误:

'UIView' does not have a member named 'recursiveDescription'
Run Code Online (Sandbox Code Playgroud)

有什么建议?

Rob*_*Rob 81

如果要在lldb中显示视图层次结构,则不必添加任何类别或桥接标题或类似的内容.在调试Objective-C代码时,通常会在(lldb)提示符下使用以下命令:

po [[UIWindow keyWindow] recursiveDescription]
Run Code Online (Sandbox Code Playgroud)

但是,如果你在Swift框架中暂停,lldb可能会期望一个Swift表达式.但是,您可以明确地告诉expr(po缩写实际上是调用expression)表达式所使用的语言:

expr -l objc++ -O -- [[UIWindow keyWindow] recursiveDescription]
Run Code Online (Sandbox Code Playgroud)

使用以下方法查看视图控制器层次结构时,iOS 8中会出现相同的模式:

po [UIViewController _printHierarchy]
Run Code Online (Sandbox Code Playgroud)

或者,在Swift框架中:

expr -l objc++ -O -- [UIViewController _printHierarchy]
Run Code Online (Sandbox Code Playgroud)

使用Xcode的 WWDC 2018 高级调试中,他们建议通过创建文本文件expr来定义别名poc,~/.lldbinit使用以下行来摆脱这种复杂的语法:

command alias poc expression -l objc -O --
Run Code Online (Sandbox Code Playgroud)

然后你可以做以下事情:

poc [UIViewController _printHierarchy]
Run Code Online (Sandbox Code Playgroud)

值得注意的是Xcode 8引入了视图调试器(点击 查看调试按钮),提供一种更加交互式的方式来分析视图层次结构,从而在很大程度上消除了recursiveDescription对视图层次结构的LLDB的需求.有关更多信息,请参阅WWDC 2016视频使用Xcode进行可视化调试.不可否认,有时我们最终不得不回到recursiveDescription上面所示的技术,但大多数情况下,视图调试器使这个过程变得更加自然,直观.

在Xcode 9中,他们扩展了这个视图调试器,所以它现在也包含了相关的视图控制器:

在此输入图像描述

  • 对于Swift 2.0,Ron的答案更简单,但这对lldb知识很有用 (2认同)

Ron*_*Ron 66

在swift 2.0中,您可以简单地运行:

po view.performSelector("recursiveDescription")
Run Code Online (Sandbox Code Playgroud)

在(使用iOS10 Beta3测试)swift 3.0中,这有点复杂:

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

  • 这应该是公认的答案,因为它不需要额外的代码. (5认同)

rob*_*off 23

po view.value(forKey: "recursiveDescription")!
Run Code Online (Sandbox Code Playgroud)


小智 11

要从Swift 访问私有/未记录的Objective-C API(如-recursiveDescriptionon on方法UIView),您可以执行以下操作:

  1. 在私有方法定义的类(例如UIView)中创建新的Objective-C类别.
  2. 如果Xcode中询问关于配置桥接报头.(如果您的项目中已经有一个桥接标题,则会跳过此步骤).
  3. 可以删除该类别的实现文件(.m).
  4. 在类别标头中声明私有方法:

    // UIView+Debugging.h
    
    @interface UIView (Debugging)
    - (id)recursiveDescription;
    @end
    
    Run Code Online (Sandbox Code Playgroud)

现在,您可以设置断点并在LLDB中打印出递归描述:

po view.recursiveDescription() as NSString
Run Code Online (Sandbox Code Playgroud)

  • 这种技术效果很好但很快/ lldb搞砸了.我不知道为什么,但是从这种技术得到的输出(XCode 6.2 6C101)非常混乱,包括\n作为不同的字符,因此控制台中的实际换行符 - 这很棒 - 并且它在大约1800个字符处剪辑,使它变得毫无价值.啊. (2认同)

Cop*_*ash 7

首先添加类别@interface,而不@implementation在你的桥接报头.

@interface UIView (Debug)
- (id)recursiveDescription;
- (id)_autolayoutTrace;  // This one is even sweeter
@end
Run Code Online (Sandbox Code Playgroud)

然后在你的控制台

po self.recursiveDescription() as NSString
po self._autolayoutTrace() as NSString
Run Code Online (Sandbox Code Playgroud)

这里的关键as NSString不是as String