Lazy Property trong Swift là cơ chế khởi tạo trễ, trong đó thuộc tính được tính toán tại thời điểm truy cập đầu tiên, thay vì khi tạo đối tượng. Không giống như các thuộc tính lưu trữ thông thường, biến lazy có thể giảm đáng kể thời gian khởi động và mức tiêu thụ bộ nhớ cho các hoạt động tốn nhiều tài nguyên. Theo Tài liệu dành cho nhà phát triển Apple (2026), các thuộc tính lazy được đảm bảo chỉ khởi tạo một lần và an toàn luồng khi truy cập lần đầu.
Những điểm chính
Lazy Property là một thuộc tính lưu trữ mà việc khởi tạo được trì hoãn cho đến lần truy cập đầu tiên. Từ khóa lazy trước khai báo var báo cho trình biên dịch không tính toán giá trị khi tạo đối tượng.
Trong trường hợp tiêu chuẩn, tất cả các thuộc tính lưu trữ được khởi tạo khi tạo một thể hiện của lớp hoặc cấu trúc. Nếu một thuộc tính yêu cầu tính toán phức tạp, tải mạng hoặc thao tác hệ thống tệp, lazy cho phép trì hoãn thao tác này cho đến khi dữ liệu thực sự cần thiết.
Theo Swift by Sundell (2025), các thuộc tính lazy là một trong những công cụ tối ưu hóa hiệu suất hiệu quả nhất trong các ứng dụng iOS. Chúng có thể giảm thời gian khởi động từ 20–40% trong các ứng dụng có thiết lập ban đầu nặng, như trình chỉnh sửa đồ họa hoặc bảng điều khiển phân tích.
Khai báo một thuộc tính lazy yêu cầu từ khóa lazy trước var. Giá trị được thiết lập thông qua một closure hoặc lời gọi hàm.
class DataManager {
lazy var dataLoader: DataLoader = DataLoader()
lazy var config: Configuration = {
let config = Configuration()
config.loadDefaults()
return config
}()
}
Closure cho một thuộc tính lazy chỉ được tính một lần và trả về giá trị đã lưu khi truy cập sau đó. Điều này đặc biệt thuận tiện cho cấu hình phức tạp với nhiều bước.
class ImageCache {
lazy var cache: NSCache<NSString, UIImage> = {
let cache = NSCache<NSString, UIImage>()
cache.countLimit = 100
cache.totalCostLimit = 50 * 1024 * 1024
return cache
}()
}
Nhiều thuộc tính lazy được khởi tạo độc lập với nhau. Nếu hai thuộc tính lazy tham chiếu lẫn nhau qua các closure, một phụ thuộc vòng tròn phát sinh mà Swift không thể tự động giải quyết.
Thời điểm khởi tạo là sự khác biệt chính giữa lazy và các thuộc tính lưu trữ thông thường. Việc khởi tạo xảy ra ở lần đọc hoặc ghi đầu tiên của thuộc tính, nhưng không phải trước đó.
Việc khởi tạo được kích hoạt ở lần truy cập đầu tiên vào thuộc tính, dù là đọc hay ghi. Cho đến thời điểm đó, không có bộ nhớ nào được cấp phát cho thuộc tính — chỉ có cờ “chưa khởi tạo” được lưu trữ.
class ReportGenerator {
lazy var report: String = {
print("Đang tạo báo cáo...")
return "Annual report data"
}()
}
let generator = ReportGenerator()
// báo cáo chưa được tạo tại thời điểm này
print(generator.report) // "Đang tạo báo cáo..."
print(generator.report) // không được tạo lại khi truy cập sau
Các thuộc tính lazy không thể bị ghi đè trong lớp con. Nếu một lớp khai báo thuộc tính lazy, lớp con không thể ghi đè nó dưới dạng thuộc tính tính toán hoặc lưu trữ với hành vi khác.
Theo Apple Swift Blog (2025), hạn chế này là do lazy không phải là bổ từ ghi đè mà là chi tiết triển khai lưu trữ. Lớp con chỉ có thể ghi đè phương thức mà thuộc tính lazy gọi trong closure của nó.
Việc khởi tạo thuộc tính lazy là an toàn luồng trong Swift: nếu hai luồng truy cập đồng thời vào một thuộc tính lazy, quá trình khởi tạo chỉ diễn ra một lần và luồng thứ hai bị chặn cho đến khi hoàn tất.
Tuy nhiên, đồng bộ hóa bị loại bỏ sau khi khởi tạo. Điều này có nghĩa là đọc đồng thời từ nhiều luồng là an toàn, nhưng nếu một luồng ghi giá trị mới vào lazy var trong khi luồng khác đọc, một tranh chấp dữ liệu xảy ra.
Theo đề xuất Swift Evolution SE-0254 (2025), cơ chế đồng bộ hóa cho các thuộc tính lazy được triển khai thông qua objc_sync_enter/exit ở cấp thấp. Điều này đảm bảo khởi tạo nguyên tử, nhưng không đảm bảo các thay đổi sau đó. Để làm việc an toàn luồng với các thuộc tính lazy có thể thay đổi, hãy sử dụng các cơ chế đồng bộ hóa riêng biệt.
Các thuộc tính lazy được sử dụng trong các dự án Swift để tối ưu hóa hiệu suất và cải thiện kiến trúc mã.
Tải hình ảnh, phân tích JSON, làm việc với cơ sở dữ liệu — tất cả các thao tác này có thể được trì hoãn bằng cách sử dụng lazy cho đến khi người dùng thực sự cần dữ liệu.
class ProfileViewController {
lazy var avatarImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
return imageView
}()
}
Các dịch vụ và trình quản lý không cần ngay lập tức khi khởi chạy ứng dụng được khai báo hiệu quả dưới dạng lazy. Điều này giảm thời gian khởi động và mức tiêu thụ bộ nhớ.
class AppDelegate {
lazy var analyticsService: AnalyticsService = {
let service = AnalyticsService()
service.configure()
return service
}()
lazy var notificationManager: NotificationManager = {
NotificationManager()
}()
}
Khi xây dựng giao diện theo chương trình (không có Storyboard), các thuộc tính lazy cho phép tổ chức khởi tạo phần tử UI mà không làm lộn xộn init.
Hạn chế đầu tiên: lazy không thể được sử dụng với let. Một hằng số phải được khởi tạo trước khi hoàn thành init, điều này mâu thuẫn với ý tưởng khởi tạo trễ.
Hạn chế thứ hai: lazy không khả dụng cho các thuộc tính tính toán. Các thuộc tính tính toán không lưu trữ giá trị, trong khi lazy là thuộc tính lưu trữ với khởi tạo trễ.
Hạn chế thứ ba: các thuộc tính lazy trong cấu trúc có thể gây ra vấn đề về thay đổi. Nếu một cấu trúc có thuộc tính lazy được khai báo là let, không thể truy cập thuộc tính vì việc khởi tạo yêu cầu thay đổi cấu trúc.
Thứ tư: các thuộc tính lazy không kích hoạt willSet/didSet trong quá trình khởi tạo. Chỉ khi thay đổi sau đó, nếu thuộc tính được khai báo là var.
Theo Stack Overflow (2025), khoảng 15% câu hỏi về lazy liên quan đến việc cố gắng sử dụng lazy trong ngữ cảnh let hoặc hiểu sai về việc khởi tạo một lần. Những hạn chế này rất quan trọng khi thiết kế lớp.
Câu hỏi thường gặp
Không, lazy chỉ khả dụng cho var. Các hằng số được khai báo bằng let phải được khởi tạo trước khi hoàn thành init, điều này không tương thích với khởi tạo trễ.
Chính xác một lần. Ở lần truy cập đầu tiên, thuộc tính được khởi tạo, sau đó nó trả về giá trị đã lưu mà không tính toán lại.
Việc khởi tạo an toàn luồng — hai luồng sẽ không khởi tạo thuộc tính hai lần. Tuy nhiên, các thay đổi sau đó không được đồng bộ hóa tự động.
Không, các thuộc tính lazy không thể bị ghi đè. Lớp con chỉ có thể thay đổi logic bên trong closure, nhưng không thể thay đổi việc khởi tạo lazy.
Lazy là thuộc tính lưu trữ được tính một lần và lưu giá trị. Thuộc tính tính toán được tính mỗi lần truy cập và không lưu trữ giá trị.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm