Tag: 调试

Xcode中的断点和检查变量

想象一下,您刚刚构建了一个很棒的iOS应用程序,用于存储您拥有的图书的详细信息。 该应用程序有两个主要场景-一个场景包含一个列出所有书籍的表格,另一个场景可以在其中添加或编辑书籍的详细信息。 您甚至可以使用设备的相机或通过检测书籍的条形码来添加封面图像。 现在,假设您将您的应用程序发送给了一位朋友,以获得他们的反馈,而他们的回应如下: “添加图像并保存后,下次编辑书并保存时,书的封面似乎消失了……很奇怪吗?” 好。 这很奇怪-看起来您需要进行一些调试! 在本文中,我们将探讨诊断和解决此问题的方法。 我们将特别关注断点以及检查Xcode中变量的不同技术。 下载代码 在执行任何操作之前,我们需要下载该应用程序的代码。 为此,您将从Xcode中克隆项目。 1.选择源代码->克隆。 2.在文本字段中输入存储库的URL:https://github.com/iOSAppDevelopmentwithSwiftinAction/Bookcase.git。 Xcode项目应下载。 将选择默认分支,但是我们要选择其他分支。 我们可以在Source Control导航器中选择一个分支,您可以在Xcode左侧的列中找到该分支,称为导航器区域。 3.从左侧选择第二个选项卡。 这将打开“源代码管理”导航器。 4.打开Bookcase存储库,您应该看到三个组-Branchs , Tags和Remotes 。 5.选择Remotes,然后在Origin中找到Chapter15.1b.UpdatesNeedFixing分支。 右键单击该分支,然后选择“ 签出”以签出正确的分支。 由于尚未下载此分支,因此它不会下载。 6.连接iPhone或iPad,然后单击左上角的播放按钮,检查是否可以在设备上运行应用程序。 7.选择跳过按钮绕过入门。 复制问题 您需要做的第一步检查是尝试重现该问题。 有关您的朋友描述的问题的直观表示,请参见图1。 让我们尝试复制该错误。 从列表中选择一本书。 选择相机按钮,添加封面图像,然后选择保存。 现在,您应该在主表场景中看到封面图像。 到目前为止一切都很好! 3.再次打开同一本书,然后选择保存。 书籍图像返回到默认封面图像。 奇怪是对的! 可能会发生什么? 您直接怀疑是由于某种原因,当BookViewController生成要保存的书时,没有使用现有的书封面。 通过检查BookViewController类中的bookToSave变量,在touchSave方法中确认这touchSave 。 与Xcode中的情况一样,检查变量内容的方式有很多。 现在,让我们看一下一些内容,从您可能已经见过的方法print方法开始。 用print检查变量 要检查bookToSave变量,让我们使用print方法将其内容打印到控制台。 1.在touchSave方法调用dismissMe之前,打印bookToSave变量: print(“Saving book: \(bookToSave)”) 2.再次运行该应用程序,再次向书中添加封面图像,选择保存,重新打开书并选择保存。 这次,book对象应该打印到控制台,例如: […]

构建自定义Xcode Instruments软件包

在AppSpector,我们经常使用集成的工具(当然是我们自己的代码,包括核心部分-移动SDK)来调试客户端应用程序。 我们一直使用适用于特定平台的各种工具来加快调试速度,并使开发过程更容易且容易出错。 因此,当我们发现WWDC 2018大会410“创建自定义工具”时,我们迫不及待地想要使用新的API进行构建。 如果您只有锤子,那么一切看起来都像钉子。 值得构建自定义Instruments软件包的问题不久就出现了。 AppSpector iOS SDK的核心部分是一个消息传递模块,简而言之,它负责iOS和我们的后端之间的双向流量交换。 SDK发送大量事件,描述主机应用程序的行为和各种操作,还接收来自后端的请求。 流量足够大,需要压缩,因此我们从一开始就实现了它,现在所有消息都在SDK和后端进行了压缩/解压缩。 在某个时候,我们决定将压缩算法从LZ4更改为基于字典的zstd,并可能对我们的数据类型提供更好的压缩。 众所周知,测量任何变化的能力对于安全有效地将它们引入至关重要,因此我们决定创建一个内置机制来跟踪压缩率和性能。 当然,定制乐器是最佳选择。 潜在的工具如何提供帮助 实际上,通过简单的日志记录就可以轻松实现几乎相同的目标,但是我们想要的以及适用于Instruments的是数据采样和可视化。 想象一下,一百个消息中的单个消息遇到压缩问题,其压缩率非常低,您需要执行某些操作(例如建立蓝牙连接)才能在真实设备上触发它。 在日志中搜索此消息可能会很痛苦。 即使您使用某种服务从设备收集和保存日志消息,并且消息具有预先计算的压缩率,也不是完全可以的。 但是就像在WWDC会话上的那个家伙一样看交互式图形,能够保存收集的数据并以后比较两次运行,建立自定义选择规则以识别和聚合具有某些属性的消息-看起来很棒。 从技术上讲,Instruments是最强大的调试平台之一DTrace的前端。 它是从Sun Solaris进入OSX的,详细描述它可以占用整本书(实际上是这样:https://www.amazon.com/DTrace-Dynamic-Tracing-Solaris-FreeBSD/dp/0132091518)。 DTrace使用以D语言编写的特殊跟踪程序(称为探针)进行操作。 在Apple推出Instruments软件包之前,您可以通过编写自己的D脚本作为数据提供程序并将其包装在Instrument模板中来构建自定义乐器。 我们将使用os_signpost API向我们的仪器提供数据。 项目设置 为了方便起见,我们将构建一个示例项目来说明一个简单的Instruments软件包。 除了在示例项目中用于模拟压缩和解压缩消息大小的随机生成的事件值之外,我们的压缩配置文件工具的工作方式相同。 我们建议克隆示例项目并在阅读时参考它。 Xcode提供了一个新的目标类型,称为“ Instruments Package”,位于“ MacOS”->“ Other”部分下。 目标模板没有任何作用,只是添加了一个扩展名为.instrpkg的文件,它实际上是一个描述我们的仪器布局和功能的XML文件。 构建软件包的大部分工作只是用原始XML编写。 让我们希望我们能够尽快得到一些特定于任务的编辑器,例如InterfaceBuilder或CoreData模型编辑器。 仪器架构 我们将构建的工具将使用os_signpost调用作为数据提供者。 该API允许定义事件的开始和结束,还可以传递一些格式化的字符串以及开始和结束调用。 就像使用“ scanf()”一样,通过根据字符串的格式解析该字符串来获取在Instruments端的事件数据。 我们将在Swift中使用os_signpost(),如果您使用Objective-C编写代码,则应使用os_signpost_interval_begin / os_signpost_interval_end调用。 要开始使用这些API,我们需要实例化“ log”实例,因为os_signpost使用os_logging子系统发送消息和唯一的路标标识符: 静态let log = OSLog(子系统:“ com.package”,类别:“行为”)static let […]

调试内存不足问题:使用Runtime Magic捕捉布局反馈循环

让我们想象一下这种情况:您拥有一个成功的应用程序,该应用程序具有大量的每日用户和100%的无崩溃率。 您很高兴,您的生活令人赞叹。 但是在某个时候,您开始看到App Store出现负面评论,说它经常崩溃。 检查Fabric并没有帮助-没有出现新的崩溃。 那会是什么呢? 答案是OOM(内存不足)终止。 当您在最终用户的设备上使用RAM时,操作系统可以决定为其他进程回收该内存并终止您的应用程序。 我们将此称为“内存不足”终端。 可能有多种原因: 保持周期; 比赛条件; 废弃的线; 僵局; 布局反馈循环。 Apple提供了许多解决此类问题的解决方案: 解决滞留周期和其他类型泄漏的分配和泄漏工具 Xcode 8中已引入的Memory Debugger,它替代了Allocations和Leaks工具的某些功能 线程清理程序可帮助您查找竞争条件,废弃线程或死锁 布局反馈循环 我们将研究布局反馈循环。 这不是很常见的问题,但是一旦遇到,它可能会给您带来很多麻烦。 当您的视图运行其布局代码时,会发生布局反馈循环,但是某种方式导致它们再次开始其布局传递。 这可能是由于一个视图更改其超级视图之一的大小而导致的,或者可能是因为布局不明确。 无论哪种方式,此问题都会在您的CPU耗尽和RAM使用率稳定上升的情况下显现出来,这都是因为您的视图一次又一次地运行其布局代码而从未返回。 – 来自HackingWithSwift的Paul Hudson 对我们来说幸运的是,在WWDC16中,Apple花了整整15分钟的时间(!)引入了“布局反馈循环调试器”,该功能可帮助您识别调试期间发生循环的时刻。 这只是一个象征性的断点,它的工作方式就变得很简单:它计算在单个运行循环迭代中每个视图上的layoutSubviews()方法被调用的次数。 一旦超过某个阈值(例如100),该应用程序将在此断点处停止并打印一个不错的日志,以帮助您找到根本原因。 这是一篇不错的文章,简要描述了如何使用此调试器。 如果您可以重现此问题,则此方法非常适用。 但是,如果您有数十个屏幕,数百个视图,但您的App Store评论只说:“此应用程序很烂,总是崩溃,永远不要使用它!”? 您希望可以将所有这些人员带到您的办公室并为他们设置布局反馈循环调试器。 尽管第一部分由于GDPR而不能完全实现,但是您可以尝试在生产代码中复制UIViewLayoutFeedbackLoopDebuggingThreshold 。 让我们回想一下该断点是如何工作的:它计算一次layoutSubviews()调用,并在单个runloop迭代中超过某个阈值时发送一个事件。 听起来很容易,对吧? 该代码对于您的视图非常有效。 但是现在您想在另一个视图上实现它。 您当然可以创建UIView的子类,在其中实现它,然后从中继承项目中的所有视图。 然后对UITableView , UIScrollView , UIStackView等执行相同的操作…… 您希望可以将此逻辑注入所需的任何类中,而无需编写大量重复的代码。 这正是运行时编程允许您执行的操作。 我们将做同样的事情-创建一个子类,重写layoutSubviews()方法并计算其调用。 唯一的区别是所有这些将在运行时完成,而不是在项目中创建重复的类。 让我们开始简单-我们将创建我们的自定义子类,并将原始视图的类更改为该新子类: […]

如何调试iOS Appex

在“调试,分析和测试您的应用程序扩展”说明了如何使用主机应用程序调试iOS应用程序扩展(“ appex”)时,有时不依赖特定应用程序会更加方便。 一个很好的例子是在Network Extension框架之上构建的appex,例如自定义隧道提供程序-当用户从“设置”应用⚙️打开VPN时,iOS启动这种类型的扩展。 术语 包含应用程序 -在捆绑包中附带应用程序扩展并允许对其进行调整的应用程序[appex]。 主机应用程序 -设备上安装的任何其他应用程序,都可以使用第三方应用程序。 Appex-应用程序扩展名(或简称为“扩展名”)与包含应用程序一起提供,但由主机应用程序启动。 生成并运行 首先,appex是二进制文件,因此必须对代码进行任何更改,并将生成的二进制文件复制到设备中。 因此,每次您对包含的应用和/或其appex进行更改时,请点击“构建并运行”以获取包含的应用方案 。 等到该应用程序安装并启动。 此时,您可以确定已安装更新的appex二进制文件。 知道您的流程名称 您将使用适合于appex类型的任何方法启动appex。 例如,可以从包含的应用程序或“设置”应用程序中的“ VPN设置”面板直接启动“自定义隧道提供程序”扩展。 另一方面,必须先将“自定义键盘”扩展名安装到系统中并授予一些权限,然后用户才能从几乎所有具有键入功能的应用程序中启动键盘。 在启动扩展之前,进入Xcode菜单Debug- > Attach to Process 。 等待列表加载完毕,然后在“ 可能的目标”下找到进程名称。 您很快将需要它。 停止 现在,停止包含应用程序,appex和主机应用程序(如果有)。 添加断点 将断点添加到应用程序扩展的主体类中很重要。 因为应用程序扩展类型之间的入口点(启动appex进程时首先被调用的方法)有所不同,所以请查阅文档以找出调试期间在哪里中断。 附加到流程 在Xcode中,转到“ 调试” ->“ 按PID或名称附加到进程…” ,并确保进程名称与您先前捕获的名称相对应。 点击附加 。 然后,等待Xcode等待连接-按Command + 7找出状态。 启动appex 执行您希望启动扩展程序的所有操作。 换句话说,以某种方式使用它。 只要Xcode检测到iOS已启动,Xcode就会方便地附加到您的appex流程中。 它还会在命中的第一个断点处中断执行。 NOTE️ 注意:在撰写本文时,最新的Xcode 9.4.1的lldb通常无法发现该进程并将其附加。 因此,需要从头开始。 […]

在IOS中进行调试

大家好,我所有的IOS开发人员! 我们所有人都使用调试来发现错误以纠正它们,或者知道在我们编写的代码的底层发生了什么。 当我学习Objective-C时,对于IOS开发,我的一个朋友说,如果您成为一个优秀而高效的调试器,您将成为一个出色的程序员。 当我开始第一份工作后,很快我意识到了调试的重要性。 有时,我们需要在公司中调试其他人的代码,以了解他们的代码的逻辑和内幕。 从Apple Documents: 调试工作流程分为五个部分: 发现。 找出问题。 定位。 确定在代码中出现问题的位置。 检查。 检查正在运行的代码的控制流和数据结构以查找问题的原因。 固定。 将您的见解应用于问题原因以设计解决方案,并编辑适合的代码。 确认。 编辑后,运行该应用程序并使用调试器进行检查,以确保修复成功。 ->看下面的图片,熟悉调试工具,在Xcode上可以找到它们。 断点:我们使用它们来暂停应用程序,同时运行检查变量或了解我们编写的代码如何执行。 在断点调试中,我们主要使用“调试/运行”,“跳过”,“进入”和“退出”按钮,它们位于“调试”栏上。 >移入按钮有助于移入当前正在执行的方法。 >跳出按钮可以帮助跳过当前方法并移至源代码管理中的下一行。 -> Step-Over将执行当前代码行,如果该行中有任何func / method,它也会执行该代码并移至代码的下一行。 ->使用断点运行时,我们可以在Xcode的源代码文件上的任意位置单击鼠标右键,然后,如果选择“ continue to here ”,执行流程将在您单击的地方停止。 这样,您可以避免许多断点并更快地分析代码。 2.在Debug Navigator中,它形成一个调用堆栈,该堆栈将执行过程中的每个方法添加到断点命中为止,然后我们可以从正在执行的当前方法上进行任何级别的检查,以检查上一个步骤中发生了什么。代码行/方法。 它仍然显示与先前方法中使用的变量相同的值,这有助于通过发现问题进行调试。 3.如果我们要检查任何UIComponent的错误,可以使用Debug-hierarchy按钮,该按钮以3D视觉形式向您显示所有IBdesigned子视图,以检查视图的参数,视图层次结构等。 在调试中,我们通常通过-> 发现错误2.找到错误3.检查代码4.修复错误并5.确认过程。 Xcode中有许多类型的调试断点。 要查看列表,请通过单击左侧面板中的调试导航器来选择调试导航区域。 然后按一下底部左侧的+图标,以查看可用的断点类型。 异常断点: ->>在我们的开发中很多时候,我们都会在红色突出显示的行中看到“ Thread1:signal SIGABURT… ”之类的错误。 这可能会导致我们的代码出现异常。 例如,使用已存在的索引路径在表视图中插入新行。 对于这类异常,我们可以使用异常断点,该断点在发生异常的行中暂停执行。 一件很棒的事情是,通过与Xcode用户一起保存,我们可以在所有项目中使用这些异常的断点。 这样,在我们所有的项目中,只要发生异常,断点就会暂停执行。 您可以在Xcode中启用或禁用该断点。 我们要做的就是将异常断点移动到Xcode中的用户帐户。 >我们可以通过在断点导航区域中右键单击断点,然后选择共享来共享断点。 […]

在Xcode 9中使用内存图调试器

我从未真正花费时间来正确学习如何使用乐器。 当然,我知道如何使用Time Profiler和查找泄漏,但是我感觉那里还有很多未开发的潜力。 当Xcode 9与Memory Graph Debugger一起启动时,我真的很兴奋。 也许我可以继续保持懒惰,不学习乐器。 到目前为止,它一直有效。 我可以使用Xcode中的内存规来确定何时可能发生泄漏,然后使用Memory Graph Debugger进行识别。 我最近在App Store上发布了一个名为Subs的应用程序。 它是用于轻松管理所有订阅的。 在开发可以使用Touch ID和Face ID启用的下一个版本时,我通过反复关闭和​​解锁应用程序来测试锁定屏幕。 我注意到每次解锁时内存使用量都在不断增长。 轻击视图调试器旁边的小图图标将加载“内存图调试器”。 滚动浏览左侧的堆内存时,我注意到某些不应该存在的内容。 PageViewController的实例应该只有一个,但其中有五个。 另外,应该只有一个ViewController,在这种情况下,只有五个SubscriptionViewController。 为什么要创建这些其他实例? 更确切地说,为什么不清除先前的那些? 单击其中一个PageViewControllers,将显示其内存图。 它基本上显示了引用此特定PageViewController的所有对象。 您可以看到一些预期的引用,但是有一个引人注目:为什么SubscriptionsViewController引用PageViewController,因为它应该反过来。 原来是罪魁祸首。 除了使用PageViewController引用所有SubscriptionViewControllers之外,还有一个反向引用将PageViewController保留在内存中,然后将所有SubscriptionViewControllers保留在内存中。 单击连接两者的箭头,可以看到参考类型,在这种情况下,参考类型很强。 由于它是一个强大的参考,因此仅将其保存在内存中就足够了。 那么为什么会有一个强有力的参考呢? 因为我把它放在那里(菜鸟把菜鸟当成菜鸟) 在某些情况下,应用程序需要通过SubscriptionViewController中发生的操作来切换页面。 而不是使用通知或委托(我可能应该这样做),我只是向包含页面视图控制器的SubscriptionViewController添加了一个属性。 幸运的是,解决方案非常简单:只需将引用设为弱: 但是如果没有在Xcode 9中使用方便的Memory Graph Debugger来找到它,我不确定如何找到它。 我敢肯定,Instruments可以告诉我这一点,但我不知道在哪里看。

使用新的OpenWhisk调试器

无服务器计算的迅速普及也就不足为奇了。 隐式可伸缩性,事件驱动/自动数据处理,简单性,可重用性,可组合性和降低的成本只是无服务器编程模型开始兴起的几个原因。 人们有时会反对使用无服务器编程模型的一个论据是,由于无法将本地调试器附加到无服务器操作上,因此无服务器操作可能更难开发,但实际上,既然有了wskdb ,这不再是问题。 wskdb:OpenWhisk调试器 如果您还没有看到它,那么现在您可以wskdb ,它是新的/ Beta版OpenWhisk调试器。 它允许您在丰富的调试环境中调试本地计算机上的OpenWhisk操作,就像调试本地代码一样。 实际上,您实际上是在调试本地代码。 使用调试器时,您将附加到操作。 然后,对该操作的调用将重新路由到您的开发机,您可以在其中调试并进行本地更改。 调试完成后,您可以推送更改,或者只是断开连接即可清理重新路由。 您甚至可以调试序列中的特定操作。 假设您有一个由操作A,B,C和D组成的序列。您可以将调试器附加到这些操作中的任何一个上。 因此,如果我想调试动作C,则将其附加到动作C。调用序列时,将在OpenWhisk环境中执行动作A和B,然后将在本地调试环境中调用动作C,然后将动作D在OpenWhisk环境中执行。 您可以使用OpenWhisk调试器来调试Node.js / JavaScript,Swift或Python操作,它使您能够达到断点,单步执行代码,检查内存值等等。 查看此概述: 可用的命令是: 指令说明 列表,l列出可用的操作 cli使用CLI调试器(如果可用) 调用,我调用一个动作 检查,获取,检查OpenWhisk操作的详细信息 火,f扳机 附加,附加到动作 分离,动作分离 diff显示给定操作的待处理差异 p,发布对给定操作的未决更改 退出,退出,e,q退出调试器 clean,c清除调试工件 创建动作 删除删除动作 帮助,h ,? 打印此帮助文本 要调试动作,您必须首先运行attach命令–这将设置“管道”以能够调试您的动作。 一旦连接了调试器,就可以使用in invoke命令(像OpenWhisk CLI一样传递参数)。 在下面的屏幕截图中,您可以看到我如何附加和调用我的斐波那契操作(该操作会在斐波那契序列中生成数字): 这将启动调试过程。 对于JavaScript / Node.js操作,这将基于您熟悉的Chrome / Blink / Webkit / Node Inspector调试器,如下图所示。 这样就可以检查内存中的变量,设置断点,逐行执行代码等。所有这些都是非常有用的开发和调试工具。 […]

使用LLDB调试Swift代码

作为工程师,我们将近70%的时间用于调试。 其余的20%会继续考虑架构方法+与队友进行交流,而实际上只有10%会继续编写代码。 调试就像是犯罪电影中的侦探一样,而您也是凶手。 —通过Twitter的Filipe Fortes 因此,使我们这70%的时间尽可能愉快是非常重要的。 LLDB进行了救援。 花式Xcode调试器用户界面显示所有可用信息,而无需键入单个LLDB命令。 但是,控制台仍然是我们工作流程的重要组成部分。 让我们分解一些最有用的LLDB技巧。 我个人每天使用它们进行调试。 LLDB是一个强大的工具,它内部包含许多有用的命令。 我不会全部描述。 我想向您介绍最有用的命令。 所以这是我们的计划: 探索变量值: expression , e , print , po , p 获取整体应用程序的状态+语言特定的命令: bugreport , frame , language 控制应用程序的执行流程: process , breakpoint , thread , watchpoint 荣誉奖: command , platform , gui 我还准备了有用的LLDB命令的图以及说明和示例。 如果需要,可以将其挂在Mac上方以记住这些命令🙂 命令: expression , e , print , po […]

构建自定义的Xcode Instruments包,XML反击

他们说:“写不止一个” 不久前,我开始使用自定义Instruments软件包。 去年Apple WWDC 410会议之后,我感到很兴奋,并认为构建某个东西会很棒。 在上一篇文章中,我描述了整体程序包体系结构,开发工作流程中的一些陷阱以及在AppSpector中我们如何构建自定义程序包来跟踪SDK中的流量压缩。 在410会议上,Apple工程师说:在另一张幻灯片上“制造多个仪器”。 所以我想-为什么不呢? Instruments的自定义软件包是实现高度特定的调试流程的理想工具。 每个人都知道一个bug可以忍受多久,因为您不知道发生了什么。 一旦找到“观点”来解决问题,您就快完成了。 解决方法始终是大约10%,而找到正确的视角就是剩下的时间。 在思考软件包的一些想法时,我遇到了CossackLabs [1]的一篇很棒的文章,内容涉及开放跟踪框架及其实现。 可视化应用程序内部连续过程的想法看起来很适合作为一种工具。 这样的过程的完美示例是在不同视图控制器的上下文中执行的任何操作,堆积在队列中的操作或客户端-后端消息交换。 如果我只知道实施将需要32个小时😉 封装架构 让我们从一个基本的方法开始:为了实现类似开放式跟踪的图形,我决定使用看起来最好的图形元素。 开放式跟踪框架处理范围的两个基本概念:正在发生事情的上下文; 范围-范围内的一些活动。 包实现中的作用域具有开始和停止事件,唯一名称以及结果:成功或失败。 与成熟的开放式跟踪框架所建议的相比,此方法大大简化了,但足以用于试验软件包中的图并很有用。 打包方案不是很复杂。 我将不深入介绍第一部分中描述的元素,而我只会讲一些关于图形的特定内容。 您可以在这里浏览: https://github.com/appspector/Tracer/blob/master/TracerPackage/TracerPackage.instrpkg 我在周末构建原始实现时遇到的第一个问题是,仅在发送stop事件后,图形通道才出现在UI中。 我想从开始事件开始显示它,并用不同的颜色突出显示当前正在运行的跨度。 多亏了参加410次会议的Apple工程师Kacper,我才发现仪器具有一种特殊的结构,称为“开放间隔模板”。 它是一种结构,用于定义开始和结束事件之间包可使用的字段。 图本身用“图”节点描述,其中包含诸如标题和对表的引用之类的字段,以从中获取数据; “ plot-template”结构描述了显示的图形通道。 下面的示例意味着我们将为每个唯一的作用域都有一个单独的通道,它将从作用域名称变量中获取其名称。 “ plot-template”下的最后两个标签描述了车道内的线,颜色将来自“ status-color”,标签来自“ span-name”。 另一个有趣的事情是,“ open-interval-template”只能操作出现在开始模式中的变量。 这完全有道理,因为当您显示开始但未结束的事件时,您的代码无法使用结束模式中的数据。 同样,在表的最后两列中,我们计算行和状态标签的颜色,为此,我们需要知道事件的状态-它是正在运行还是已经完成? 我看到解决此问题的唯一方法是仅检查结束模式中存在的变量。 这就是为什么您在开始和结束模式中看到“ span-name-started”和“ span-name-stopped”变量的原因。 第一个用于在行上绘制跨度名称,第二个用于区分正在运行的跨度和结束跨度。 这是关于自定义程序包的丑陋事情之一,感觉它应该有另一个更优雅的解决方案。 第一次尝试 我很高兴在真实代码上尝试使用示踪剂,因此我开始寻找一个很好的例子。 第一次尝试是AppSpector SDK和消息处理模块。 每条消息的传入和传出都需要经过两个步骤:序列化,打包,压缩和最终发送。 有时,由于诸如网络故障等各种原因,消息可能会在队列中等待。这看起来很合适,因此我插入了示踪剂调用并开始记录期望的图像,就像在开放的示踪手册中有很多重叠的通道一样。 […]

Bitrise上漂亮而智能的Xcode存档步骤日志

标准日志中包含最后10行经过修饰的Xcode日志,以使在 Bitrise 上的调试更加流畅 。 在我们的Xcode构建步骤中,我们使用xcpretty修饰原始Xcode构建日志的输出。 原始日志存储在一个临时目录中,因此,如果要详细检查故障,则可以找到原始输出。 尽管xcpretty产生了更多易于消化的输出,但是很常见的是,您无法从经过修饰的输出中分辨出确切的错误,但是它包含在原始Xcode构建日志的末尾。 因此,我们更新了Xcode步骤,以在步骤失败且输出工具为xcpretty时,将构建日志的最后10行打印到标准输出中。 这与完整日志无关,该文件仍然可用。 新的日志看起来很漂亮。 😉 ▸ Check Dependencies ❌ Code signing is required for product type ‘Application’ in SDK ‘iOS 10.3’ ❌ Code signing is required for product type ‘Application’ in SDK ‘iOS 10.3’ [33;1mIf you can’t find the reason of the error in the log, please check the […]