2014-11-20 21 views
37

Tôi đang đấu tranh để hiểu tại sao tôi nhận được lỗi trình biên dịch này trong một dự án iOS bằng Swift. Nếu tôi tạo lớp sau:Tại sao tôi nhận được lỗi "Biến được sử dụng trước khi được khởi tạo" trên dòng mà tôi khởi tạo biến trong Swift?

class InitTest { 

    let a: Int 
    let b: Int 
    let c: Int 

    init() { 
     self.a = 3 
     self.b = 4 
     self.c = self.runCalculation() 
    } 

    func runCalculation() -> Int { 
     return self.a * self.b 
    } 
} 

Tôi nhận được lỗi trình biên dịch trên dòng self.c = self.runCalculation() nói "Tự biến" được sử dụng trước khi được khởi tạo ".

Lúc đầu, tôi nghĩ rằng điều này là do trình biên dịch không thể xác minh rằng phương pháp runCalculation() không truy cập self.c, nhưng sau đó tôi đã cố gắng pha trộn các phương pháp init lên một chút:

init() { 
    self.a = 3 
    self.c = self.runCalculation() 
    self.b = 4 
} 

và lần này lỗi là "Biến" self.b 'được sử dụng trước khi được khởi tạo "(trên cùng một dòng self.runCalculation()). Điều này chỉ ra rằng trình biên dịch có khả năng kiểm tra các thuộc tính mà phương thức truy cập và vì vậy, theo tôi có thể thấy không có vấn đề gì với trường hợp ban đầu. Tất nhiên đây là một ví dụ nhỏ và tôi có thể dễ dàng refactor để tránh gọi phương pháp tính toán, nhưng trong một dự án thực sự có thể có một số tính toán mỗi trong số đó có thể được khá tham gia. Tôi muốn có thể tách ra khỏi logic để giữ cho mọi thứ có thể đọc được.

May mắn thay có một cách giải quyết đơn giản:

init() { 
    self.a = 3 
    self.b = 4 

    self.c = 0 
    self.c = self.runCalculation() 
} 

(hoặc sử dụng một tài sản initialiser let c = 0) nhưng tôi muốn hiểu lý do tại sao các trình biên dịch có một vấn đề với ví dụ đầu tiên. Tôi có thiếu cái gì đó hay là một hạn chế không cần thiết?

Trả lời

42

Swift có hành vi này do hai giai đoạn khởi tạo. Từ cuốn sách Swift của Apple:

Khởi tạo lớp trong Swift là một quy trình hai pha. Trong giai đoạn đầu tiên, mỗi thuộc tính được lưu trữ được gán giá trị ban đầu theo lớp giới thiệu nó. Khi trạng thái ban đầu cho mỗi thuộc tính được lưu trữ đã được xác định, giai đoạn thứ hai bắt đầu và mỗi lớp được cấp cơ hội tùy chỉnh các thuộc tính được lưu trữ của nó trước khi cá thể mới được xem là sẵn sàng để sử dụng.

Lớp cần một loại giá trị mặc định trước khi kết thúc giai đoạn đầu tiên. Các giá trị tùy biến là một phần của giai đoạn thứ hai.

Objective-C không có hành vi này, bởi vì nó luôn luôn có thể cung cấp cho 0 như mặc định cho nguyên thủy và nil cho các đối tượng, nhưng trong Swift không có cơ chế để cho giá trị mặc định như vậy.

+0

Khi nào giai đoạn đầu tiên kết thúc? Tôi đã nghĩ rằng 'self.c = self.runCalculation()' vẫn đang trong giai đoạn đầu tiên. – rankAmateur

+0

Giai đoạn đầu tiên kết thúc sau khi bạn cung cấp các giá trị ban đầu cho các thuộc tính được lưu trữ cho lớp gốc trong phân cấp lớp. Vì vậy, trong trường hợp này nó kết thúc khi bạn đặt 'self.c = 0'. – Kirsteins

+0

Nếu tôi sử dụng 'self.c = self.a * self.b' thay vì gọi phương thức thì không có vấn đề gì. Nó là gì về việc gọi một phương pháp thay đổi mọi thứ? – rankAmateur

Các vấn đề liên quan