2015-06-24 71 views
9

我有以下情形:映射及其中用於循環

protocol A {} 
protocol B: A {} 
protocol C: A {} 

let objects: [A] = ... 

我如何遍歷數組,僅是B類型的對象執行的邏輯?

現在,我在做這樣的事情:

for object in objects { 
    if let b = object as? B { 
     ... 
    } 
} 

但我在想,如果我可以使用where,使這個更具表現力和優雅。

for b in objects where b is B // <- compiles, but b is typed as A, not B 
for b: B in objects where b is B // <- doesn't compile 
for b in objects as! [B] where b is B // <- I get a warning that "is" will always be true 

回答

8

還有for case(幾乎相同caseswitch語句),所以它看起來是這樣的:

for case let b as B in objects { 
    // use b which is now of type B 
} 

另外一個不錯的表達式爲:

for case let b as protocol<B, C> in objects { 
    // use b which is now of type protocol<B, C> 
} 

所以你可以使用的方法,性質等等

0

我不是100%肯定,這會回答你的情況 - 因爲你有類似的東西 - 而且我不完全瞭解你不喜歡你的版本。然而這部作品在斯威夫特2:

for object in objectArray where object is protocolB { 
    //print(object) // only objects conforming to protocolB 
} 

這裏是我的聲明:

var objectArray: [AnyObject] = [] 
// contains a mix of objects of the following 3 classes 


class class01: protocolA { 
} 
class class02: protocolA, protocolB { 
    func test() -> String { 
    // required to conform to protocolB 
    return "hello" 
    } 
} 
class class03: protocolA, protocolB, protocolC { 
    func test() -> String { 
    // required to conform to protocolB 
    return "hello" 
    } 
} 

protocol protocolA { 
} 
protocol protocolB: protocolA { 
    func test() -> String 
} 
protocol protocolC: protocolA { 
} 

編譯,而B的類型爲A,不是B

那是位我不不明白。很可能是因爲我愚蠢。但是我正在閱讀的這種方式,您的protocolB對象也符合protocolA的定義。我已經定義了我的一樣。

+0

如果'protocolB'會定義一個函數'test()',那麼在迭代中你不能在'object'上調用它,因爲'object'是類型的''object''到'protocolB' 'AnyObject',不是'protocolB'類型。 – rid

+0

在更新的代碼中,如果您嘗試在您評論的循環中調用print(object.test())',將會出現錯誤('AnyObject'沒有名爲'test()'的成員)。 – rid

+0

它在Xcode7中絕對正常。包括'print(object)'。這只是評論,因爲它是一個例如 – simons

2

as? subtype及其變異ts是代碼味道。這裏的其他答案將幫助您完成您想要的任務,但我想建議您將此邏輯從for循環移至協議(如果可能的話)。

例如,考慮Shape協議:

protocol Shape { 
    func draw() 
    func executeSomeSpecialOperation() 
} 

extension Shape { 
    func executeSomeSpecialOperation() { 
     // do nothing by default 
    } 
} 

創建符合了三份形狀類型:

struct Circle : Shape { 
    func draw() { 
     // drawing code goes here 
    } 
} 

struct Diamond : Shape { 
    func draw() { 
     // drawing code goes here 
    } 
} 

struct Pentagon : Shape { 
    func draw() { 
     // drawing code goes here 
    } 

    func executeSomeSpecialOperation() { 
     print("I'm a pentagon!") 
    } 
} 

如你所知,你可以創建形狀的數組:

let shapes : [Shape] = [Circle(), Diamond(), Pentagon()] 

這種方法可以讓您在不知道類型的情況下遍歷這個數組:

for shape in shapes { 
    shape.draw() 
    shape.executeSomeSpecialOperation() 
} 

這有兩個好處:

  • 降低耦合(您運行for循環方法並不需要知道Pentagon是什麼)
  • 提高凝聚力(相關Pentagon邏輯包含在該類型的定義中)

我不確定這是否適用於您的特定用例,但是第I墨水通常是更好的模式。

+0

這假定該方法對所有「形狀」都有意義。例如,如果你想計算'shapes'數組中所有圓的平均半徑,你會做什麼? – rid

+0

如果我需要執行依賴同質性的操作,我不會在數組中存儲異構類型。例如,你可以有一個單獨的'circles'數組,並且使'shapes'成爲一個計算屬性。 –

+0

那麼每次你需要一個所有形狀的列表,一個新的數組將被實例化? – rid