有没有办法在 Swift 中使用 [self.view recursiveDescription]?我正在尝试使用此方法,但出现以下错误:
'UIView' does not have a member named 'recursiveDescription'
有什么建议么?
有没有办法在 Swift 中使用 [self.view recursiveDescription]?我正在尝试使用此方法,但出现以下错误:
'UIView' does not have a member named 'recursiveDescription'
有什么建议么?
如果要在 lldb 中显示视图层次结构,则不必添加任何类别或桥接头或类似内容。在调试 Objective-C 代码时,通常会在(lldb)
提示符处使用以下命令:
po [[UIWindow keyWindow] recursiveDescription]
但是,如果您在 Swift 帧中暂停,则 lldb 可能需要一个 Swift 表达式。但是,您可以明确地告诉expr
(po
缩写实际上是调用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 中,他们扩展了这个视图调试器,因此它现在也包含相关的视图控制器:
在 swift 2.0 中,您可以简单地运行:
po view.performSelector("recursiveDescription")
在(使用 iOS10 Beta3 测试)swift 3.0 中,这有点复杂:
po let s = view.perform("recursiveDescription"); print(s)
po view.value(forKey: "recursiveDescription")!
为了从 Swift 访问私有/未记录的 Objective-C API(如-recursiveDescription
on 方法UIView
),您可以执行以下操作:
UIView
)。在类别标头中声明私有方法:
// UIView+Debugging.h
@interface UIView (Debugging)
- (id)recursiveDescription;
@end
现在您可以设置断点并在 LLDB 中打印出递归描述:
po view.recursiveDescription() as NSString
首先在您的桥接头中@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
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。
使用该方法向桥接头添加 UIView 类别的声明。
基于@Rob Mayoff 的 回答:
extension UIView {
/**
Wrapper for useful debugging description of view hierarchy
*/
var recursiveDescription: NSString {
return value(forKey: "recursiveDescription") as! NSString
}
}