Quan sát thuộc tính
Thuộc phần Lập trình hướng đối tượng trong hành trình Swift của Coddy. Bài học 13 trên 57.
Bộ quan sát thuộc tính chạy code mỗi khi thuộc tính được lưu trữ thay đổi. didSet chạy ngay sau khi giá trị mới được lưu, và bên trong đó, oldValue giữ giá trị trước đó:
class Player {
var score = 0 {
didSet {
print("score \(oldValue) -> \(score)")
}
}
}
let p = Player()
p.score = 10
p.score += 5Đầu ra:
score 0 -> 10
score 10 -> 15willSet chạy trước khi giá trị thay đổi, với giá trị mới được truyền vào dưới dạng newValue. Các trình quan sát không chạy khi thuộc tính nhận giá trị ban đầu:
struct Thermostat {
var target = 20 {
willSet { print("changing to \(newValue)") }
didSet { print("changed from \(oldValue)") }
}
}
var t = Thermostat()
t.target = 22Đầu ra:
changing to 22
changed from 20didSet là nơi phù hợp để giữ cho một giá trị luôn hợp lệ. Gán giá trị cho thuộc tính bên trong chính didSet của thuộc tính đó sẽ không kích hoạt lại trình quan sát:
struct Volume {
var level = 5 {
didSet {
if level > 10 { level = 10 }
if level < 0 { level = 0 }
}
}
}
var v = Volume()
v.level = 42
print(v.level)
v.level = -3
print(v.level)Đầu ra:
10
0Observer cũng có thể lưu lịch sử hoặc cập nhật trạng thái liên quan, nhờ đó logic nằm cạnh thuộc tính thay vì rải rác trong code:
class Account {
var history: [Int] = []
var balance = 0 {
didSet { history.append(balance - oldValue) }
}
}
let a = Account()
a.balance = 100
a.balance = 70
print(a.history)Đầu ra:
[100, -30]Thử thách
DễHoàn thiện lớp Tank. Thuộc tính được lưu trữ level phải luôn nằm trong khoảng từ 0 đến capacity: thêm didSet để điều chỉnh các giá trị nằm ngoài khoảng đó và thêm cảnh báo low vào alerts bất cứ khi nào mức đã điều chỉnh xuống dưới 20% sức chứa (và mức trước đó không thấp).
Code được cung cấp đọc sức chứa, sau đó thay đổi +n hoặc -n. Code in ra mức sau mỗi lần thay đổi và cuối cùng in alerts: cùng số cảnh báo.
Code của bạn nằm trong Tank.swift. main.swift chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.
Tự làm thử
// Đoạn code đầu vào/đầu ra đã được cung cấp: giữ nguyên
var input: [String] = []
while let line = readLine() { input.append(line) }
let tank = Tank(capacity: Int(input[0])!)
for cmd in input.dropFirst() {
let n = Int(cmd.dropFirst())!
tank.level += cmd.hasPrefix("+") ? n : -n
print(tank.level)
}
print("alerts: \(tank.alerts.count)")
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Lớp và đối tượng
Làm việc với tệpĐịnh nghĩa lớpPhương thức và selfHàm khởi tạoLớp là tham chiếuÔn tập: Thẻ thư viện2Struct và kiểu giá trị
StructNgữ nghĩa giá trịPhương thức thay đổiStruct hay classÔn tập: mặt hàng trong kho5Kế thừa
Lớp conGhi đè phương thứcHàm khởi tạo và superfinal và hệ phân cấpÔn tập: hệ phân cấp nhân viên8Các giao thức tiêu chuẩn
CustomStringConvertibleEquatableComparableHashableÔn tập: Sắp xếp tùy chỉnh3Tìm hiểu sâu về thuộc tính
Thuộc tính tính toánQuan sát thuộc tínhThành viên tĩnhEnum với phương thứcÔn tập: Nhật ký nhiệt độTự luyện tập: Playground Swift