一、前言

  • 在上一篇博客中,已经详细地介绍如何使用 LLDB 表达式修改 UI 元素,具体请参考:Swift之深入解析如何将代码添加为自定义LLDB命令。
  • 在这篇博客中,将继续讨论相同的问题需求,并将重点讨论如何最大限度地利用 LLDB 表达式,如果工具太过复杂,那么它就无法工作并获得用户的采用,出于这个原因,本文将分享一些使 LLDB 表达式更容易使用的替代方法。

二、命令别名

  • 首先,必须输入(或复制)这个长度的命令(例如 po [[[UIApplication sharedApplication] keyWindow] recursiveDescription])可能会阻碍开发者使用这些 LLDB 命令。幸运的是,这个问题有解决方案,它被称为命令别名,惟一需要做的就是编辑位于 ~/.lldbinit 目录中的文件,Lldbinit(或者通过键入 touch ~/.lldbinit 创建它),并添加如下命令:
command alias views expression -l objc -O -- [[[UIApplication sharedApplication] keyWindow] recursiveDescription]command alias flush expression -l objc -- (void)[CATransaction flush]
command regex change_color 's/(.+) (.+)/e (void)[(id)%1 setBackgroundColor:[UIColor %2]]/'
  • 前两个命令在Swift之深入解析如何将代码添加为自定义LLDB命令已经介绍使用过,第一个是打印视图层次结构,获取按钮的内存地址,第二个是刷新 UI。
  • 最后一个命令演示了如何使用 regex 创建带参数的命令,在这个特定的情况下,需要一个内存地址和颜色的名称(blueColor),结果按钮的背景颜色将会改变。例如,运行 change_color 0x7f9f7e40cd70 blueColor 并刷新将导致将按钮的背景颜色更改为蓝色。
  • 使用别名将提高使用此工具的可能性,但在某些情况下需要更高级的别名。比如说,如何通过按钮标签的文本找到按钮的内存地址。在这种情况下,Python 可以提供可扩展性。

三、LLDB 与 Python

  • 现在开始编写 Python 命令的一个简单方法是使用 Xcode 控制台,输入命令脚本添加帮助并遵循说明:

  • 或者,可以创建一个脚本文件,它可以添加到回收和版本控制系统中,然后在 Xcode 控制台上运行命令 command script import <script_file_path>,或者更好的方法是将它添加到 ~/.lldbinit 文件中。
  • 要写一个 Python 函数用作新的 LLDB 命令,需要实现一个带有四个参数的函数:
def command_function(debugger, command, result, internal_dict):# Your code goes here
  • 根据 LLDB python 参考,这些变量的类型和描述如下:
    • debugger (类型:lldb.SBDebugger):当前调试器对象;
    • command (类型:python string):一个包含命令所有参数的 Python 字符串,如果需要分割参数,请尝试使用 shlex 模块的 shlex.split(命令)来正确地提取参数;
    • result (类型: lldb.SBCommandReturnObject):一个返回对象,它封装了命令的成功/失败信息,以及作为命令结果需要打印的输出文本,普通的 Python“print” 命令也可以工作,但默认情况下文本不会进入结果(它作为临时日志记录工具很有用);
    • internal_dict (类型:python dict object): 当前嵌入脚本会话的字典,其中包含所有变量和函数。
  • 如果使用命令脚本导入方法,可以像下面这样定义 __lldb_init_module 函数:
def __lldb_init_module(debugger, internal_dict):# Command Initialization code goes heredebugger.HandleCommand('command script add -f filter.filter_button_by_label filter_button_by_label')
  • 其中调试器和 internal_dict 如上所述,当加载模块时,这个函数将被调用,允许在当前调试器中添加任何想要的命令。debugger.HandleCommand 的参数描述如下:
    • command script add:使用 LLDB 命令添加脚本;
    • -f argument:指定命令将执行的 Python 函数的名称,它遵循的格式:{module name}.{function name};如同上面的例子中:
    • filter:是模块的名称(在 Python 中只是不带 .py 扩展名的文件名);
    • filter_button_by_label:命令功能,描述同 command_function(debugger, command, result, internal_dict)) 一致;
    • argument(例如 filter_button_by_label):是 Xcode 控制台中用来调用此函数的命令。
  • 如下所示,展示了一个如何从按钮标签的文本中获取按钮内存地址的示例:
import lldb
import commands
import optparse
import shlex
import redef create_options():usage = "usage: filter_button_by_label [options]"description='''This command is used to find a UIButton with a label matching the option provided as option'''parser = optparse.OptionParser(description=description, prog='filter_button_by_label', usage=usage)parser.add_option('-n', '--needle', type='string', dest='needle', help='Text to search on UIButton labels.')return parserdef filter_button_by_label(debugger, command, result, internal_dict):target = debugger.GetSelectedTarget()process = target.GetProcess()mainThread = process.GetThreadAtIndex(0)currentFrame = mainThread.GetSelectedFrame()# Parse arguments and optionscommand_args = shlex.split(command)parser = create_options()try:(options, args) = parser.parse_args(command_args)# if needle is not providedif not options.needle:parser.print_help()returnexcept:returnview_hierarchy_command = '(id)[[[UIApplication sharedApplication] keyWindow] recursiveDescription]'view_hierarchy = currentFrame.EvaluateExpression(view_hierarchy_command).GetObjectDescription()for match in re.finditer('.*<UIButton: (0x[0-9a-fA-F]*);.*', view_hierarchy, re.IGNORECASE):view = match.groups()[-1]created_command = '(NSString *)[ (id)' + view + ' currentTitle]'title = currentFrame.EvaluateExpression(created_command).GetObjectDescription()if title == options.needle:print >>result, viewelse:print >>result, "Not Found"def __lldb_init_module(debugger, internal_dict):debugger.HandleCommand('command script add -f ' + __name__ + '.filter_button_by_label filter_button_by_label')
  • 它可以像 filter_button_by_label -n “Press me” 这样调用,它会返回那个按钮的内存地址。因此改变按钮颜色的整个流程就变成:

  • 与第一个实现相比,代码更短,更容易记忆,因此更容易使用。

四、Chisel

  • 除此之外,Facebook 已经提供了一个名为 Chisel 的开源 LLDB 命令集,它提供了大量的命令,可能解决了任何 iOS 开发者可能面临的大多数问题。
  • 如下所示,个人最喜欢的两个命令:
    • findinstances:可以用来查找指定 ObjC 类的实例;
    • pcurl:它可以被用来打印作为 curl 命令的 NSURLRequest,稍后可以用于调试目的。

Swift之深入解析如何使用Xcode和LLDB v2修改UI元素相关推荐

  1. Swift之深入解析如何避免单元测试中的强制解析

    一.前言 强制解析(使用 !)是 Swift 语言中不可或缺的一个重要特点(特别是和 Objective-C 的接口混合使用时),它回避了一些其他问题,使得 Swift 语言变得更加优秀. 比如在我的 ...

  2. Swift 类似HandyJSON解析Struct

    Swift 类似HandyJSON解析Struct HandyJSON 从源码解析Struct 获取TargetStructMetadata 获取TargetStructDescriptor 实现Ta ...

  3. Swift之深入解析可选链的功能和使用

    一.什么是可选链? 可选链(Optional Chaining)是一种可以请求和调用属性.方法和子脚本的过程,用于请求或调用的目标可能为nil. 可选链返回两个值: 如果目标有值,调用就会成功,返回该 ...

  4. Swift之深入解析“对象”的底层原理

    一.Swift 编译简介 Swift 的编译环境配置和编译流程,请参考我之前的博客:Swift之源码编译的环境搭建和编译流程: 新建一个 Swift 工程,在 main.swift 中创建一个 YDW ...

  5. swift php json解析,Swift 4.0 | JSON数据的解析和编码

    文 / 菲拉兔 自己撸的图 要求: Platform: iOS8.0+ Language: Swift4.0 Editor: Xcode9 [问题补充2017-09-28] 最近我发现了一个问题:在S ...

  6. swift html 数据解析,Swift MWResolver解析HTML/XML

    上篇文章Swift 最简单的方式来解析HTML我通过截取字符串的方式,很艰难的实现了一个解析HTML的方式,但是过程相当难受,并且扩展性不强,适应性也很糟糕. libxml2 libxml2的官网在这 ...

  7. swift使用yymodel解析数组模型

    这里写目录标题 桥接文件 模型类 解析json的代码 上一篇我已经写了,用swift建立模型类,然后在oc文件中,使用yymodel来解析模型,这次,写一个纯swift使用yy_model来解析数组j ...

  8. Swift之深入解析类和结构体的本质

    一.类和结构体的异同 Swift中,类和结构体有许多相似之处,但也有不同.内存分配可以分为堆区(Heap)和栈区(Stack),由于栈区内存是连续的,内存的分配和销毁是通过入栈和出栈操作进行的,速度要 ...

  9. Swift之深入解析构造过程和析构过程

    一.Swift 构造过程 构造过程是为了使用某个类.结构体或枚举类型的实例而进行的准备过程,这个过程包含了为实例中的每个属性设置初始值和为其执行必要的准备和初始化任务. Swift 构造函数使用 in ...

最新文章

  1. istringstream ostringstream stringstream
  2. 兔子繁殖MATLAB,2011-2012数学建模题
  3. 亿级短视频社交美拍架构实践
  4. UGUI 事件穿透规则
  5. DFS——深度优先搜索基础
  6. 【渝粤教育】国家开放大学2018年春季 建筑结构基础 参考试题
  7. 【Flink】Flink使用withParameters(Configuration)传参
  8. iphone通知和android,手机App 通知数量太多,让你备感压力吗?教你如何消除令人心烦的信息通知(iPhone、Android)...
  9. [转载] 聚类算法总结
  10. 【COGS 1873】 [国家集训队2011]happiness(吴确) 最小割
  11. 04_zookeeper客户端使用及常用命令
  12. CAT1 4G+以太网开发板腾讯云手机微信小程序显示温度和下发控制
  13. ZigBee2006 CC2430 按键流程
  14. JS代码转换d.ts语法
  15. laravel seeder 填充数据
  16. javaweb-39:文件上传及拓展鸡汤
  17. Bursuite简单抓包改包发包__超详细步骤
  18. 第九章:项目资源管理-0316
  19. synergy软件的安装及配置(附下载地址)
  20. radio input 不可以更改的状态(disabled readonly)

热门文章

  1. 从DUMP函数说开去
  2. goldengate Linux平台Oracle RAC-Oracle
  3. vue脚手架中使用axios
  4. 深入浅出ShellExecute(总结)
  5. html中使浮动的字为行排列,CSS布局:float浮动
  6. java集合性能_Java集合性能分析-疯狂Java讲义
  7. 每日程序C语言20-利用递归求阶乘
  8. c语言如何控制上位机界面大小,电机上位机控制及界面设计参考.doc
  9. oracle查询第二个字为a,Oracle多表查询 - osc_yqnlq679的个人空间 - OSCHINA - 中文开源技术交流社区...
  10. 前端参数无法转为后端实体内部类_Java学到什么程度才能叫精通?