'Removing an item from a loop in Swift
Pretty straightforward question. I am having trouble removing a specific item from a for loop in Swift. I am showing different webviews in a scrollview(each webview being a different slide) with the urls coming from Firebase. This code works great but if a url is not available I want to be able to remove that website(slide) so it is not just a blank frame. If there is an easier and less complicated way of doing this please let me know.
func loadWebsites() -> [Website] {
let url1 = URL(string: "\(nikeWebsite)")
let request1 = URLRequest(url: url1!)
let url2 = URL(string: "\(finishlineWebsite)")
let request2 = URLRequest(url: url2!)
let url3 = URL(string: "\(eastbayWebsite)")
let request3 = URLRequest(url: url3!)
let url4 = URL(string: "\(footlockerWebsite)")
let request4 = URLRequest(url: url4!)
let url5 = URL(string: "\(footactionWebsite)")
let request5 = URLRequest(url: url5!)
let url6 = URL(string: "\(champsWebsite)")
let request6 = URLRequest(url: url6!)
let website1:Website = Bundle.main.loadNibNamed("Website", owner: self, options: nil)?.first as! Website
website1.webView.load(request1)
website1.webView.navigationDelegate = self
let website2:Website = Bundle.main.loadNibNamed("Website", owner: self, options: nil)?.first as! Website
website2.webView.load(request2)
website2.webView.navigationDelegate = self
let website3:Website = Bundle.main.loadNibNamed("Website", owner: self, options: nil)?.first as! Website
website3.webView.load(request3)
website3.webView.navigationDelegate = self
let website4:Website = Bundle.main.loadNibNamed("Website", owner: self, options: nil)?.first as! Website
website4.webView.load(request4)
website4.webView.navigationDelegate = self
let website5:Website = Bundle.main.loadNibNamed("Website", owner: self, options: nil)?.first as! Website
website5.webView.load(request5)
website5.webView.navigationDelegate = self
let website6:Website = Bundle.main.loadNibNamed("Website", owner: self, options: nil)?.first as! Website
website6.webView.load(request6)
website6.webView.navigationDelegate = self
return [website1, website2, website3, website4, website5, website6]
}
func setupWebsiteScrollView(websites : [Website]) {
scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(websites.count), height: view.frame.height)
scrollView.isPagingEnabled = false
scrollView.isScrollEnabled = false
scrollView.contentInsetAdjustmentBehavior = .never
for i in 0 ..< websites.count {
websites[i].frame = CGRect(x: view.frame.width * CGFloat(i), y: 0, width: view.frame.width, height: view.frame.height)
scrollView.addSubview(websites[i])
//It would be an if statement that initially trigger the code I'm looking for
if nikeWebsite == nil {
websites.remove(at: 0)
}
}
Getting this error message.
Cannot use mutating member on immutable value: 'websites' is a 'let' constant
Solution 1:[1]
Your code doesn't make any sense on a couple of levels.
First problem:
This code:
func foo() {
var array = ["a", "b", "c", "d", "e", "f"]
for index in 0..<array.count {
let item = array[index]
print("Item \(item)")
array.remove(at: index)
}
}
Will crash.
The range of the for loop is generated at the beginning, before the for loop is executed. Since there are 6 items in the array, the for loop will iterate through a range from 0 to 5.
- On the first pass through, we print the first item, "a".
- Then we remove the item at index 0.
- Next, we increment index, and fetch the item at index 1.
- Now, since we've removed "a", we fetch "c".
- Then we remove "c" from the array.
- We increment index to 2. Index 2 now contains "e", which we print, then remove from the array.
- The array now only contains 3 items. We increment index to 3, and try to fetch the item at index 3. However, that is out of range, so we crash.
You can't remove items from an array as you index through it. You'd have to loop through it backwards.
Next problem: You are passing the array in as a function parameter. Arrays are passed by value, so the parameter is a let constant. You can't modify the array.
You could solve both of those problems by looping through the array backwards, and making the array an inout parameter, but why?
func foo(_ array: inout [String]) {
for index in (0..<array.count).reversed() {
let item = array[index]
print("Item \(item)")
array.remove(at: index)
}
}
Why do you need to remove each item from the array as it's processed?
Edit:
Instead, I would suggest a function that returns a copy of the array with the discarded items removed. The filter function does exactly that.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
