2014-06-09 27 views
26

Hãy nói rằng tôi có lớp sau trong Swift (trong đó có vấn đề rõ ràng)phương pháp Gọi từ Swift initializer

class MyClass { 
    let myProperty: String 

    init() { 
     super.init() 
     self.setupMyProperty() 
    } 

    func setupMyProperty() { 
     myProperty = "x" 
    } 
} 

Đây là quá đơn giản nhưng tôi về cơ bản cố gắng để ủy thác việc khởi tạo myProperty vào phương pháp setupMyProperty() . Đó là một mẫu mà tôi thường sử dụng để chia nhỏ các phần khác nhau của việc thiết lập một lớp. Nhưng tất nhiên, tôi không thể gọi self cho đến khi trình khởi chạy siêu chạy, và tôi không thể chạy trình khởi chạy siêu cho đến khi tất cả các thuộc tính đã được thiết lập, vì vậy tôi đang nắm bắt 22. Trên đầu trang của kể từ setupMyProperty() không được coi là bộ khởi tạo, nó sẽ không thể gán myProperty.

Có ai có thể cho tôi biết cách triển khai mẫu này trong Swift không?

+0

Tôi không biết điều này có phù hợp với bạn hay không nhưng bạn có thể gán giá trị khi khai báo thuộc tính. 'cho phép myProperty: String =" x "' –

+0

Vâng, tôi sử dụng nó ở nơi có ý nghĩa.Nhưng trong trường hợp những thứ này được khởi tạo dựa trên các tham số cho bộ khởi tạo, thì bộ khởi tạo trở nên lộn xộn. Tôi đoán đó là dấu hiệu lớp của tôi có quá nhiều thuộc tính. – mprivat

+1

Kiểm tra phiên WWDC 403: Trung cấp Swift, khoảng 29 phút trong bao gồm khởi tạo lớp. – DogCoffee

Trả lời

30

tuyên bố nó như một ngầm nào không bắt buộc

class MyClass : NSObject { 
    var myProperty: String! 

    init() { 
     super.init() 
     self.setupMyProperty() 
    } 

    func setupMyProperty() { 
     self.myProperty = "x" 
    } 
} 

trang 499 của "The Ngôn ngữ lập trình Swift" bằng tay

+1

Bạn không bị mất an toàn bằng cách làm điều này? Tôi đoán tôi phải chắc chắn rằng các tài sản được khởi tạo trước khi nó được truy cập hoặc người nào khác sẽ có một lỗi thời gian chạy. Và nó không thể là một hằng số cho trường hợp này. Tôi đoán đây là cách tốt nhất tôi đã nhìn thấy, chỉ cần không hoàn hảo – mprivat

+0

Nó sẽ được truy cập trước khi khởi tạo chỉ trong trường hợp một thread khác cố gắng truy cập nó giữa super.init() và "set" thực sự ... Tôi không biết liệu bạn có thể khóa biến cho đến khi nó được khởi tạo hoàn toàn hay không (xem http://stackoverflow.com/questions/24045895/what-is-the-swift-equivalent-to-objective-cs-synchronized, nhưng tôi ' m không tài liệu đủ để nói nếu nó có thể và nếu nó có thể là một vấn đề bằng cách sử dụng nó trong một initializer). Câu trả lời của Bill có vẻ là một lựa chọn tốt khác. – LombaX

+0

Vì vậy, không có cách nào để giữ 'myProperty' một hằng số (let)? –

2

Bạn không thể sử dụng self cho đến khi bộ nhớ của dụ của bạn được khởi tạo đầy đủ (lúc này bạn không thể đặt thuộc tính cố định nữa), do đó, thứ tự mà trình khởi tạo được chỉ định của bạn phải làm mọi việc là:

  1. khởi tạo tất cả các thuộc tính được thêm vào bởi lớp này
  2. gọi cha initializer (nếu có một lớp cha)
  3. bây giờ bạn có thể sử dụng self, phương pháp gọi, vv

Tôi không chắc chắn nếu có một cách giải quyết tốt đối với trường hợp một tài sản cố định. Một thay thế sẽ được kê khai tài sản như một tùy chọn ngầm nào, vì vậy nó bước đầu thiết lập để nil:

class MyClass { 
    var myProperty: String! 
    init() { 
     super.init() // only if you actually have a superclass, and make sure this does not use `myProperty` 
     self.setupMyProperty() 
    } 

    func setupMyProperty() { 
     myProperty = "x" 
    } 
} 

Hãy cẩn thận với điều này, nó sẽ mất một chút kiểu an toàn, như myProperty bây giờ có thể được nil, và nếu đó là khi bạn cố gắng truy cập nó, nó sẽ dẫn đến một lỗi thời gian chạy. Vì vậy, chỉ thực hiện điều này nếu bạn chắc chắn nó sẽ được khởi tạo bởi tất cả các trình khởi tạo được chỉ định của bạn, không được sử dụng bởi bất kỳ thứ gì được gọi trước setupMyProperty() trong chuỗi khởi tạo (ví dụ: khi trình khởi tạo siêu lớp gọi phương thức bạn ghi đè truy cập myProperty) và không bao giờ đặt thành nil một cách rõ ràng.

Ngoài ra, cf. the docs, đặc biệt là phần về Thừa kế và Khởi tạo Lớp cho toàn bộ thứ tự gọi tôi đã giải thích ở trên.

+1

'private (set) var myProperty: String' sẽ ngăn chặn những thay đổi bất thường bên ngoài giá trị tài sản của bạn – bshirley

8

setupMyProperty cần truy cập tự? Nếu không, bạn có thể đạt được điều này với phương thức lớp học:

class MyClass: NSObject { 
    let myProperty: String 

    init() { 
     myProperty = MyClass.setupMyProperty() 
     super.init() 
    } 

    class func setupMyProperty() -> String { 
     return "foo" 
    } 
} 
+2

Vấn đề ở đây là khi nó hoạt động với ví dụ đơn giản, toàn bộ điểm là khởi tạo một tập hợp các thuộc tính trong một phương thức con. – mprivat

1

Thử đặt setupMyProperty() trong một hằng số. Sau đó, nó có trước khi bạn khởi tạo và bạn có thể gọi nó từ init(). Bạn thậm chí có thể truy cập các thông số như sau:

class MyClass { 
    var myProperty: String 
    let setupMyProperty : (String) -> (void) = { 
     param in 
     self.myProperty = param 
    } 

    init(x: String) { 
    // removed redundant line: super.init() 
     self.setupMyProperty(x) 
    } 
} 
+0

Bạn không cần super.init() trong lớp của bạn vì 'MyClass' là một lớp gốc. –

+0

Chắc chắn, tôi đã làm điều đó mà không cần suy nghĩ. Đã xóa dòng vi phạm ngay bây giờ. – Tchelyzt

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