24/09/2022

Chuyển vòng lặp for từ Object-C sang Swift

 Hôm qua gặp một cái bug khá vui. Mình và bạn khác nữa làm dự án Port code cũ Object-C sang Swift. Bạn này sau khi kết thúc giai đoạn coding thì rời dự án và mình tiếp tục test và fix bug. Mình chạy test case trên code cũ và code mới thấy kết quả khác nhau. Mình review từng dòng code thấy không có vấn đề gì (tuy cả ngàn LOC nha). Cái mình nghi ngờ nhất là hai vòng for lồng nhau mình chèn code xuất log và phát hiện chính xác nguyên nhân là do cách port vòng for.

Trong Object-C vòng for sau đây:


for (int i = 1; i <= 10; i++)
{
    //do something
}

được chuyển sang Swift như sau:

for i in 1..<11 {
//do something
}
và vấn đề phát sinh khi trong thân của vòng lặp chúng ta thay đổi biến đếm i. Ở phiến bản Object-C thì mỗi lần quay lại vòng lặp biến i được tăng thêm 1 và so sánh 10 xem i đã vượt quá 10 chưa nếu chưa thì tiếp tục thực hiện các câu lệnh bên trong vòng lặp. Ở phiên bản Swift thì 1..<11 là một iterable (xem thêm về IteratorProtocol) nên khi mỗi lần vòng lặp quay lại thì i=iterable.next() và giá trị của i bên trong vòng lặp đã bị ghi đè, huỷ bỏ. Kết quả hai phiên bản chạy hoàn toàn khác nhau.

Trong trường hợp này trong Swift nên dùng vòng lặp while thay cho vòng lặp for.