Lời mở đầu
Giao diện người dùng(User Interface) của một ứng dụng hiện đại là một cấu trúc phức tạp. Nó liên quan đến các thành phần UI, bố cục và bản thiết kế dẫn đến quá trình gỡ lỗi(debugging) trở nên khá phức tạp. Việc biết các công cụ có sẵn giúp bạn giảm hàng giờ ngồi gỡ lỗi và làm cho việc tìm ra vấn đề trở nên đơn giản hơn.
Trong bài viết này mình sẽ giới thiệu về các công cụ gỡ lỗi giao diện do Apple cung cấp.
- iOS/Auto Layout – Phần 1: Auto layout là gì?
- iOS/Auto Layout – Phần 2: Sử dụng “XCode/Interface Builder” sao cho hiệu quả?
- iOS/Auto Layout – Phần 3: Anatomy of a Constraint, cách để tạo constraints bằng code
- iOS/Auto Layout – Phần 4: Làm sao để viết constraint dễ dàng hơn? Giới thiệu Snapkit
- iOS/Auto Layout – Phần 5: Stack View
- iOS/Auto Layout – Phần 6: Những trường hợp đặc biệt trong Auto Layout
1. View Hierarchy Debugger
View hierarchy debugger cung cấp khả năng kiểm tra và hiểu hệ thống phân cấp UI. Các thông tin bao gồm Phân cấp ứng dụng(app’s hierarchy), các view, các ràng buộc và view controller được hiển thị dưới dạng danh sách phân cấp. Object inspector và size inspector và thậm chí là mô hình 3D có thể tương tác được. Xịn sò vl 😀
Nó được đặt ở thanh debug. Để mở tính năng này bạn bấm vào biểu tượng được khoanh đỏ hình dưới đây. Khi ở chế độ này XCode sẽ dừng ứng dụng của bạn ở trạng thái hiện tại.
Tính năng này có thể sử dụng được cho iOS, tvOS, macOS, máy ảo(simulator) và thiết bị thật.
2. lldb
Nếu bạn thích console hơn là các công cụ trực quan thì UIKit cũng cung cấp các APIs logging rất ổn. Có một vấn đề nhỏ đó là những APIs private. Nhưng chúng ta cũng không dùng debug cho các bản release.
-[UIView recursiveDescription]
Nó sẽ hiển thị dưới dạng như sau:
<UIView: 0x7f9b29c08770; frame = (100 100; 50 50); layer = <CALayer: 0x600001b516e0>>
Nó sẽ hiển thị các thông tin bố cục, bản vẽ, CALayer và các trường cụ thể bổ sung.
-[UIViewController _printHierarchy]
Tương tự UIViewController cũng hiển thị các thông tin như dưới đây:
(lldb) po [viewController _printHierarchy]
<UISplitViewController 0x7fb23a605920>, state: disappeared, view: <UILayoutContainerView 0x7fb23d80dc60> not in the window
| <UINavigationController 0x7fb23b817000>, state: disappeared, view: <UILayoutContainerView 0x7fb23d80e280> not in the window
| | <MasterDetailTemplate.MasterViewController 0x7fb23a606140>, state: disappeared, view: <UITableView 0x7fb23b05ac00> not in the window
+ <UINavigationController 0x7fb23b01d600>, state: appeared, view: <UILayoutContainerView 0x7fb23a503150>, presented with: <_UIFullscreenPresentationController 0x7fb23d808f20>
| | <MasterDetailTemplate.ModalViewController 0x7fb23a409660>, state: appeared, view: <UIView 0x7fb23a51dfc0>
- | là biểu tượng cho biết các child view controllers
- + đại diện cho Modal presentation
_printHierarchy là phương thức đặc biệt hữu ích khi được gọi triên rootViewCOntroller của UIWindow:
po [[[UIWindow keyWindow] rootViewController] _printHierarchy]
Các phương thức ở trên đều dành cho Objective-C. Nếu bạn đang sử dụng swift thì cần tạo một số extension như sau:
#if DEBUG
extension UIWindow {
class var key: UIWindow {
let selector: Selector = NSSelectorFromString("keyWindow")
let result = UIWindow.perform(selector)
return result?.takeUnretainedValue() as! UIWindow
}
}
extension UIView {
var recursiveDescription: NSString {
let selector: Selector = NSSelectorFromString("recursiveDescription")
let result = perform(selector)
return result?.takeUnretainedValue() as! NSString
}
}
extension UIViewController {
var printHierarchy: NSString {
let selector: Selector = NSSelectorFromString("_printHierarchy")
let result = perform(selector)
return result?.takeUnretainedValue() as! NSString
}
}
#endif
Khi tạo xong các extension này chúng ta có thể sử dụng nó ở console bằng cách:
po view.recursiveDescription
po UIWindow.key.rootViewController!.printHierarchy
3. Instruments – Core Animation
Kiểm tra cấu trúc UI để tối ưu hóa hiệu suất. Điều đầu tiên chúng ta cần làm là đo khung hình mỗi giây. Con người có cảm nhận ứng dụng chạy mượt khi nó có thể hoạt động ở ~ 60FPS (Frames per second). Và đó chính là mục đích của chúng ta.
Lưu ý: Nó không hoạt động trên Simulator
Để mở chúng ứng dụng này chúng ta sử dụng tính năng search(command + space) đánh từ khóa Instruments:
Mở ứng dụng Instruments lên và chọn core animation
Core Animation đo hiệu năng đồ họa của ứng dụng. Trong ví dụ này, mình chỉ tập trung vào rendering performance. Ứng dụng của mình hiện tại là một UITableView với các custom cell. Bây giờ nó chỉ hiển thị section và row.
Khi cuộn mình nhận thấy nó hơi giật. Cấu hình ứng dụng với Instruments cho thấy hiệu suất cách xa mức 60 FPS. Khi cuộn (từ giây thứ 4->23) hiệu suất giảm xuống còn ~44 FPS giảm 16 so với mục tiêu đặt ra.
Tôi nghi ngờ vấn đề ở đây liên quan đến cell rendering. Với tính năng Color Blended Layers debug được bật, ta có thể hiểu rõ hơn về những gì đang xảy ra.
Color blended layer chỉ ra các view layers đang được vẽ chiingf lên nhau.
Để hiểu tại sai nó lại là vấn đề, chúng ta cần biết hình ảnh cuối cung được tạo ra như thế nào. Pixel cuối cùng mà người dùng nhìn thấy là một bố cục pha trộn các pixel trên cùng và bên dưới cùng tọa độ. Nó có nghĩa là mọi view layer phải được render để tạo hình ảnh cuối cùng. Khi view layer mờ đục, blending(Pha trộn) có thể được tối ưu hóa bằng cách không vẽ các layer bên dưới.
Để bẻ cong góc và đổ bóng cho View, tôi sử dụng CALayer properties:
let cardView = UIView()
cardView.layer.cornerRadius = 10.0
cardView.layer.shadowColor = UIColor.black.cgColor
cardView.layer.shadowOpacity = 0.5
cardView.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
cardView.layer.shadowRadius = 4.0
Điều này làm cho các phần view của tôi có các layer trong suốt, nó gây ra việc blending không cần thiết. Bởi vì background color được tô, nên rendering có thể được tối ưu. Ta sẽ set một solid background cho View của mình và sử dụng hình nên mà không có alpha:
let cardView = UIImageView(image: UIImage(named: "cardBackground"))
Đây là một thủ thuật đơn giản giúp chúng ta giải quyết việc bị blending.
Lúc này hiệu suất của ứng dụng đã tốt hơn, cho cảm giác cuộn rất mượt.
Bạn cũng có trể truy cập nhanh vào Color Blended Layers từ iOS Simulator.
4. Pixie
Pixie giúp bạn thực hiện thiết kế một cách hoàn hảo. Công cụ này cho phép bạn kiểm tra từng pixel của ứng dụng theo đúng nghĩa đen.
Pixie có thể được tải từ website của Apple. XCode > Open Developer Tool > More Developer Tools… trong công cụ bổ xung cho XCode.
Tổng kết
Mình hi vọng bài này giúp các bạn có thể giúp các bạn tận dụng tool debug của apple để làm việc tốt hơn 😀
- iOS/Auto Layout – Phần 1: Auto layout là gì?
- iOS/Auto Layout – Phần 2: Sử dụng “XCode/Interface Builder” sao cho hiệu quả?
- iOS/Auto Layout – Phần 3: Anatomy of a Constraint, cách để tạo constraints bằng code
- iOS/Auto Layout – Phần 4: Làm sao để viết constraint dễ dàng hơn? Giới thiệu Snapkit
- iOS/Auto Layout – Phần 5: Stack View
- iOS/Auto Layout – Phần 6: Những trường hợp đặc biệt trong Auto Layout