2016-05-27 17 views
13

chữ ký ghi đè trọng số trong phần mở rộng dường như tạo ra kết quả không thể đoán trước trong một số trường hợp nhất định. Ví dụ sau minh họa hai kết quả khác nhau với một mẫu tương tự.Chuyển nhanh đến các phương thức ghi đè trong phần mở rộng phân lớp

class A: UIViewController { 
    func doThing() { 
     print("dothing super class") 
    } 

    override func viewDidLoad() { 
     print("viewdidload superclass") 
     super.viewDidLoad() 
    } 
} 

class B: A { } 

extension B { 
    override func doThing() { 
     print("dothing sub class") 
     super.doThing() 
    } 

    override func viewDidLoad() { 
     print("viewdidload subclass") 
     super.viewDidLoad() 
    } 
} 

let a: A = B() 
a.doThing() 

let vc: UIViewController = B() 
vc.viewDidLoad() 

in này:

dothing super class 
viewdidload subclass 
viewdidload superclass 

Bạn có thể thấy điều này bỏ qua việc thực hiện các doThing các 's B khi nó được chọn vào vai A, tuy nhiên bao gồm cả việc triển khai của viewDidLoad khi vào vai UIViewController. Đây có phải là hành vi dự kiến? Nếu vậy, lý do cho việc này là gì?

VIV: Xcode 7.3, Sân chơi

+7

Thử 'dynamic func doThing()' trong lớp cha. – jtbandes

+0

@jtbandes Điều đó tạo ra kết quả mong đợi (ví dụ: các cuộc gọi cả triển khai lớp con và triển khai siêu lớp). Nhưng tôi không rõ ràng về lý do tại sao mà sẽ được yêu cầu và khác với hành vi khi cast vào 'UIViewController'. Các hành vi có khác nhau dựa trên phạm vi mô-đun không? – ahtierney

Trả lời

12

Điều ngạc nhiên ở đây là trình biên dịch cho phép ghi đè trong phần mở rộng. này không biên dịch:

class A { 
    func doThing() { 
     print("dothing super class") 
    } 
} 
class B: A { 
} 
extension B { 
    override func doThing() { // error: declarations in extensions cannot override yet 
     print("dothing sub class") 
     super.doThing() 
    } 
} 

Trong ví dụ của bạn, dường như trình biên dịch cung cấp cho bạn một đường chuyền vì A xuất phát từ NSObject - có lẽ để cho phép lớp này để tương tác với Objective-C. này không biên dịch:

class A : NSObject { 
    func doThing() { 
     print("dothing super class") 
    } 
} 
class B: A { 
} 
extension B { 
    override func doThing() { 
     print("dothing sub class") 
     super.doThing() 
    } 
} 

đoán của tôi là thực tế bạn được phép làm ghi đè này ở tất cả là chính nó có thể là một lỗi. docs nói:

Tiện ích mở rộng có thể thêm chức năng mới vào loại, nhưng không thể ghi đè chức năng hiện có.

Và ghi đè không được liệt kê là một trong những điều tiện ích mở rộng có thể thực hiện. Vì vậy, nó có vẻ như thế này nên không phải biên dịch. Tuy nhiên, có lẽ điều này được cho phép có tính tương thích với Objective-C, như tôi đã nói trước đây. Dù bằng cách nào, chúng tôi sau đó khám phá một trường hợp cạnh, và bạn đã rất độc đáo gợi ra sự sắc sảo của nó.

Cụ thể, mã trước vẫn không làm cho công văn động hoạt động. Đó là lý do tại sao bạn phải khai báo doThingdynamic, như được gợi ý bởi @jtbandes, hoặc đặt nó trong lớp thực tế thay vì phần mở rộng - nếu bạn muốn đa hình hoạt động. Như vậy, điều này hoạt động theo cách bạn mong đợi:

class A : NSObject { 
    dynamic func doThing() { 
     print("dothing super class") 
    } 
} 
class B: A { 
} 
extension B { 
    override func doThing() { 
     print("dothing sub class") 
     super.doThing() 
    } 
} 

Và như vậy thực hiện điều này:

class A : NSObject { 
    func doThing() { 
     print("dothing super class") 
    } 
} 
class B: A { 
    override func doThing() { 
     print("dothing sub class") 
     super.doThing() 
    } 
} 

Kết luận của tôi sẽ là: Very nice dụ; gửi cho Apple như một lỗi có thể xảy ra; và đừng làm điều đó. Làm trọng tâm của bạn trong lớp học, không phải trong phần mở rộng.

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