39

有没有办法在 Swift 中使用 [self.view recursiveDescription]?我正在尝试使用此方法,但出现以下错误:

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

有什么建议么?

4

8 回答 8

89

如果要在 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 框架中:

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

在 WWDC 2018 Advanced Debugging with Xcodeexpr中,他们建议通过定义别名来摆脱这种复杂的语法poc,通过创建一个文本文件,~/.lldbinit使用以下行:

command alias poc expression -l objc -O --

然后您可以执行以下操作:

poc [UIViewController _printHierarchy]

值得注意的是,Xcode 8 引入了视图调试器(点击查看调试按钮),提供了一种更具交互性的方式来分析视图层次结构,很大程度上消除了对recursiveDescription视图层次结构的 LLDB 的需求。(这在 WWDC 2016 视频Visual Debugging with Xcode不再可用)中进行了讨论。诚然,有时我们最终不得不退回到recursiveDescription上面显示的技术,但大多数时候视图调试器使这变得更加自然,直观的过程。

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

在此处输入图像描述

于 2015-02-20T15:23:34.787 回答
67

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

po view.performSelector("recursiveDescription")

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

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

于 2015-09-30T15:56:36.263 回答
31
po view.value(forKey: "recursiveDescription")!
于 2016-12-05T16:13:07.270 回答
11

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

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

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

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

po view.recursiveDescription() as NSString
于 2014-12-29T19:03:33.727 回答
10

首先在您的桥接头中@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

于 2015-01-21T08:51:14.340 回答
4
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`]

Back ticks 就像一个预处理步骤,首先在当前帧中评估 this 的内容并插入结果,然后我们可以评估其余部分。

我的答案取自 WWDC 2018 Session 412 Advanced debugging with Xcode and lldb。

于 2018-09-02T22:37:29.180 回答
2

使用该方法向桥接头添加 UIView 类别的声明。

于 2014-09-18T01:39:10.197 回答
1

基于@Rob Mayoff 的 回答

extension UIView {

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

}
于 2018-09-04T02:05:24.430 回答