Skip to content

Instantly share code, notes, and snippets.

@kastiglione
Last active June 2, 2022 02:02
Show Gist options
  • Save kastiglione/d7fc5b3b3ebab1248333b858591e06b0 to your computer and use it in GitHub Desktop.
Save kastiglione/d7fc5b3b3ebab1248333b858591e06b0 to your computer and use it in GitHub Desktop.
Swift helpers, and the lldb setup to use them. Presented @ SLUG https://speakerdeck.com/kastiglione/advanced-debugging-and-swift
extension UIView {
/// Example: call someView.nudge(0, 30)
func nudge(_ dx: CGFloat, _ dy: CGFloat) {
self.frame = self.frame.offsetBy(dx: dx, dy: dy)
CATransaction.flush()
}
}
extension UIView {
/// Example: po UIView.root
static var root: UIView {
return UIApplication.shared.keyWindow!.rootViewController!.view
}
}
extension UIViewController {
/// Example: po UIViewController.current
static var current: UIViewController {
var controller = UIApplication.shared.keyWindow!.rootViewController!
if let child = (controller as? UINavigationController)?.topViewController {
controller = child
}
if let container = (controller as? UITabBarController)?.selectedViewController {
controller = child
}
return controller
}
}
extension UIView {
/// Example: po UIView.current
static var current: UIView {
return UIViewController.current.view
}
}
extension UIView {
/// Utility used by others helpers.
func tree() -> UnfoldSequence<UIView, [UIView]> {
return sequence(state: [self]) { state in
guard let view = state.popLast() else { return nil }
state.append(contentsOf: view.subviews.reversed())
return view
}
}
}
extension UIView {
func grep(_ pattern: String) -> [UILabel] {
return self.tree()
.compactMap { $0 as? UILabel }
.filter { $0.text?.range(of: pattern) != nil }
}
}
extension UIView {
/// Example: po UIButton.first(in: UIView.current)
static func first(in root: UIView) -> Self? {
return root.first { _ in true }
}
/// Example: po UIView.current.first { (b: UIButton) in b.currentTitle == "Tap Me" }
func first<T: UIView>(where match: (T) -> Bool) -> T? {
return self.tree()
.lazy
.compactMap { $0 as? T }
.filter(match)
.first
}
}
extension UIView {
func fillText(_ text: String) {
if let textField = UITextField.first(in: self) {
textField.text = text
CATransaction.flush()
}
}
}
extension UIView {
// Example: po someView.screenshot("/some/path.png")
// Example: shell open /some/path.png
func screenshot(_ path: String) {
let renderer = UIGraphicsImageRenderer(bounds: self.bounds)
let png = renderer.pngData { _ in
self.drawHierarchy(in: self.bounds, afterScreenUpdates: false)
}
do {
try png.write(to: URL(fileURLWithPath: path))
} catch let e {
print("Failed to write \(path): \(e)")
}
}
}
// Example: someButton.sendActions(for: $touchUpInside)
let $touchUpInside = UIControl.Event(rawValue: 64)
# create the `alias` used below
command alias alias command alias
# to load python lldb commands
alias import command script import
# to run lldb "shell" scripts
alias source command source
# to run a shell command, like `open`
alias shell platform shell
# tell lldb to assume swift, not objc
settings set target.language swift
alias clear-lang settings clear target.language
# `load_swift` command is used to load helpers written in swift
import ~/load_swift.py
# load_swift path/to/helpers.swift
alias action breakpoint command add
alias autocontinue breakpoint modify --auto-continue true
import lldb
import os
kNoResult = 0x1001
@lldb.command("load_swift")
def load_swift(debugger, path, ctx, result, _):
with open(os.path.expanduser(path)) as f:
contents = f.read()
options = lldb.SBExpressionOptions()
options.SetLanguage(lldb.eLanguageTypeSwift)
error = ctx.frame.EvaluateExpression(contents, options).error
if error.fail and error.value != kNoResult:
result.SetError(error)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment