How to write a non-C-like for-loop in Swift 2.2+?
Worst case, you can convert it to a while loop.
var i = 0
var j = 1
while i <= array.count -2 && j <= array.count - 1 {
// something
i += 1
j += 1
}
-- EDIT --
Because you said, "while loop is preferable universal substitution for all cases more complicated than the simple example of C-like for-loop"... I feel the need to expand on my answer. I don't want to be responsible for a bunch of bad code...
In most cases, there is a simple for-in loop that can handle the situation:
for item in array {
// do something with item
}
for (item1, item2) in zip(array, array[1 ..< array.count]) {
// do something with item1 and item2
}
for (index, item1) in array.enumerate() {
for item2 in array[index + 1 ..< array.count] {
// do soemthing with item1 and item2
}
}
For your last case, you might be justified using a for look, but that is an extremely rare edge case.
Don't litter your code with for loops.
Fix warning C-style for Statement is deprecated in Swift 3
C-style for
loop has been deprecated in Swift 3. You can continue using it for a while, but they will certainly disappear in the future.
You can rewrite your loop to Swift's style:
for i in 0..<len {
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.characterAtIndex(Int(rand)))
}
Since you don't use i
at all in the loop's body, you can replace it with:
for _ in 0..<len {
// do stuffs
}
Alternative for Swift C-style loop when iterator was changed conditionally within the loop
The iterator variable declared in a for
loop is scoped to a single pass through that loop, so if you want to change it across multiple passes through the loop you'll need to use a while
loop instead.
Also, since your intention seems to be "increment the loop counter only if checkCondition()
is false" you can do that more clearly with a single, conditional increment, instead of using a decrement to undo your increment. Here are a couple of examples of that:
var i = 1
while i <= 10 {
if !checkCondition() {
i += 1
}
}
var j = 1
while j <= 10 {
j = checkCondition() ? j : j + 1
}
And a one that's maybe a little silly, but might come in handy if you do this sort of thing a lot:
extension IntegerType {
mutating func incrementIf(@autoclosure condition: () -> Bool) {
if condition() {
self = self + 1
}
}
}
var k = 1
while k <= 10 {
k.incrementIf(!checkCondition())
}
Of course, there's the further question of whether you want to be following this counter-based pattern at all (as @Sulthan notes in comments). Part of why Swift is doing away with the C-style for loop is that many loops with a counter are actually using that counter to index a collection, which is a pattern better served by collection iteration. So you might instead do something like:
for item in collection {
process(item)
if item.needsMoreProcessing {
process(item) // some more
}
}
for item in collection {
while item.needsProcessing {
process(item)
}
}
If something like this is what your loop is actually doing, writing it this way makes your purpose much more clear to other readers of your code (including your future self).
How to replace a complicated C-style for loop in Swift 2.2
The simplest solution is to just use a while
loop:
Replace this code:
if bitsToWalk > 0 {
// Walk significant bits by shifting right until all bits are equal to 0.
for var bitsLeft = bitsToWalk; bitsLeft > 0; bitsLeft >>= 1 {
significantBitCount += 1
}
}
With the following while
loop:
while bitsToWalk > 0 {
significantBitCount += 1
bitsToWalk >>= 1
}
Replace c style for-loop in Swift 2.2.1
Try this:
var i = column - 1
while i >= 0 && burgers[i, row]?.burgerType == burgerType {
i -= 1
horzLength += 1
}
This sort of abuse of the for
loop syntax was the exact reason it was deprecated in Swift 2.2. Even if a for
syntax was available, this would still be more clear than that abomination
What are the advantages Swift deprecates C-style for statement?
For details, see Swift Evolution - Remove C style for-loops
To quote the reasoning:
- Both
for-in
andstride
provide equivalent behavior using Swift-coherent approaches without being tied to legacy terminology.- There is a distinct expressive disadvantage in using for-loops compared to for-in in succinctness
for-loop
implementations do not lend themselves to use with collections and other core Swift types.- The
for-loop
encourages use of unary incrementors and decrementors, which will be soon removed from the language.- The semi-colon delimited declaration offers a steep learning curve from users arriving from non C-like languages
- If the for-loop did not exist, I doubt it would be considered for inclusion in Swift 3.
In summary: there are better ways (more expressive) than a C-style for-loop
to iterate in Swift.
Some examples:
for-in
over a range:
for i in 0 ..< 10 {
//iterate over 0..9
print("Index: \(i)")
}
for i in (0 ..< 10).reverse() {
//iterate over 9..0
print("Index: \(i)")
}
For arrays (and other sequences) we have many options (the following is not a complete list):
let array = ["item1", "item2", "item3"]
array.forEach {
// iterate over items
print("Item: \($0)")
}
array.reverse().forEach {
// iterate over items in reverse order
print("Item: \($0)")
}
array.enumerate().forEach {
// iterate over items with indices
print("Item: \($1) at index \($0)")
}
array.enumerate().reverse().forEach {
// iterate over items with indices in reverse order
print("Item: \($1) at index \($0)")
}
for index in array.indices {
// iterate using a list of indices
let item = array[index]
print("Item \(item) at index: \(index)")
}
Also note that if you are converting an array to another array, almost always you want to use array.filter
or array.map
or a combination of them.
For all Strideable
types we can use the stride
method to generate indices, for example:
for index in 10.stride(to: 30, by: 5) {
// 10, 15, 20, 25 (not 30)
print("Index: \(index)")
}
for index in 10.stride(through: 30, by: 5) {
// 10, 15, 20, 25, 30
print("Index: \(index)")
}
With arrays we can do:
for index in 0.stride(to: array.count, by: 2) {
// prints only every second item
let item = array[index]
print("Item \(item) at index: \(index)")
}
#warning: C-style for statement is deprecated and will be removed in a future version of Swift
Removing for init; comparison; increment {}
and also remove ++
and --
easily. and use Swift's pretty for-in loop
// WARNING: C-style for statement is deprecated and will be removed in a future version of Swift
for var i = 1; i <= 10; i += 1 {
print("I'm number \(i)")
}
Swift 2.2:
// new swift style works well
for i in 1...10 {
print("I'm number \(i)")
}
For decrement index
for index in 10.stride(to: 0, by: -1) {
print(index)
}
Or you can use reverse()
like
for index in (0 ..< 10).reverse() { ... }
for float type (there is no need to define any types to index)
for index in 0.stride(to: 0.6, by: 0.1) {
print(index) //0.0 ,0.1, 0.2,0.3,0.4,0.5
}
Swift 3.0:
From Swift3.0
, The stride(to:by:)
method on Strideable has been replaced with a free function, stride(from:to:by:)
for i in stride(from: 0, to: 10, by: 1){
print(i)
}
For decrement index in Swift 3.0
, you can use reversed()
for i in (0 ..< 5).reversed() {
print(i) // 4,3,2,1,0
}
Other then for each
and stride()
, you can use While Loops
var i = 0
while i < 10 {
i += 1
print(i)
}
Repeat-While Loop:
var a = 0
repeat {
a += 1
print(a)
} while a < 10
check out Control flows in The Swift Programming Language Guide
Replacement for C-style loop in Swift 2.2
Although it's not as "pretty", you can use stride
:
for var i in 0.stride(to: -1, by: -1) {
print(i)
}
Converting a C-style for loop that uses division for the step to Swift 3
MartinR's solution is very generic and useful and should be part of your toolbox.
Another approach is to rephrase what you want: the powers of two from 7 down to 0.
for i in (0...7).reversed().map({ 1 << $0 }) {
print(i)
}
Related Topics
Is There a Neat Way to Represent a Fraction as an Attributed String
How to Pass Arguments into a Function with Completion Swift
Swift - Pass JSON Data to Other Views
Why Won't My Collection View Cells Display in the iPhone Simulator
How to Use Core Data Value from Picker? #Swiftui #Coredata
With Data (Not Nsdata), in Fact How Actually Do You Make a Utf8 Version of a Jpeg
Swift: Download Image from Internet and Cache Them Doesn't Work Properly. Need Suggestions
Swiftui How to Invoke the Function and Change View from Other Page
Access Enum Associated Value as Optional
Realm Error Domain=Io.Realm.Unknown Code=89 "Operation Canceled"
Example for Drag and Drop Inside Nscollectionview
Sending Variables with a Segue
Swift - Protocol as Type as Target of Button Action
Swift Generics and Protocols Not Working on Uikit [Possible Bug]
Runaction on Sknode Does Not Complete
Could Not Cast Value of Type Uiview to [Customview] Using Xib
How to Properly Test Against Certain Values in Nseventmodifierflags via Swift