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 调试篇
知乎专栏:极光日报
- iOS 调试心得
- GooglePlus API的iOS调试心得
- 调试心得
- 调试心得
- 调试心得
- ASP.NET调试心得.......
- VC6 调试心得
- 调试的一点心得
- VS 调试心得
- OV7670调试心得
- 调试论坛系统心得
- 调试Business项目心得
- 调试Shoppingbook项目心得
- oa系统调试心得
- 调试exam工程心得
- 调试luntan工程心得
- gdb调试心得
- TCC TP调试心得
- Android模拟IBeacon周边
- 不可解问题[停机问题]
- Java 二叉树
- 感悟、资产和幸福感
- mysql5.7 根据二进制文件mysqlbinlog恢复数据库 Linux
- iOS 调试心得
- ecshop源码分析02
- android音量控制
- 配置face-identification
- 自编超声波测距模块(HC-SR04)STC程序开源
- 2017三大数字营销趋势!营销人的必修课!
- QT+OPENCV+Cmake安装文档
- SylixOS中TPSFS格式化流程简析
- 系统服务之下载管理(DownloadManager)