2015-08-31 26 views
1

我想指定一個協議來管理符合另一個協議的某些類型的對象。就像這樣:在Swift中指定協議之間的關係

// Specify protocol 
protocol ElementGenerator { 
    func getElements() -> [Element] 
} 
protocol Element { 
    // ... 
} 

// Implement 
class FooElementGenerator: ElementGenerator { 
    func getElements() -> [FooElement] { 
     // Generate elements here 
     return [FooElement()] 
    } 
} 
class FooElement { 
    // ... 
} 

當試圖編譯此,我得到一個錯誤:

Type 'FooElementGenerator' does not conform to protocol 'ElementGenerator' 

暗示候選人func getElements() -> [FooElement]() -> [FooElement]不匹配類型,而是它預計() -> [Element]

這種錯誤怎麼解決?

UPDATE:

該解決方案似乎是工作:

protocol ElementGenerator { 
    typealias T:Element 

    func getElements() -> [T] 
} 

protocol Element { 
    // ... 
} 


class FooElementGenerator: ElementGenerator { 
    typealias T = FooElement 

    func getElements() -> [T] { 
     return [T()] 
    } 
} 

class FooElement: Element { 
    // ... 
} 

但是當我嘗試創建這樣一個變量:

let a: ElementGenerator = FooElementGenerator() 

出現新的錯誤:

Protocol 'ElementGenerator' can only be used as a generic constraint because it has Self or associated type requirements 

回答

1

實現協議方法時,返回類型必須相同,但可以像這樣返回子類對象;

protocol ElementGenerator { 
    func getElements() -> [Element] 
} 

//@objc for bridging in objective C 
@objc protocol Element { 
    // ... 
} 

// Implement 
class FooElementGenerator: NSObject,ElementGenerator { 

    override init() { 
     super.init(); 
     //-- 
     let fooElements:[FooElement] = self.getElements() as! [FooElement] 
    } 

    func getElements() -> [Element] { 
     // Generate elements here 
     return [FooElement()] 
    } 
} 

class FooElement:NSObject, Element { 
    // ... 
    override init() { 
     super.init(); 
     //-- 
     NSLog("FooElement init"); 
    } 
} 
+0

測試在迅速1.2 – Shoaib

+0

是的,這是解決方案。我想我正在考慮太複雜的事情,所以我錯過了這個簡單的想法。 – ULazdins

0

在第二種情況下,出現錯誤信息,因爲您已經定義ElementGenerator與「關聯類型」,這意味着你只能在給予約束類型使用它。

舉例來說,如果你需要爲通用ElementGenerator值定義的功能,你可以寫這樣的事情:

func f<T1:ElementGenerator>(elemGenerator:T1) -> Element { 
    return elemGenerator.getElements()[0] 
} 

var a : Element = FooElementGenerator() 
var b : Element = BarElementGenerator() 

var x : Element = f(a) 
var y : Element = f(b) 

var z : FooElement = f(a) as! FooElement