2014-09-15 15 views
6

Tôi vẫn gặp sự cố khi hiểu một số sự tinh tế của generics trong Swift. Tôi xác định các loại sau:Loại không tuân theo giao thức

protocol SomeProtocol { 
    func setValue(value: Int) 
} 

class ProtocolLabel : UILabel, SomeProtocol { 
    func setValue(value: Int) { 

    } 
} 

class ProtocolImageView : UIImageView, SomeProtocol { 
    func setValue(value: Int) { 
    } 
} 

viewForValue (2) Bây giờ tôi đã xác định hàm sau. Tôi mong đợi T là UIView tuân thủ giao thức SomeProtocol.

func viewForValue<T where T: SomeProtocol, T: UIView>(param: Int) -> UIView { 
    var someView: T 
    if param > 0 { 
     someView = ProtocolLabel() as T 
    } else { 
     someView = ProtocolImageView() as T 
    } 
    someView.setValue(2) 
    someView.frame = CGRectZero 
    return someView 
} 

Tuy nhiên, tôi nhận ra lỗi biên dịch sau khi tôi thực thi mã:

viewForValue(2) // <-- Type 'UIView' does not conform to protocol 'SomeProtocol' 

Dường như trong mệnh đề mà tôi không thể xác định một lớp học mà không thực hiện các giao thức . Tại sao vậy?

Xin cảm ơn trước.

+1

Bạn có thể thử sử dụng này: Greg

Trả lời

4

viewForValue được cho là trả lại một lớp kế thừa từ UIView và triển khai SomeProtocol. Bạn đã xác định 2 lớp không có mối quan hệ trực tiếp - chúng chỉ thừa kế từ UIView và triển khai SomeProtocol.

Khi hàm phải xác định loại trả về, loại bê tông trực tiếp cả hai lớp kế thừa từ là UIView, do đó, đó là số tiền trả về viewForValue.

Để khắc phục vấn đề này, bạn phải tạo ra một mối quan hệ trực tiếp và cụ thể giữa 2 lớp, bằng cách tạo ra một lớp thứ 3 kế thừa từ UIView và thực hiện SomeProtocol:

protocol SomeProtocol { 
    func setValue(value: Int) 
} 

class SomeClass: UIView, SomeProtocol { 
    func setValue(value: Int) { 

    } 
} 

class SomeSubclass : SomeClass { 
} 

class SomeOtherSubclass : SomeClass { 
} 

func viewForValue<T where T: SomeProtocol, T: SomeClass>(param: Int) -> T { 
    var someView: T 
    if param > 0 { 
     someView = SomeSubclass() as T 
    } else { 
     someView = SomeOtherSubclass() as T 
    } 
    someView.setValue(2) 
    someView.frame = CGRectZero 
    return someView 
} 

viewForValue(2) 

Phụ Lục: đọc OP bình luận bên dưới, mục đích là để tự động khởi tạo các lớp UIKit hiện có kế thừa từ UIView. Vì vậy, giải pháp được đề xuất không áp dụng.

Tôi nghĩ rằng việc mở rộng UIView bằng cách thực hiện SomeProtocolnên công việc:

protocol SomeProtocol { 
    func setValue(value: Int) 
} 

extension UIView : SomeProtocol { 
    func setValue(value: Int) { 
    } 
} 

func viewForValue<T where T: SomeProtocol, T: UIView>(param: Int) -> UIView { 
    var someView: T 
    if param > 0 { 
     someView = UILabel() as T 
    } else { 
     someView = UIImageView() as T 
    } 
    someView.setValue(2) 
    someView.frame = CGRectZero 
    return someView 
} 

nhưng có vẻ như đó là một lỗi biên dịch. Mã này trong sân chơi hiển thị thông báo cho biết rằng:

Giao tiếp với dịch vụ sân chơi bị gián đoạn bất ngờ. Dịch vụ sân chơi "com.apple.dt.Xcode.Playground" có thể đã tạo ra nhật ký sự cố.

trong khi trong một ứng dụng biên soạn iOS thất bại do một lỗi segmentation 11.

+0

Tôi đã cố gắng để được chung chung hơn với câu hỏi của tôi nhưng trong trường hợp của tôi, các lớp có liên quan là các lớp con 'UIView' hiện có:' UILabel', 'UIImageView' vì vậy tôi không thể khiến chúng kế thừa từ' SomeClass'. Tôi sẽ chỉnh sửa để phản ánh điều đó. – Kamchatka

+0

Xem thêm câu trả lời của tôi - Tôi nghĩ giải pháp thứ 2 nên hoạt động, nhưng mã làm cho trình biên dịch bị lỗi ... – Antonio

+0

Điều này rất hữu ích, cảm ơn! – Kamchatka

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