Reputation: 4363
I have an array of colors, that I want to apply to uitableviewcells
in iOS.
let colorPalet = [
UIColor(red: 255.0/255.0, green: 159.0/255.0, blue: 112.0/255.0, alpha: 1),
UIColor(red: 81.0/255.0, green: 218.0/255.0, blue: 168.0/255.0, alpha: 1),
UIColor(red: 2.0/255.0, green: 207.0/255.0, blue: 255.0/255.0, alpha: 1),
UIColor(red: 144.0/255.0, green: 153.0/255.0, blue: 166.0/255.0, alpha: 1)
]
cell.backgroundColor = colorPalet[indexPath.row]
The problem is, then when indexPath.row
is greater then the colorPalet array, it will crash, because there is no more entries in the array. How to start iteratie again through the array if it is at the end of the array in Swift?
Upvotes: 0
Views: 1001
Reputation: 73186
The accepted answer already covers the specific situation of the OP (cell colors in a table view), whereas this answer will approach the more general question title:
How to loop through array and start again if the array is at the end?
The modulo operation naturally comes to mind,
truncatedIndex = runningIndexDividend % divisor
But what if we're to use this in a long running application, where the runningIndexDividend
needlessly increase to values much larger than the divisor
(possibly, in a theoretic contrived situation, even leading to integer overflow ...)? For such a case, an alternative, mainly to tap into the Sequence
neatness of Swift, is to use an on-the-fly generating sequence: one which lazily constructs its next element upon demand.
sequence(state:next:)
functionFor the case of constructing a (infinite) sequence which repeatedly traverses a given array ("joining" the head with the tail), you could make use of the global sequence(state:next:)
function.
E.g., applied to your example (here storing the colorPalet
as a static member of ColorSettings
utility class, just know the possible non-thread safety if using static properties in threaded applications):
class ColorSettings {
private static let colorPalet = [
UIColor(red: 255.0/255.0, green: 159.0/255.0, blue: 112.0/255.0, alpha: 1),
UIColor(red: 81.0/255.0, green: 218.0/255.0, blue: 168.0/255.0, alpha: 1),
UIColor(red: 2.0/255.0, green: 207.0/255.0, blue: 255.0/255.0, alpha: 1),
UIColor(red: 144.0/255.0, green: 153.0/255.0, blue: 166.0/255.0, alpha: 1)
]
static let colorSequence = sequence(
state: 1,
next: { (idx: inout Int) -> UIColor? in
guard colorPalet.count > 0 else { return nil }
defer { idx == colorPalet.count ? (idx = 1) : (idx += 1) }
/* alternatively (loose clarity/semantics to gain brevity)
defer { idx = idx % colorPalet.count + 1 } */
return colorPalet[idx-1]
})
}
Example "usage" (not really intended for this application)
// example usage
let numberOfRowsInSection = 7
for (row, color) in zip(0..<numberOfRowsInSection,
ColorSettings.colorSequence) {
// ...
print(row, color)
} /* 0 UIExtendedSRGBColorSpace 1 0.623529 0.439216 1
1 UIExtendedSRGBColorSpace 0.317647 0.854902 0.658824 1
2 UIExtendedSRGBColorSpace 0.00784314 0.811765 1 1
3 UIExtendedSRGBColorSpace 0.564706 0.6 0.65098 1
4 UIExtendedSRGBColorSpace 1 0.623529 0.439216 1
5 UIExtendedSRGBColorSpace 0.317647 0.854902 0.658824 1
6 UIExtendedSRGBColorSpace 0.00784314 0.811765 1 1 */
Note that the state will not be saved between two separate traversals of colorSequence
. I.e., if copying the loop above and applying elsewhere, the first state will always correspond to the first color.
Also beware that when constructing an infinitely generating sequence as the one above, the sequence can naturally not terminate by itself (no nil
return, apart from the empty colorPalet
array case). Hence its practical use will mostly be in conjunction with a finite sequence with use of zip
as above.
AnyIterator
If you'd rather keep the end state in one traversal as a starting point for the subsequent one (not resetting it, as above), you could use an approach similar to the one above, but using a help state
property combined with AnyIterator
:
class ColorSettings {
private static let colorPalet = [
UIColor(red: 255.0/255.0, green: 159.0/255.0, blue: 112.0/255.0, alpha: 1),
UIColor(red: 81.0/255.0, green: 218.0/255.0, blue: 168.0/255.0, alpha: 1),
UIColor(red: 2.0/255.0, green: 207.0/255.0, blue: 255.0/255.0, alpha: 1),
UIColor(red: 144.0/255.0, green: 153.0/255.0, blue: 166.0/255.0, alpha: 1)
]
private static var idx: Int = 1
static let colorIterator: AnyIterator<UIColor> = AnyIterator {
guard colorPalet.count > 0 else { return nil }
defer { idx == colorPalet.count ? (idx = 1) : (idx += 1) }
return colorPalet[idx-1]
}
}
Example usage:
// first traversal
for (i, color) in zip(0..<2, ColorSettings.colorIterator) {
// ...
print(i, color)
} /* 0 UIExtendedSRGBColorSpace 1 0.623529 0.439216 1
1 UIExtendedSRGBColorSpace 0.317647 0.854902 0.658824 1 */
// state from previous traversal will be used
// to decide starting state here, in next
for (i, color) in zip(0..<4, ColorSettings.colorIterator) {
// ...
print(i, color)
} /* 0 UIExtendedSRGBColorSpace 0.00784314 0.811765 1 1
1 UIExtendedSRGBColorSpace 0.564706 0.6 0.65098 1
2 UIExtendedSRGBColorSpace 1 0.623529 0.439216 1
3 UIExtendedSRGBColorSpace 0.317647 0.854902 0.658824 1 */
Upvotes: 0
Reputation: 131426
Make colorPalet an instance variable. You can just move the code below to the top of the class:
let colorPalet = [
UIColor(red: 255.0/255.0, green: 159.0/255.0, blue: 112.0/255.0, alpha: 1),
UIColor(red: 81.0/255.0, green: 218.0/255.0, blue: 168.0/255.0, alpha: 1),
UIColor(red: 2.0/255.0, green: 207.0/255.0, blue: 255.0/255.0, alpha: 1),
UIColor(red: 144.0/255.0, green: 153.0/255.0, blue: 166.0/255.0, alpha: 1)
]
That way you're not creating an array of colors for each cell you configure. Then use the modulo (`%) Code in ROC's answer:
cell.backgroudColor = colorPalet[indexPath.row % colorPalet.count]
Upvotes: 1
Reputation: 78
you can use modulo:
cell.backgroudColor = colorPalet[indexPath.row % colorPalet.count]
Upvotes: 5
Reputation: 2187
You can use something like this:
let index = indexPath.row%4
cell.something = colorPalet[index]
Upvotes: 0
Reputation: 588
for index in 0..array.count {
//Do stuff here
if (index == array.count -1)
{
index = 0
}
}
Upvotes: 0