Trang chủ

Giới thiệu

View là giá trị, không phải đối tượng

Một view trong SwiftUI là một struct mô tả những gì cần có trên màn hình ứng với trạng thái hiện tại. Nó không phải thứ bạn giữ lấy rồi sửa — nó được tạo ra, đọc, rồi vứt đi, nhiều lần trong một giây.

struct Counter: View {
    @State private var count = 0

    var body: some View {
        Button("Đã bấm \(count) lần") { count += 1 }
    }
}

Counter được tạo lại mỗi lần trạng thái đổi. Nghe thì tốn kém nhưng không: struct chỉ vài byte, và SwiftUI so bản mô tả mới với bản cũ để quyết định thứ gì thật sự cần vẽ lại.

Mẹo

Cú xoay chuyển tư duy làm mọi thứ còn lại sáng ra: bạn không bao giờ bảo SwiftUI cập nhật. Bạn đổi trạng thái, còn view là một hàm của trạng thái đó. Bất cứ lúc nào bạn thấy mình muốn “làm tươi lại view”, nghĩa là mô hình trạng thái đang sai.

Phần không ai nói với bạn

Nếu view chỉ là một hàm của trạng thái thì SwiftUI đã là một bộ máy template và cuốn sách này đã là một trang tra cứu. Phần thú vị nằm ở chỗ framework phải giữ lại nhiều thứ xuyên qua hàng nghìn struct bị vứt đi ấy — con trỏ đang ở đâu trong một ô nhập chữ, danh sách đã cuộn tới đâu, animation nào đang chạy dở — và struct của bạn thì đã biến mất từ lâu trước khi những thứ đó có ý nghĩa.

Vậy là có hai thế giới song song. Thế giới bạn viết là các giá trị: rẻ, dùng một lần, tạo lại liên tục. Thế giới SwiftUI duy trì là một cây các nút lưu trữ sống lâu, và nó quyết định nút nào thuộc về struct nào của bạn dựa vào vị trí và danh tính của chúng trong cây view.

Gần như mọi lỗi SwiftUI có cảm giác như ma thuật đều là sự bất đồng giữa hai thế giới đó. Ô nhập chữ quên mất bạn vừa gõ gì, animation nhảy giật thay vì trượt, @State bị đặt lại khi view cha vẽ lại, sheet mở ra hiện sai món — mỗi trường hợp đều là framework ghép một struct vào một nút lưu trữ mà bạn không định, hoặc vào một nút mới trong khi bạn mong nút cũ.

Đó là sợi chỉ cuốn sách này lần theo, và cũng là lý do các chương được xếp như vậy thay vì xếp theo bề mặt API.

Sách này nói về gì

View nói về chính cái cây: vì sao ghép lại thắng cấu hình, điều gì cho một view danh tính của nó, và vì sao một modifier là bọc chứ không phải đặt.

Trạng thái và luồng dữ liệu là câu hỏi về quyền sở hữu — một giá trị thuộc về @State, @Binding, @Observable hay @Environment, và mỗi thứ tốn gì khi nó đổi.

Bố cục là cuộc thương lượng giữa cha và con: lời đề nghị, câu trả lời, và cách đọc một bố cục đã ra sai. Chương kết thúc bằng việc tự viết một Layout.

Animation là những gì xảy ra giữa hai trạng thái, vì sao nó gắn với một giá trị chứ không phải một view, và một transaction thật ra mang theo cái gì.

Hiệu năng là chương đo đạc — tìm ra view nào đang vẽ lại và vì sao, thay vì đoán.

Sách giả định gì

Rằng bạn biết Swift. Struct, protocol, generic, closure và kiểu trả về mờ được dùng thẳng mà không rào đón. Nếu những thứ đó còn chông chênh, hãy đọc Swift in Depth trước — hai cuốn được viết để đứng cạnh nhau, và chương về giá trị và tham chiếu là chương cuốn này tựa vào nhiều nhất.

Sách cũng giả định một SwiftUI đời mới: @Observable, NavigationStack và protocol Layout được coi là cách làm bình thường chứ không phải thứ mới đến. Ở đâu một API cũ vẫn đáng biết — thường vì bạn sẽ gặp nó trong codebase không do bạn viết — thì nó được gọi tên hẳn hoi chứ không bị lờ đi.

Đọc thế nào

Lần đầu thì đọc đúng thứ tự. Các chương tựa vào nhau nhiều hơn tên gọi của chúng gợi ra: bố cục rất khó lập luận khi chưa biết danh tính là gì, còn animation thì không đọc nổi khi chưa có bố cục.

Sau lần đó, sách là tài liệu tra cứu, và mỗi chương được viết để đứng một mình vẫn đọc được.