Blog
Ghi chú về Swift, Rust và những thứ mình học được khi làm ứng dụng.
- Chuyển một bộ test từ XCTest sang Swift Testing
Test tham số hóa đã dẹp đi một phần ba lượng code test của tôi, và một khác biệt về hành vi đã bẫy tôi.
- Hãy đọc mã nguồn, đừng chỉ đọc tài liệu
Thói quen làm thay đổi tốc độ tiến bộ của tôi nhiều nhất, và cách bắt đầu mà không bị choáng ngợp.
- Một KeyPath tốn những gì
Chúng trông như cú pháp và chúng là đối tượng. Khi nào điều đó quan trọng, và khi nào thì không.
- SwiftData sau tám năm dùng Core Data
Nó thật sự chữa được gì, giấu đi cái gì, và ba chỗ tôi vẫn phải tụt xuống tầng bên dưới.
- UIViewRepresentable làm cho tử tế
Ba phương thức, một Coordinator, và cái vòng lặp cập nhật sẽ làm đơ ứng dụng của bạn nếu làm sai.
- Gọi Rust từ Swift
Một lõi dùng chung viết bằng Rust với một ứng dụng Swift đặt lên trên: ranh giới FFI, các quy tắc về bộ nhớ, và liệu nó có đáng không.
- Thử lại có độ lùi, và những request không được phép thử lại
Hai mươi dòng async/await, cộng với quyết định còn quan trọng hơn cả thuật toán.
- Làm cho preview SwiftUI thật sự dùng được
Preview trong ứng dụng của tôi hỏng, nên tôi thôi dùng. Việc lấy lại chúng đã đổi cách tôi dựng màn hình.
- Sáu lần bị App Store từ chối và thứ thật sự chữa được chúng
Lần nào cũng tránh được. Con số điều khoản ấy thật ra nghĩa là gì, và câu trả lời đã giúp từng bản build được duyệt.
- Khi nào unsafe là chính đáng, và bạn nợ gì khi dùng nó
unsafe không phải lối thoát khỏi borrow checker. Nó là một lời cam kết, và đây là việc viết lời cam kết ấy ra trông như thế nào.
- `lazy var` không an toàn luồng, còn `static let` thì có
Hai tính năng Swift trông như cùng một ý tưởng. Một cái an toàn trước truy cập đồng thời, cái kia sẽ làm hỏng bộ nhớ.
- Dùng Keychain trực tiếp, không cần thư viện bọc
Bốn hàm và khoảng sáu mươi dòng. API thì khó chịu, và nó không đủ lớn để biện minh cho một phụ thuộc.
- Iterator của Rust thật sự không tốn gì
Tôi không tin lời tuyên bố chi phí bằng không, nên tôi đi xem mã máy. Đây là thứ trình biên dịch thật sự làm.
- Vì sao Swift không cho bạn viết `string[0]`
Nó trông như sự thù địch với người mới. Thật ra nó là thiết kế đúng duy nhất, và lý do nằm ở một cái emoji.
- Vì sao tôi viết sách thay vì viết thread
Viết dài thì kém hơn về độ phủ và tốt hơn ở mọi mặt khác. Việc viết một chương làm được điều mà một thread thì không.
- Làm cho tác vụ chạy nền thật sự chạy
BGTaskScheduler là một lời đề nghị, không phải một lời hứa. Sáu lý do tác vụ của tôi không bao giờ nổ, và cách kiểm thử một cái trong mười giây.
- `.task` và thứ thật sự hủy nó
Cái modifier đã thay cho onAppear, tham số `id:` đã chữa được dữ liệu cũ của tôi, và một trường hợp nó không nổ.
- SQL được kiểm tra lúc biên dịch với sqlx
Các truy vấn của bạn được đối chiếu với một cơ sở dữ liệu thật ngay khi build. Nó bắt được gì, và nó tốn gì cho CI của bạn.
- Những phần tuân thủ Codable vỡ trong môi trường thật
Sáu cách một Codable được sinh tự động hỏng khi gặp một API thật, và nên viết gì thay thế.
- Đưa một ứng dụng từ 142MB xuống 38MB
Dung lượng thật sự nằm ở đâu, và con số Apple báo cáo không phải con số người dùng nhìn thấy.
- Thay các singleton bằng environment
Mười hai thuộc tính `.shared` khiến nửa ứng dụng không kiểm thử được. Tôi đã thay chúng bằng gì, và hai cái tôi giữ lại.
- Website này không gửi đi framework JavaScript nào, một cách có chủ đích
Một website Astro tĩnh với một shader và ít JavaScript thuần tốn gì để xây và bảo trì, sau bốn tháng.
- Hình dạng của một dịch vụ axum còn bảo trì được
Extractor, state, middleware và xử lý lỗi — cấu trúc tôi đi đến sau khi làm sai hai phiên bản đầu.
- Macro Swift đầu tiên của tôi, và vì sao tôi xóa cái thứ hai
Macro là công cụ siêu lập trình mạnh nhất Swift có. Hai trong ba cái tôi viết lẽ ra nên là hàm.
- Giải mã ký hiệu một báo cáo sự cố từ App Store
Một bức tường địa chỉ hex trở thành một số dòng trong ba câu lệnh, một khi bạn có đúng cái dSYM.
- NavigationStack với một path có kiểu
Điều hướng bằng code sống sót được qua một deep link, một lần khôi phục trạng thái và một cú 'về màn hình gốc' — trong khoảng bốn mươi dòng.
- Một CLI Rust có cảm giác hoàn chỉnh
API derive của clap, cộng bốn thứ phân biệt một cái script với một công cụ mà người ta chịu dùng.
- Viết một result builder, và khi nào thì đừng
Cơ chế đứng sau @ViewBuilder, dựng lại từ đầu cho một DSL truy vấn — và lập luận thành thật chống lại việc làm điều đó.
- Bốn lần tôi tối ưu nhầm chỗ
Mỗi lần đều là một phỏng đoán đầy tự tin, và lần nào cũng sai. Đây là những gì trình đo hiệu năng thật sự nói.
- Chuyển build settings của bạn vào các file xcconfig
Thiết lập nằm trong file dự án thì vô hình khi review và là một xung đột merge đang chờ xảy ra. File văn bản chữa được cả hai.
- dyn Trait hay generic: quyết định nằm ở cái tập hợp
Điều phối tĩnh và động trong Rust, và câu hỏi chốt hạ nhanh hơn cả việc đi đo hiệu năng.
- Bật kiểm tra concurrency nghiêm ngặt trên một ứng dụng bốn năm tuổi
812 cảnh báo trong ngày đầu. Thứ tự khiến việc đó khả thi, và hai thay đổi đã dẹp phần lớn chúng.
- Chẻ một ứng dụng thành các Swift package cục bộ
Việc chia module thật sự đem lại gì, tốn gì, và sai lầm về phụ thuộc đã mất một tuần để gỡ.
- PreferenceKey, giải thích bằng cách tự viết một cái
Dữ liệu chảy xuống cây view SwiftUI qua environment. PreferenceKey là cách nó chảy ngược lên.
- Tôi tìm gì khi review code
Bốn thứ, theo thứ tự. Phong cách không nằm trong đó, và mọi thứ một cái linter bắt được cũng vậy.
- Lifetime trong struct: khi nào mượn và khi nào sở hữu
Cái `'a` trong định nghĩa một struct mang một nghĩa cụ thể, và nó thường là dấu hiệu rằng lẽ ra bạn nên dùng String thay vì &str.
- Task.cancel() gần như chẳng làm gì
Việc hủy trong Swift concurrency là hợp tác. Nếu code của bạn không bao giờ kiểm tra thì hủy nó chẳng thay đổi điều gì.
- Cắt một bản build Xcode 4 phút xuống 50 giây
Đo xem hàm nào chậm khi kiểm tra kiểu, và ba khuôn mẫu biểu thức đã gây ra phần lớn chuyện đó.
- Vì sao List của tôi cuộn tệ, và bốn thứ đã chữa được nó
Một danh sách SwiftUI giật trên iPhone SE. Không nguyên nhân nào là thứ tôi đã đoán.
- Arc<Mutex<T>> và ba lần bạn không cần đến nó
Câu trả lời mặc định cho trạng thái dùng chung trong Rust, và vì sao với tới nó đầu tiên thường là một lối tắt trong thiết kế.
- Con bug tái nhập actor tôi đã phát hành
Actor ngăn được đua dữ liệu. Chúng không ngăn được các bất biến của bạn vỡ qua một lần await, và tôi phát hiện ra điều đó trong môi trường thật.
- Tôi sẽ học gì trước, nếu được bắt đầu lại từ đầu theo kiểu tự học
Sau bốn năm, những lỗ hổng tôi thật sự có không phải những thứ tôi từng lo. Đây là thứ tôi sẽ ưu tiên bây giờ.
- Tìm một vòng giữ tham chiếu bằng Memory Graph Debugger
Một chỗ rò làm tăng 4MB mỗi lần đẩy màn hình. Cách tìm ra nó trong năm phút thay vì đọc từng closure trong file.
- Thôi với tới GeometryReader
Nó tham lam, nó chạy trong lượt tính kích thước, và bốn API mới hơn lo được phần lớn những việc người ta dùng nó để làm.
- Vì sao tôi thôi đắn đo về runtime async của Rust
async-std, smol, hay tokio. Quyết định đó lấy của tôi một tuần và lẽ ra chỉ nên mất mười phút.
- Làm cho một kiểu Sendable mà không với tới @unchecked
@unchecked Sendable làm trình biên dịch im lặng và giữ nguyên con bug. Bốn cách để giành được phần tuân thủ ấy một cách tử tế.
- Cắt thời gian khởi động nguội từ 2,1s xuống 900ms
Thời gian thật sự đi đâu trong một ứng dụng mà tôi đinh ninh là đã nhanh, và phép đo khiến nó lộ ra.
- Chuyển ObservableObject sang @Observable, và những lần vẽ lại biến mất
Một cuộc chuyển đổi máy móc với đúng một phần không máy móc, và một khoản lợi hiệu năng mà tôi không ngờ lại lớn đến vậy.
- Một quy trình gỡ lỗi, cho lúc bạn đã cạn ý tưởng
Không phải mẹo vặt. Một quy trình — thứ tôi quay về khi con bug đã hạ tôi suốt một ngày và việc đoán mò đã thôi hiệu nghiệm.
- thiserror hay anyhow: ranh giới nằm ở ranh giới thư viện
Hai crate trông như hai lựa chọn thay thế nhau mà không phải. Quy tắc quyết định chọn cái nào, gói trong một câu.
- weak, unowned, và cú sập tôi đã phát hành
Lời khuyên ai cũng nhắc lại nói về vòng đời. Quy tắc thật sự giữ bạn an toàn nói về việc ai sống lâu hơn ai, và tôi học được nó theo cách đắt đỏ.
- Đọc một bản ghi Time Profiler mà không cần đoán
Instruments cho bạn một biểu đồ ngọn lửa và cả triệu mẫu. Bốn thiết lập biến nó thành một câu trả lời.
- Cái animation nhảy phựt, và câu `if` gây ra nó
Một chuyển cảnh SwiftUI nhất định không chịu chạy animation, và câu điều kiện hai nhánh vẫn lặng lẽ hủy view mỗi lần.
- Borrow checker là một người đọc, không phải một người gác cổng
Đến từ Swift, tôi vật lộn với borrow checker của Rust suốt một tháng. Đây là mô hình khiến nó thôi là một cuộc vật lộn.
- `any` thật ra tốn những gì
Swift bắt viết existential ra một cách tường minh là có lý do. Đây là việc cái hộp đó làm, và khi nào generic mới là câu trả lời tốt hơn.
- Vì sao có blog này
Chỗ dành cho những ghi chú quá ngắn để viết thành sách.