Lớp không triển khai các thành viên cần thiết của lớp cha


155

Vì vậy, tôi đã cập nhật lên Xcode 6 beta 5 ngày hôm nay và nhận thấy tôi đã nhận được lỗi trong gần như tất cả các lớp con của các lớp học của Apple.

Các lỗi nêu:

Lớp 'x' không triển khai các thành viên bắt buộc của lớp cha của nó

Đây là một ví dụ tôi chọn vì lớp này hiện tại khá nhẹ nên sẽ dễ đăng.

class InfoBar: SKSpriteNode  { //Error message here

    let team: Team
    let healthBar: SKSpriteNode

    init(team: Team, size: CGSize) {
        self.team = team
        if self.team == Team.TeamGood {
            healthBar = SKSpriteNode(color: UIColor.greenColor(), size:size)
        }
        else {
            healthBar = SKSpriteNode(color: UIColor.redColor(), size:size)
        }
        super.init(texture:nil, color: UIColor.darkGrayColor(), size: size)

        self.addChild(healthBar)

    }

}

Vì vậy, câu hỏi của tôi là, tại sao tôi nhận được lỗi này, và làm thế nào tôi có thể sửa nó? Cái gì mà tôi không thực hiện? Tôi đang gọi một trình khởi tạo được chỉ định.

Câu trả lời:


127

Từ một nhân viên Apple trên Diễn đàn nhà phát triển:

"Một cách để khai báo với trình biên dịch và chương trình được xây dựng mà bạn thực sự không muốn tương thích với NSCoding là làm một cái gì đó như thế này:"

required init(coder: NSCoder) {
  fatalError("NSCoding not supported")
}

Nếu bạn biết bạn không muốn tuân thủ NSCoding, đây là một tùy chọn. Tôi đã thực hiện phương pháp này với rất nhiều mã SpriteKit của mình, vì tôi biết tôi sẽ không tải nó từ bảng phân cảnh.


Một tùy chọn khác mà bạn có thể thực hiện khá hiệu quả là triển khai phương thức như một init tiện lợi, như vậy:

convenience required init(coder: NSCoder) {
    self.init(stringParam: "", intParam: 5)
}

Lưu ý cuộc gọi đến một trình khởi tạo trong self. Điều này cho phép bạn chỉ phải sử dụng các giá trị giả cho các tham số, trái ngược với tất cả các thuộc tính không tùy chọn, trong khi tránh ném lỗi nghiêm trọng.


Tất nhiên, tùy chọn thứ ba là triển khai phương thức trong khi gọi super và khởi tạo tất cả các thuộc tính không tùy chọn của bạn. Bạn nên thực hiện phương pháp này nếu đối tượng là chế độ xem được tải từ bảng phân cảnh:

required init(coder aDecoder: NSCoder!) {
    foo = "some string"
    bar = 9001

    super.init(coder: aDecoder)
}

3
Tuy nhiên, tùy chọn thứ hai là vô dụng trong hầu hết các trường hợp thực tế. Lấy ví dụ, trình khởi tạo yêu cầu của tôi init(collection:MPMediaItemCollection). Bạn phải cung cấp một bộ sưu tập vật phẩm truyền thông thực sự; đó là điểm của lớp này Lớp này chỉ đơn giản là không thể được khởi tạo mà không có một. Nó sẽ phân tích bộ sưu tập và khởi tạo một tá biến thể hiện. Đó là toàn bộ quan điểm của việc này là trình khởi tạo được chỉ định một và duy nhất! Do đó, init(coder:)không có MPMediaItemCollection có ý nghĩa (hoặc thậm chí vô nghĩa) để cung cấp ở đây; chỉ có fatalErrorcách tiếp cận là đúng.
matt

@matt Đúng, một hoặc tùy chọn khác sẽ hoạt động tốt hơn trong các tình huống khác nhau.
Ben Kane

Phải, và tôi đã khám phá và xem xét tùy chọn thứ hai một cách độc lập, và đôi khi nó sẽ có ý nghĩa. Ví dụ tôi có thể đã khai báo di init(collection:MPMediaItemCollection!). Điều đó sẽ cho phép init(coder:)vượt qua con số không. Nhưng sau đó tôi nhận ra: không, bây giờ bạn chỉ đang lừa trình biên dịch. Vượt qua con số không được chấp nhận, vì vậy hãy ném fatalErrorvà đi tiếp. :)
matt

1
Tôi biết câu hỏi này và câu trả lời của nó hiện đã cũ, nhưng tôi đã đăng một câu trả lời mới giải quyết một số điểm mà tôi nghĩ là rất quan trọng để thực sự hiểu lỗi này mà không có câu trả lời nào hiện có.
nhgrif

Câu trả lời tốt. Tôi đồng ý với bạn rằng việc hiểu rằng Swift không phải luôn kế thừa các siêu khởi tạo là điều cần thiết để hiểu mô hình này.
Ben Kane

71

Có hai thông tin cực kỳ quan trọng về thông tin cụ thể của Swift bị thiếu trong các câu trả lời hiện có mà tôi nghĩ giúp loại bỏ hoàn toàn vấn đề này.

  1. Nếu một giao thức chỉ định một trình khởi tạo là một phương thức bắt buộc, thì trình khởi tạo đó phải được đánh dấu bằng requiredtừ khóa của Swift .
  2. Swift có một bộ quy tắc thừa kế đặc biệt liên quan đến initcác phương thức.

Các tl; dr là đây:

Nếu bạn triển khai bất kỳ trình khởi tạo nào, bạn không còn kế thừa bất kỳ trình khởi tạo nào được chỉ định của lớp cha.

Các trình khởi tạo duy nhất, nếu có, mà bạn sẽ thừa kế, là các trình khởi tạo tiện lợi siêu hạng chỉ đến một trình khởi tạo được chỉ định mà bạn tình cờ ghi đè.

Vậy ... đã sẵn sàng cho phiên bản dài chưa?


Swift có một bộ quy tắc thừa kế đặc biệt liên quan đến initcác phương thức.

Tôi biết đây là điểm thứ hai trong hai điểm tôi đã thực hiện, nhưng chúng tôi không thể hiểu điểm đầu tiên, hoặc tại sao required từ khóa thậm chí tồn tại cho đến khi chúng tôi hiểu điểm này. Một khi chúng ta hiểu điểm này, một điểm khác trở nên khá rõ ràng.

Tất cả thông tin tôi trình bày trong phần này của câu trả lời này là từ tài liệu của Apple được tìm thấy ở đây .

Từ các tài liệu của Apple:

Không giống như các lớp con trong Objective-C, các lớp con Swift không kế thừa các trình khởi tạo siêu lớp của chúng theo mặc định. Cách tiếp cận của Swift ngăn chặn tình huống trong đó một trình khởi tạo đơn giản từ siêu lớp được kế thừa bởi một lớp con chuyên biệt hơn và được sử dụng để tạo một thể hiện mới của lớp con không được khởi tạo đầy đủ hoặc chính xác.

Nhấn mạnh mỏ.

Vì vậy, trực tiếp từ các tài liệu của Apple ngay tại đó, chúng ta thấy rằng các lớp con Swift sẽ không luôn luôn (và thường không) thừa hưởng siêu lớp của chúng init phương thức .

Vì vậy, khi nào họ thừa hưởng từ siêu lớp của họ?

Có hai quy tắc xác định khi một lớp con kế thừa initcác phương thức từ cha của nó. Từ các tài liệu của Apple:

Quy tắc 1

Nếu lớp con của bạn không xác định bất kỳ trình khởi tạo được chỉ định nào, nó sẽ tự động kế thừa tất cả các trình khởi tạo được chỉ định của lớp cha.

Quy tắc 2

Nếu lớp con của bạn cung cấp một triển khai của tất cả các trình khởi tạo được chỉ định của siêu lớp của nó bằng cách kế thừa chúng theo quy tắc 1 hoặc bằng cách cung cấp một triển khai tùy chỉnh như một phần của định nghĩa của nó thì nó sẽ tự động kế thừa tất cả các trình khởi tạo tiện lợi của siêu lớp.

Quy tắc 2 không phải là đặc biệt có liên quan đến chuyện này vì SKSpriteNode's init(coder: NSCoder)là không phải là một phương pháp tiện lợi.

Vì vậy, InfoBarlớp của bạn đã kế thừa trình requiredkhởi tạo cho đến khi bạn thêm vào init(team: Team, size: CGSize).

Nếu bạn đã chưa cung cấp này initphương pháp và thay vào đó làm bạn InfoBar'tính s thêm tùy chọn hoặc cung cấp cho họ với giá trị mặc định, sau đó bạn muốn có vẫn được kế thừa SKSpriteNode' s init(coder: NSCoder). Tuy nhiên, khi chúng tôi thêm trình khởi tạo tùy chỉnh của riêng mình, chúng tôi đã ngừng kế thừa trình khởi tạo được chỉ định của siêu lớp của chúng tôi (và trình khởi tạo tiện lợi không trỏ đến trình khởi tạo mà chúng tôi đã triển khai).

Vì vậy, như một ví dụ đơn giản, tôi trình bày điều này:

class Foo {
    var foo: String
    init(foo: String) {
        self.foo = foo
    }
}

class Bar: Foo {
    var bar: String
    init(foo: String, bar: String) {
        self.bar = bar
        super.init(foo: foo)
    }
}


let x = Bar(foo: "Foo")

Mà trình bày các lỗi sau:

Thiếu đối số cho tham số 'bar' trong cuộc gọi.

nhập mô tả hình ảnh ở đây

Nếu đây là Objective-C, nó sẽ không gặp vấn đề gì khi kế thừa. Nếu chúng ta khởi tạo a Barvới initWithFoo:Objective-C, thuộc self.bartính sẽ đơn giản là nil. Nó có thể không tuyệt vời, nhưng nó là một trạng thái hoàn toàn hợp lệ cho đối tượng ở đó. Nó không phải là trạng thái hoàn toàn hợp lệ cho đối tượng Swift ở. self.barKhông phải là một tùy chọn và không thể lànil .

Một lần nữa, cách duy nhất chúng ta kế thừa các công cụ khởi tạo là không cung cấp riêng của chúng tôi. Vì vậy, nếu chúng ta cố gắng kế thừa bằng cách xóa Bar's init(foo: String, bar: String), như vậy:

class Bar: Foo {
    var bar: String
}

Bây giờ chúng tôi quay lại kế thừa (loại), nhưng điều này sẽ không được biên dịch ... và thông báo lỗi giải thích chính xác lý do tại sao chúng tôi không kế thừa initcác phương thức siêu lớp :

Vấn đề: Class 'Bar' không có trình khởi tạo

Fix-It: Thuộc tính được lưu trữ 'thanh' mà không có trình khởi tạo ngăn chặn trình khởi tạo tổng hợp

Nếu chúng tôi đã thêm các thuộc tính được lưu trữ trong lớp con của chúng tôi, không có cách Swift nào có thể để tạo một phiên bản hợp lệ của lớp con của chúng tôi với các trình khởi tạo siêu lớp mà không thể biết về các thuộc tính được lưu trữ của lớp con của chúng tôi.


Được rồi, tốt, tại sao tôi phải thực hiện init(coder: NSCoder)tất cả? Tại sao vậy required?

Các initphương thức của Swift có thể chơi theo một bộ quy tắc thừa kế đặc biệt, nhưng sự tuân thủ giao thức vẫn được kế thừa trong chuỗi. Nếu một lớp cha tuân thủ một giao thức, các lớp con của nó phải tuân theo giao thức đó.

Thông thường, đây không phải là vấn đề, vì hầu hết các giao thức chỉ yêu cầu các phương thức không chơi theo quy tắc thừa kế đặc biệt trong Swift, vì vậy nếu bạn thừa hưởng từ một lớp phù hợp với giao thức, bạn cũng sẽ thừa hưởng tất cả các giao thức các phương thức hoặc thuộc tính cho phép lớp thỏa mãn giao thức.

Tuy nhiên, hãy nhớ rằng, initcác phương thức của Swift chơi theo một bộ quy tắc đặc biệt và không phải lúc nào cũng được kế thừa. Do đó, một lớp phù hợp với một giao thức yêu cầu các initphương thức đặc biệt (như NSCoding) yêu cầu lớp đánh dấu các initphương thức đó là required.

Xem xét ví dụ này:

protocol InitProtocol {
    init(foo: Int)
}

class ConformingClass: InitProtocol {
    var foo: Int
    init(foo: Int) {
        self.foo = foo
    }
}

Điều này không biên dịch. Nó tạo ra cảnh báo sau:

Vấn đề: Yêu cầu khởi tạo 'init (foo :)' chỉ có thể được thỏa mãn bởi trình khởi tạo 'bắt buộc' trong lớp không hoàn thành 'ConformingClass'

Fix-It: Yêu cầu chèn

Nó muốn tôi thực hiện init(foo: Int)khởi tạo yêu cầu. Tôi cũng có thể làm cho nó hạnh phúc bằng cách tạo ra lớp final(có nghĩa là lớp không thể được kế thừa từ đó).

Vì vậy, điều gì xảy ra nếu tôi phân lớp? Từ thời điểm này, nếu tôi phân lớp, tôi ổn. Nếu tôi thêm bất kỳ trình khởi tạo nào, tôi đột nhiên không còn kế thừa init(foo:). Đây là vấn đề vì bây giờ tôi không còn tuân thủ InitProtocol. Tôi không thể phân lớp từ một lớp phù hợp với giao thức và sau đó đột nhiên quyết định tôi không còn muốn tuân thủ giao thức đó nữa. Tôi đã thừa hưởng sự tuân thủ giao thức, nhưng do cách Swift làm việc với initkế thừa phương thức, tôi đã không được thừa hưởng một phần của những gì bắt buộc phải tuân thủ giao thức đó và tôi phải thực hiện nó.


Được rồi, tất cả điều này có ý nghĩa. Nhưng tại sao tôi không thể nhận được thông báo lỗi hữu ích hơn?

Có thể cho rằng, thông báo lỗi có thể rõ ràng hơn hoặc tốt hơn nếu nó chỉ định rằng lớp của bạn không còn tuân thủ NSCodinggiao thức được kế thừa và để khắc phục nó, bạn cần phải thực hiện init(coder: NSCoder). Chắc chắn rồi.

Nhưng Xcode đơn giản là không thể tạo ra thông báo đó vì thực sự đó sẽ không phải là vấn đề thực sự khi không thực hiện hoặc kế thừa một phương thức bắt buộc. Có ít nhất một lý do khác để tạo ra initcác phương thức requiredbên cạnh việc tuân thủ giao thức và đó là các phương thức xuất xưởng.

Nếu tôi muốn viết một phương thức xuất xưởng phù hợp, tôi cần chỉ định loại trả về là Self(tương đương với Objective-C của Swift instanceType). Nhưng để làm điều này, tôi thực sự cần phải sử dụng một requiredphương thức khởi tạo.

class Box {
    var size: CGSize
    init(size: CGSize) {
        self.size = size
    }

    class func factory() -> Self {
        return self.init(size: CGSizeZero)
    }
}

Điều này tạo ra lỗi:

Xây dựng một đối tượng của loại lớp 'Tự' với giá trị siêu dữ liệu phải sử dụng trình khởi tạo 'bắt buộc'

nhập mô tả hình ảnh ở đây

Về cơ bản là cùng một vấn đề. Nếu chúng ta phân lớp Box, các lớp con của chúng ta sẽ kế thừa phương thức lớp factory. Vì vậy, chúng tôi có thể gọi SubclassedBox.factory(). Tuy nhiên, nếu không có sự requiredtừ khóa trên init(size:)phương pháp, Boxlớp con 's không đảm bảo kế thừa self.init(size:)đó factoryđang gọi.

Vì vậy, chúng ta phải tạo phương thức đó requirednếu chúng ta muốn một phương thức xuất xưởng như thế này và điều đó có nghĩa là nếu lớp của chúng ta thực hiện một phương thức như thế này, chúng ta sẽ có một requiredphương thức khởi tạo và chúng ta sẽ gặp phải những vấn đề chính xác mà bạn gặp phải ở đây với NSCodinggiao thức.


Cuối cùng, tất cả tập trung vào sự hiểu biết cơ bản rằng các trình khởi tạo của Swift chơi theo một bộ quy tắc thừa kế hơi khác một chút, điều đó có nghĩa là bạn không được đảm bảo thừa kế các trình khởi tạo từ siêu lớp của bạn. Điều này xảy ra vì các trình khởi tạo siêu lớp không thể biết về các thuộc tính được lưu trữ mới của bạn và chúng không thể khởi tạo đối tượng của bạn sang trạng thái hợp lệ. Nhưng, vì nhiều lý do, một siêu lớp có thể đánh dấu một trình khởi tạo là required. Khi thực hiện, chúng ta có thể sử dụng một trong những kịch bản rất cụ thể mà theo đó chúng ta thực sự kế thừa requiredphương thức hoặc chúng ta phải tự thực hiện nó.

Điểm chính ở đây là nếu chúng ta gặp lỗi bạn thấy ở đây, điều đó có nghĩa là lớp của bạn không thực sự thực hiện phương thức nào cả.

Vì có lẽ là một ví dụ cuối cùng để đi sâu vào thực tế là các lớp con Swift không luôn kế thừa các initphương thức của cha mẹ chúng (mà tôi nghĩ là hoàn toàn trung tâm để hiểu đầy đủ vấn đề này), hãy xem xét ví dụ này:

class Foo {
    init(a: Int, b: Int, c: Int) {
        // do nothing
    }
}

class Bar: Foo {
    init(string: String) {
        super.init(a: 0, b: 1, c: 2)
        // do more nothing
    }
}

let f = Foo(a: 0, b: 1, c: 2)
let b = Bar(a: 0, b: 1, c: 2)

Điều này không biên dịch.

nhập mô tả hình ảnh ở đây

Thông báo lỗi mà nó đưa ra là một chút sai lệch:

Đối số thêm 'b' trong cuộc gọi

Nhưng điểm được, Barkhông thừa hưởng bất kỳ Foo's initphương pháp bởi vì nó chưa thỏa mãn một trong hai trường hợp đặc biệt cho kế thừa initphương pháp từ lớp cha của nó.

Nếu đây là Objective-C, chúng tôi sẽ thừa hưởng điều đó mà initkhông có vấn đề gì, vì Objective-C hoàn toàn hạnh phúc khi không khởi tạo các thuộc tính của đối tượng (mặc dù là nhà phát triển, bạn không nên hài lòng với điều này). Trong Swift, điều này chỉ đơn giản là không làm được. Bạn không thể có trạng thái không hợp lệ và kế thừa các trình khởi tạo siêu lớp chỉ có thể dẫn đến trạng thái đối tượng không hợp lệ.


Bạn có thể vui lòng giải thích ý nghĩa của câu này hoặc đưa ra một ví dụ? "(và các trình khởi tạo tiện lợi không trỏ đến các trình khởi tạo mà chúng tôi đã triển khai)"
Abbey Jackson

Câu trả lời rực rỡ! Tôi muốn nhiều bài viết SO là về lý do tại sao , như thế này, thay vì chỉ như thế nào .
Alexander Vasenin

56

Tại sao vấn đề này phát sinh? Chà, thực tế đơn giản là nó luôn luôn quan trọng (ví dụ như trong Objective-C, kể từ ngày tôi bắt đầu lập trình lại Cốc Cốc trong Mac OS X 10.0) để đối phó với các trình khởi tạo mà lớp của bạn chưa sẵn sàng để xử lý. Các tài liệu luôn luôn khá rõ ràng về trách nhiệm của bạn trong vấn đề này. Nhưng có bao nhiêu người trong chúng ta bận tâm để hoàn thành chúng, hoàn toàn và gửi thư? Có lẽ không ai trong chúng ta! Và trình biên dịch đã không thực thi chúng; tất cả chỉ là thông thường

Ví dụ, trong lớp con trình điều khiển khung nhìn Objective-C của tôi với trình khởi tạo được chỉ định này:

- (instancetype) initWithCollection: (MPMediaItemCollection*) coll;

... điều quan trọng là chúng ta phải được thông qua một bộ sưu tập vật phẩm truyền thông thực tế: trường hợp đơn giản là không thể tồn tại mà không có một cái nào. Nhưng tôi đã viết không có "nút chặn" để ngăn người khác khởi tạo tôi bằng xương trần init. Tôi nên đã viết một (thực ra, nói một cách chính xác, tôi nên đã viết một triển khai initWithNibName:bundle:, trình khởi tạo được chỉ định kế thừa); nhưng tôi đã quá lười biếng để làm phiền, bởi vì tôi "biết" tôi sẽ không bao giờ khởi tạo không chính xác lớp học của mình theo cách đó. Điều này để lại một lỗ hổng. Trong Objective-C, ai đó có thể gọi xương trần init, để lại những chiếc ngà của tôi chưa được khởi tạo, và chúng tôi đang đi lên lạch mà không cần mái chèo.

Swift, tuyệt vời, cứu tôi khỏi bản thân mình trong hầu hết các trường hợp. Ngay khi tôi dịch ứng dụng này sang Swift, toàn bộ vấn đề đã biến mất. Swift có hiệu quả tạo ra một nút chặn cho tôi! Nếu init(collection:MPMediaItemCollection)là trình khởi tạo được chỉ định duy nhất được khai báo trong lớp của tôi, tôi không thể được khởi tạo bằng cách gọi các bộ xương trần init(). Đó là một phép màu!

Điều xảy ra trong hạt giống 5 chỉ là trình biên dịch đã nhận ra rằng phép màu không hoạt động trong trường hợp init(coder:), bởi vì về lý thuyết, một thể hiện của lớp này có thể đến từ ngòi bút và trình biên dịch không thể ngăn chặn điều đó - và khi tải nib, init(coder:)sẽ được gọi. Vì vậy, trình biên dịch làm cho bạn viết stopper một cách rõ ràng. Và hoàn toàn đúng.


Cảm ơn câu trả lời chi tiết như vậy. Điều này thực sự mang lại ánh sáng vào vấn đề.
Julian Osorio

Một upvote cho pasta12 đã cho tôi biết làm thế nào để trình biên dịch im lặng, nhưng một upvote cho bạn cũng đã theo dõi tôi về những gì nó đã rên rỉ ở nơi đầu tiên.
Garrett Albright

2
Lỗ hổng hay không, tôi sẽ không bao giờ gọi init này, vì vậy việc buộc tôi đưa nó vào là hoàn toàn bất lợi. Mã cồng kềnh là một chi phí mà không ai trong chúng ta cần. Bây giờ nó cũng buộc bạn phải khởi tạo các thuộc tính của mình trong cả hai phần. Vô nghĩa!
Dan Greenfield

5
@DanGreenfield Không, nó không bắt buộc bạn phải khởi tạo bất cứ thứ gì, bởi vì nếu bạn sẽ không bao giờ gọi nó, bạn chỉ cần đặt fatalErrornút chặn được mô tả trong stackoverflow.com/a/25128815/341994 . Chỉ cần biến nó thành Đoạn mã người dùng và từ giờ trở đi, bạn có thể đặt nó ở nơi cần thiết. Mất nửa giây.
mờ

1
@nhgrif Chà, công bằng mà nói, câu hỏi không hỏi về câu chuyện hoàn chỉnh. Đó chỉ là về cách thoát khỏi mứt này và đi tiếp. Câu chuyện đầy đủ được đưa ra trong cuốn sách của tôi: apeth.com/swiftBook/ch04.html#_group_initialulators
matt

33

thêm vào

required init(coder aDecoder: NSCoder!) {
  super.init(coder: aDecoder)
}

3
Điều này không hoạt động, nhưng tôi không nghĩ đó là một lỗi. trình khởi tạo không được kế thừa trong swift (khi trình khởi tạo của riêng bạn được khai báo) và điều này được đánh dấu bằng từ khóa bắt buộc. Vấn đề duy nhất là bây giờ tôi cần khởi tạo TẤT CẢ các thuộc tính của mình trong phương thức này cho mỗi một lớp sẽ bị lãng phí rất nhiều mã vì tôi hoàn toàn không sử dụng mã này. Hoặc tôi sẽ phải khai báo tất cả các thuộc tính của mình dưới dạng các loại tùy chọn hoàn toàn bỏ qua để bỏ qua việc khởi tạo mà tôi cũng không muốn làm.
Byte

1
Vâng Tôi nhận ra ngay sau khi nói nó có thể là một lỗi, rằng nó thực sự có ý nghĩa logic. Tôi đồng ý rằng nó sẽ rất nhiều mã bị lãng phí, vì giống như bạn, tôi sẽ không bao giờ sử dụng phương thức init này. Không chắc chắn về một giải pháp thanh lịch nào
Gagan Singh

2
Tôi gặp vấn đề tương tự. Nó có ý nghĩa với "init init", nhưng swift không phải là ngôn ngữ "dễ dàng" mà tôi hy vọng. Tất cả những "tùy chọn" này đang làm cho ngôn ngữ phức tạp hơn mức yêu cầu. Và không hỗ trợ DSL và AOP. Tôi càng ngày càng thất vọng.
dùng810395

2
Có tôi hoàn toàn đồng ý. Rất nhiều tài sản của tôi hiện được tuyên bố là tùy chọn vì tôi buộc phải thực hiện nó, khi thực sự chúng không được phép là không. Một số là tùy chọn vì chúng hợp pháp nên là tùy chọn (có nghĩa là không phải là giá trị hợp lệ). Và sau đó trong các lớp học mà tôi không phân lớp, tôi không cần sử dụng các tùy chọn, vì vậy mọi thứ trở nên rất phức tạp và dường như tôi không thể tìm thấy một phong cách mã hóa phù hợp. Hy vọng Apple tìm ra một cái gì đó.
Byte

5
Tôi nghĩ rằng họ có nghĩa là bạn có thể đáp ứng trình khởi tạo được yêu cầu bằng cách không khai báo bất kỳ trình khởi tạo nào của riêng bạn, điều này sẽ dẫn đến tất cả các trình khởi tạo được kế thừa.
Epic Byte
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.