iOS 调试心得

来源:互联网 发布:apache storm 介绍 编辑:程序博客网 时间:2024/06/16 21:16

修复 bug 占用我们日常开发的大部分时间,熟练的使用调试工具可以给我们节约大部分的时间。

LLDB 的常用命令

expression

expresion 是一个非常常用的命令,我们可以通过这个命令来执行一些表达式,这样我们就不需要重写运行工程了,例如:

  (lldb) expression -- self.view.backgroundColor = [UIColor greenColor]  (lldb) expression -- (void)[CATransaction flush] // 用于刷新页面,

我们也可以使用 expression 来输出我们关注的信息

(lldb) expression -O -- self.view //这时候 就会输出对象 UIView,注意 -O 代表输出的是一个对象 ,这里有另外一种简写方式 po.<UIView: 0x7d2974a0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7d294813>>

有时候我们自定义的类并没有重写 description 方法,如果我们直接输出这个对象的话可能只会显示这个类名和地址,例如

(lldb) expression -O -- self<JChatAboutMeViewController: 0x7d2974a0>

这地址并不是我们想要的,我们想要的是这个对象内部信息,这里我推荐一个插件 chisel ,我们可以使用chisel 提供的命令来打印这个对象, 例如

(lldb) pinternals 0x7d2974a0(JChatAboutMeViewController) $4 = {  UIViewController = {    UIResponder = {      NSObject = {        isa = JChatAboutMeViewController      }      _hasOverrideClient = '\0'      _hasOverrideHost = '\0'      _hasInputAssistantItem = '\0'    }    _overrideTransitioningDelegate = nil    _view = nil    _tabBarItem = nil    _navigationItem = 0x7d4abf40    _toolbarItems = nil    _title = nil    _nibName = nil    _nibBundle = nil    _parentViewController = 0x7cb84c00    _childModalViewController = nil    _parentModalViewController = nil    _previousRootViewController = nil    _modalTransitionView = nil    _modalPreservedFirstResponder = nil    _dimmingView = nil    _dropShadowView = nil    _currentAction = nil    _storyboard = nil    _externalObjectsTableForViewLoading = nil    _topLevelObjectsToKeepAliveFromStoryboard = nil    _savedHeaderSuperview = nil    _savedFooterSuperview = nil    _editButtonItem = nil    _searchDisplayController = nil    _strongSearchDisplayController = nil    _modalTransitionStyle = 0    _modalPresentationStyle = 0    _lastKnownInterfaceOrientation = 0    _popoverController = nil    _containerViewInSheet = nil    _recordedContentScrollView = nil    _afterAppearance = nil    _explicitAppearanceTransitionLevel = 0    _interfaceBuilderKeyCommands = nil    _addedKeyCommands = nil    _overrideTraitCollections = nil    _previewSourceViews = nil    _retainCount = 0    _ignoreAppSupportedOrientations = '\0'    _viewHostsLayoutEngine = '\0'    _storyboardIdentifier = nil    _transitioningDelegate = nil    _frozenTraitCollection = nil    overrideUseCustomPresentation = '\0'    _modalPresentationCapturesStatusBarAppearance = '\0'    _disablesAutomaticKeyboardDismissal = '\0'    _ignoresParentMargins = '\0'    _childViewControllers = nil    _customNavigationInteractiveTransitionDuration = 0    _customNavigationInteractiveTransitionPercentComplete = 0    _customTransitioningView = nil    _lastNotifiedTraitCollection = nil    _presentationController = nil    _preferredFocusedItem = nil    _navigationControllerContentOffsetAdjustment = 0    _contentMargin = 16    _topLayoutGuide = nil    _bottomLayoutGuide = nil    _topBarInsetGuideConstraint = nil    _bottomBarInsetGuideConstraint = nil    _storyboardSegueTemplates = nil    _segueResponsibleForModalPresentation = nil    _sourceViewControllerIfPresentedViaPopoverSegue = nil    _modalSourceViewController = nil    _presentedStatusBarViewController = nil    _edgesForExtendedLayout = 15    __childControllerToIgnoreWhileLookingForTransitionCoordinator = nil    _presentingFocusedItem = nil    _storyboardPreviewSegueTemplates = nil    _storyboardCommitSegueTemplates = nil    _storyboardPreviewingRegistrants = nil    __embeddedView = 0xffffffff    __embeddingView = 0x78b909c0    __embeddedDelegate = 0x00007faa    _originalPresentationController = 0x78af3630    _temporaryPresentationController = 0x00007faa  }}

这样我们就能看到这个对象的内部信息了。
chisel 还提供一些便捷的功能,比如打印 pviews 递归打印层级,不过我更喜欢使用 xcode 自带的debug view hierarchy,这样更加直观。

我们可以使用 pvc 递归输出试图控制器的层级关系,例如

(lldb) pvc<JChatSwift.JChatMainTabViewController 0x7d49d560>, state: appeared, view: <UILayoutContainerView 0x7d479860>   | <UINavigationController 0x7c3afc00>, state: appeared, view: <UILayoutContainerView 0x7be8e9a0>   |    | <JChatConversationListViewController 0x7d49d2b0>, state: disappeared, view: <UIView 0x7d375320> not in the window   |    | <JChatChattingViewController 0x7bfbdde0>, state: appeared, view: <UIView 0x7d373b30>   | <UINavigationController 0x7eb7a000>, state: disappeared, view: <UILayoutContainerView 0x7d4a2c20> not in the window   |    | <JChatContactsViewController 0x7bea3d70>, state: disappeared, view: <UILayoutContainerView 0x7d4a1d40> not in the window   | <UINavigationController 0x7cb84c00>, state: disappeared, view: <UILayoutContainerView 0x7bf87590> not in the window   |    | <JChatAboutMeViewController 0x7d2974a0>, state: disappeared, view:  (view not loaded)

通过 pvc 和 pinternals 这样我们就可以在任何地方了解我们所有界面状态了。
在 xcode8 以后,我们也可以通过debug memory graph 来查看程序运行的内存状态。

thread

我们可以使用 thread backtrace 来输出线程的堆栈信息,例如

(lldb) thread backtrace  // 这个命令可以简写为bt* thread #1: tid = 0x14169a, 0x001273e5 JChatSwift`JChatChattingViewController.viewDidLayoutSubviews(self=0x7b6bc560) -> () + 21 at JChatChattingViewController.swift:48, queue = 'com.apple.main-thread', stop reason = breakpoint 7.1  * frame #0: 0x001273e5 JChatSwift`JChatChattingViewController.viewDidLayoutSubviews(self=0x7b6bc560) -> () + 21 at JChatChattingViewController.swift:48    frame #1: 0x00127502 JChatSwift`@objc JChatChattingViewController.viewDidLayoutSubviews() -> () + 34 at JChatChattingViewController.swift:0    frame #2: 0x039dc811 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1598    frame #3: 0x0305c1b9 libobjc.A.dylib`-[NSObject performSelector:withObject:] + 59    frame #4: 0x03791769 QuartzCore`-[CALayer layoutSublayers] + 141    frame #5: 0x03784a47 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 401    frame #6: 0x0378489d QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 21    frame #7: 0x0370e49f QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 339    frame #8: 0x0373d290 QuartzCore`CA::Transaction::commit() + 498    frame #9: 0x0373eda0 QuartzCore`CA::Transaction::flush_transaction() + 38    frame #10: 0x0393685c UIKit`_afterCACommitHandler + 375    frame #11: 0x022f676e CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30    frame #12: 0x022f66c7 CoreFoundation`__CFRunLoopDoObservers + 391    frame #13: 0x022da3a6 CoreFoundation`__CFRunLoopRun + 1414    frame #14: 0x022d9bab CoreFoundation`CFRunLoopRunSpecific + 395    frame #15: 0x022d9a0b CoreFoundation`CFRunLoopRunInMode + 123    frame #16: 0x06a1ab4c GraphicsServices`GSEventRunModal + 177    frame #17: 0x06a1a9c7 GraphicsServices`GSEventRun + 80    frame #18: 0x039077fb UIKit`UIApplicationMain + 148    frame #19: 0x001a7ce1 JChatSwift`main + 145 at AppDelegate.swift:15    frame #20: 0x06037799 libdyld.dylib`start + 1

我们可以看到程序停在JChatChattingViewController.swift:48 这一行

watchpoint

监视某个变量的改变,有时候我们想知道一个对象在什么时候被修改了,我们可以使用 watchpoint set var,当var 改变的时候程序就就会停在改变的地方, 如果用 chisel
的话,我们可以使用 wivar 命令来监听值的变化,例如

(lldb) wivar self name

作者:HuminiOS - 极光

原文:iOS 调试篇

知乎专栏:极光日报

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手机店把手机修坏了怎么办 在手机店买到山寨机手机怎么办 有人在qq群上骂我怎么办 qq群一直有人骚扰怎么办 苹果手机QQ图标不在桌面上怎么办 苹果手机长按不能删除怎么办 qq发的图片过期怎么办 九黎八卦在仓库怎么办 飞猪f2领了万豪银卡没住怎么办 机械键盘摁键冲突怎么办 玩游戏键盘没反应怎么办 玩枪战游戏头晕恶心怎么办 手机看视频不能横屏怎么办 苹果手机安全码忘记了怎么办 信用卡安全码忘记了怎么办 联想电脑管家阻止我安装软件怎么办 word恢复后打开乱码怎么办 苹果手机局域网也登陆不了怎么办 剑三账号冻结7天怎么办 荒野行动无缘无故被限制时间怎么办 电脑打游戏闪屏怎么办 微信下载出现数据包出错怎么办 安卓平板闪退怎么办 剑侠世界2出了1怎么办 苹果手机有木马病毒删除不了怎么办 苹果手机病毒了怎么办【解决方法】 苹果手机点击病毒链接怎么办 苹果手机有病毒啦怎么办 苹果7p反复重启怎么办 苹果手机屏幕触屏不灵怎么办 苹果手机屏翘起来了怎么办 苹果x手机触屏失灵怎么办 苹果7手机变成黑白屏怎么办 苹果手机屏不动了怎么办 苹果6老是卡屏怎么办 苹果x卡屏死机怎么办 苹果6死机卡屏怎么办 苹果手机主屏死机怎么办 苹果7手机卡屏死机怎么办 苹果6s卡死了怎么办 6s手机显示丢失锁定怎么办