I have the following scenario:
protocol A {}
protocol B: A {}
protocol C: A {}
let objects: [A] = ...
How can I loop through the array and only execute logic for the objects that are of type B
?
Right now, I'm doing something like this:
for object in objects {
if let b = object as? B {
...
}
}
But I was wondering if I can use where
to make this more expressive and elegant.
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
There is also for case
(almost the same case
as in switch
statements) so it would look like this:
for case let b as B in objects {
// use b which is now of type B
}
Another nice expression is:
for case let b as protocol<B, C> in objects {
// use b which is now of type protocol<B, C>
}
so you can use methods, properties and so on from both protocols at the same time
as? subtype
and its variants are a code smell. The other answers here will help you accomplish what you want, but I wanted to suggest that you move this logic from the for
loop to the protocol (if it's possible).
For example, consider a Shape
protocol:
protocol Shape {
func draw()
func executeSomeSpecialOperation()
}
extension Shape {
func executeSomeSpecialOperation() {
// do nothing by default
}
}
Create three shape types that conform to it:
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!")
}
}
As you know, you can create an array of shapes:
let shapes : [Shape] = [Circle(), Diamond(), Pentagon()]
This approach lets you loop through this array without knowing their type:
for shape in shapes {
shape.draw()
shape.executeSomeSpecialOperation()
}
This has two benefits:
for
loop doesn't need to know what a Pentagon
is)Pentagon
is contained within that type's definition)I don't know for sure that this will work for your specific use case, but I think it's a better pattern generally.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With