2016-05-15 21 views
18

Giả sử bạn cóđèo trong một loại để một phần mở rộng Swift chung chung, hoặc lý tưởng suy ra nó

class Fancy:UIView 

bạn muốn tìm tất cả anh chị em Fancy quan điểm. No problem ...

for v:UIView in superview!.subviews 
     { 
     if let f = v as? Fancy 
      { f.hungry = false } 
     } 

Vì vậy, hãy thử một phần mở rộng,

public extension UIView 
    { 
    internal func fancySiblings()->([Fancy]) 
     { 
      return (self.superview! 
       .subviews 
       .filter { $0 != self } 
       .flatMap { $0 as? Fancy } 
       ) 
     } 
    } 

Awesome, bạn có thể bây giờ

for f:Fancy in self.fancySiblings() 
     { f.hungry = false } 

Fantastic.

Nhưng,

Làm cách nào để khái quát hóa tiện ích mở rộng đó hoạt động với bất kỳ loại phụ UIView nào?

Lý tưởng nhất, tiện ích mở rộng có suy ra loại không? Cũng như dùng một loại?

Vì vậy, một cái gì đó giống như ...

public extension UIView 
    { 
    internal func siblings<T>(something T)->([T]) 
     { 
      return (self.superview! 
       .subviews 
       .filter { $0 != self } 
       .flatMap { $0 as? T } 
       ) 
     } 

và sau đó bạn có thể gọi nó là một cái gì đó như thế này ...

for f in self.siblings(Fancy) 
    for p in self.siblings(Prancy) 
    for b in self.siblings(UIButton) 

Làm thế nào bạn có thể "nói" một phần mở rộng chung loại sử dụng , như thế à ??

Dường như bạn có thể "suy ra nó ngược",

public extension UIView 
    { 
    internal func incredible<T>()->([T]) 
     { 
     return (self.superview! 
     .subviews 
     .filter { $0 != self } 
     .flatMap { $0 as? T } 
     ) 
     } 


    for f:Fancy in self.incredible() 

    for p:Prancy in self.incredible() 

Đó là tuyệt vời nhưng không hoạt động theo cách khác.

Bạn thậm chí có thể ...

self.siblings().forEach{ 
     (f:Fancy) in 
     d.hasRingOn = false 
     } 

Vì vậy, tôi sẽ vẫn muốn biết làm thế nào để "vượt qua trong" một loại cái gì đó như for f in self.siblings(Fancy) và lý tưởng, thậm chí suy ra nó cũng có.

+0

Câu hỏi tương tự: http://stackoverflow.com/questions/37216240/generic-function-taking-a-type-name-in-swift (Nếu bạn không nghĩ câu trả lời cho câu hỏi của bạn, điều đó không sao - nhưng đó là cùng một vấn đề cơ bản). – Hamish

Trả lời

18

Đơn giản chỉ cần sử dụng .Type:

internal func siblings<T>(something : T.Type)->([T]) { 
    ... 
} 

Sau đó for f in self.siblings(Fancy) nên làm việc một cách chính xác như mong đợi.

Full dụ làm việc:

class Fancy : UIView {} 

public extension UIView { 
    internal func siblings<T>(_ : T.Type)->([T]) { 
     return (self.superview! 
      .subviews 
      .filter { $0 != self } 
      .flatMap { $0 as? T } 
     ) 
    } 
} 

let superView = UIView() 
let view = UIView() 
superView.addSubview(view) 
superView.addSubview(UIView()) 
superView.addSubview(Fancy()) 

print(view.siblings(Fancy)) 

đúng kết quả đầu ra một Fancy xem!


Để giải quyết yêu cầu bổ sung cho tùy chọn sử dụng tham số loại rõ ràng hoặc có hiệu lực của suy luận kiểu của trình biên dịch.Bạn có thể tạo một phương pháp thứ hai trong phần mở rộng cùng

internal func siblings<T>()->([T]) { 
    return siblings(T) 
} 

Bằng cách đó cung cấp một tham số kiểu tường minh gọi một phương pháp, bỏ qua nó sẽ yêu cầu bạn phải làm cho nó kết luận và sẽ gọi hàm thứ hai mà trong điều kiện gọi là người đầu tiên trong nội bộ.


Hoặc, bạn có thể sử dụng nhiều Swifty cách và đưa ra lập luận kiểu tường minh một tùy chọn với mặc định nil. Đó, đáng chú ý, sẽ buộc các suy luận trong trường hợp bỏ qua các đối số kiểu:

// power extension, it provides both infered or stated typing 
internal func siblings<T>(_ : T.Type? = nil) -> ([T]) { 
    return (self.superview! 
     .subviews 
     .filter { $0 != self } 
     .flatMap { $0 as? T } 
     ) 
} 

mà sẽ cho phép bạn gọi phương thức hoặc thông qua

for f in self.siblings(Fancy) 

hoặc thậm chí

for f : Fancy in self.siblings() 

Cả sẽ hoạt động trong khi vẫn chỉ xác định một hàm.

+0

@ JoeBlow có bạn thực sự có thể. Tôi chỉ không muốn thay đổi nhiều mã hơn mức cần thiết;) – luk2302

+2

@JoeBlow Bạn có thể đặt đối số kiểu là tùy chọn, với giá trị mặc định là 'nil' (' _: T.Type? = Nil'). Điều đó sẽ cho phép bạn gọi phương thức có hoặc không có một loại. Việc suy luận chuẩn sẽ hoạt động như bình thường. – Hamish

+0

@Fun thực tế: mà chỉ bị rơi xcode của tôi ... – luk2302

2

câu trả lời tương tự với những gì đang được nói trước đó, nhưng một chút sắp xếp hợp lý hơn và mà không cần phải thông qua bất cứ điều gì hoặc lặp qua các subviews nhiều hơn một lần:

extension UIView { 
    internal func siblings<T: UIView>() -> [T] { 
     return superview?.subviews.flatMap {return ($0 == self) ? nil : ($0 as? T) } ?? [] 
    } 
} 

hoặc ưu tiên sử dụng tôi optionals:

internal func siblings<T: UIView>() -> [T]? { 
     return superview?.subviews.flatMap {return ($0 == self) ? nil : $0 as? T } 
} 

Ví dụ cách sử dụng:

class ExampleView: UIView { 

    func getMatchingSiblings(){ 
     let foundSiblings: [ExampleView] = siblings() 
    } 

    //or with the for loop in the question: 
    for item: ExampleView in siblings() { 

    } 
} 

Khi xử lý chung, bạn chỉ cần một thể hiện của kiểu generic trong chữ ký của phương thức. Vì vậy, nếu bạn có tham số hoặc loại trả về sử dụng thông số chung, bạn không cần phải chuyển loại.

+0

rất đẹp .......... – Fattie

+0

Cũng cực kỳ thông tin. Tôi đã nhấp vào một tiền thưởng cho câu trả lời này * cũng * - cảm ơn tất cả! – Fattie

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