"Cannot assign to" error iterating through array of struct - ios

I have an array of structs:
struct CalendarDate {
var date: NSDate?
var selected = false
}
private var collectionData = [CalendarDate]()
Which I simply populate with a date like this:
for _ in 1...7 {
collectionData.append(CalendarDate(date: NSDate(), selected: false))
}
So when you tap on a collectionView, I simply want to loop through the data and mark them all as False.
for c in collectionData {
c.selected = false ///ERROR: Cannot assign to 'selected' in 'c'
}
Why do I get this error?
If I do this, it works fine but I want to know what I did wrong above:
for i in 0..<collectionData.count {
collectionData[i].selected = false
}

As I understand it, the iterator
for c in collectionData
returns copies of the items in collectionData - (structs are value types, not reference types, see http://www.objc.io/issue-16/swift-classes-vs-structs.html), whereas the iteration
for i in 0..<collectionData.count
accesses the actual values. If I am right in that, it is pointless to assign to the c returned from the iterator... it does not "point" at the original value, whereas the
collectionData[i].selected = false
in the iteration is the original value.
Some of the other commentators suggested
for (var c) in collectionData
but although this allows you to assign to c, it is still a copy, not a pointer to the original, and though you can modify c, collectionData remains untouched.
The answer is either A) use the iteration as you originally noted or B) change the data type to a class, rather than a struct.

because each 'c' is by default let, and this is a new instance of CalendarDate and the value of array at index copied to this for each step of for, and 'c' isn't pointer to the index of the array and it is just a copy of index, so if you set a new value to this, the new value does not apply in array.
but 'i' is used as index of array and can directly manipulate the values of array.

If you are using structs they are copies in the array. So even changing them only changes the copy, not an actual object in the array.
You have to make them a variable in the loop to be editable copy, and reassign them into the array right back.
If they are classes and not structs, than you don't have to reassign part, just do the var thing.
for (index, var c) in collectionData.enumerated() {
c.selected = false
collectionData[index] = c
}

Related

Appending items to an array in dictionary not working

I have this static dictionary created as so:
static var pictures = Dictionary<Int, Array<UIImage>>()
I want to populate it with images. At the moment when I am creating it I don't know how many key/value pairs I need to create. I have to fetch from the internet the data, but after that I am doing this to populate, but still my dictionary is empty:
for i in 0...Fetching.numberOfAliveListings - 1 {
for _ in 0...AdsCollectionView.listings[i].photos.count - 1 {
AdsCollectionView.pictures[i]?.append(UIImage(named: "noimage")!)
}
}
pictures is initially empty. So any attempt to access a value for a given key will result in a nil value. Since the value (the array) is nil, the optional chaining skips the call to append.
One solution is to provide a default array when looking up the value for a given Int.
AdsCollectionView.pictures[i, default: []].append(UIImage(named: "noimage")!)
You may also wish to consider alternate syntax when declaring pictures:
static var pictures = [Int: [UIImage]]()

Trying to append text to a property inside a loop in Swift

I have an array of struct objects. These objects have a property for title (which is a String), and a property for location (of type Location).
What I would like to is append a double value for distance derived from the location property and the distance function with another, existing Location object, to the title property. Here is the code I am working with:
self.myList.map({$0.title.append("\($0.location.distance(from: location!)/1000)")})
The problem here is that the map function returns a new array, however, I need to make the change to the existing array, since I'm using this array as the datasource for my UITableView. The other problem is that despite me making the title property a var, I am always told the following error message:
Cannot use mutating member on immutable value: '$0' is immutable.
Can anyone figure out how to do this?
You should iterate over the array like this:
for (i, _) in myList.enumerated() {
myList[i].title.append("\(myList[i].location.distance(from: location) / 1000)")
}
You'd have to use a temporary mutable variable:
myList = myList.map { (myStruct: MyStruct) -> MyStruct in
var mutableStruct = myStruct
mutableStruct.title.append("\(element.location.distance(from: location) / 1000)")
return mutableStruct
}

Multidimensional Array Looping in cellForRowAtIndexPath Swift

I have a multidimensional array that I want to display the values of onto one UILabel in each respective cell.
My arrays look like this:
var arrayExample = [["beverages", "food", "suppliers"]["other stuff, "medicine"]]
I'm looping through these values in the cellForRowAtIndexPath in order for it to display on different cells (on a UILabel) the appropriate values:
if let onTheLabel: AnyObject = arrayOfContactsFound as? AnyObject {
for var i = 0; i < objects!.count; i++ {
cell?.contactsUserHas.text = "\(onTheLabel[indexPath.row][i])" as! String
print("arrayOfContactsFound Printing! \(onTheLabel)")
}
}
When printing to the console I get:
arrayOfContactsFound Printing! (
(
beverages,
"supply chain",
pharmacuticals
)
)
But on my label I get "beverages". That's it. How can I get the other 2 values (or X amount if there are more or less than 3 values)?
My for in loop is obviously not doing the trick. Assuming I can optimize/fix that to display all the values?
Thanks in advance.
In your loop you're setting the text of your label multiple times. Each time you set it it doesn't accumulate, it completely replaces the current text with the new text. You'll want something like this:
// Remove the cast and the loop in your code example, and replace with this
let items = arrayOfContactsFound[indexPath.row]
let itemsString = items.joinWithSeparator(" ")
cell?.contactsUserHas.text = itemsString
Another thing to note is your cast doesn't quite make a lot of sense.
var arrayExample = [["beverages", "food", "suppliers"]["other stuff, "medicine"]]
So arrayExample is of type [[String]]. I'm assuming each cell in your table view represents one of the arrays of strings in your array. So each cell represents one [String]. So your items should be arrayExample[indexPath.row]. The cast to AnyObject doesn't make too much sense. If anything you'd be casting it to [[AnyObject]], but there's no reason to because the compiler should already know it's [[String]].

How to remove an element of a given custom type value from an array in Swift

I want to remove element of custom type value from an array.
I want to pass a variant instance to function to remove it from array, I don't want to use removeAtIndex().
var favoriteVariants: [Variant]
func removeVariant(variant: Variant)
{
}
If Variant is Equatable and you only want to remove the first one that matches:
if let idx = favoriteVariants.indexOf(variant) {
favoriteVariants.removeAtIndex(idx)
}
If it isn’t Equatable and you have some other matching criteria to find just one to remove:
let idx = favoriteVariants.indexOf {
// match $0 to variant
}
if let idx = idx {
favoriteVariants.removeAtIndex(idx)
}
(these are assuming Swift 2.0 – if 1.2, it’s find(favoriteVariants, variant) instead of indexOf, and there isn’t a version that takes a closure, though it’s not too hard to write one)
If there are multiple ones you want to remove in one go:
favoriteVariants = favoriteVariants.filter {
// criteria to _keep_ any given favorite
}
All of these could be wrapped in extensions if what you want to do is general enough to justify it.

Creating and populating an empty Array

I'm actually learning swift in order to develop iOS apps. I'd like, as an exercise, to create and populate an empty array, that would be filled by using a textfield and a button on the storyboard.
var arr = []
// When button is pressed :
arr.append(textfield.text)
XCode tells me that the append method is not a method of NSArray. So I have used the addObject one, but it is still not correct as the arr variable contains nil.
So here are my three questions :
Is it possible to create an empty array, and if so, how to populate it ?
Sometimes, in my ViewController, when I create a non-empty array, the append method is apparently not valid, and I don't understand why..
Finally, why even though I use the syntax :
var arr = [1] // For example
The arr object is NSArray object and not a NSMutableArray object, making it impossible to add/remove any object that is contained in it?
I hope my questions are clear, if not I'll upload more code of what I'm trying to build,
thank you for your answers !
Try to define your array as a String array, like this:
var arr: [String] = []
And then append to your list, either by:
arr.append("the string")
or
arr += ["the string"]
Empty array can be created using the following syntax.
var emptyArray = [String]()
emptyArray.append("Hi")
see this
You can use following also to add elements to your array.
//append - to add only one element
emptyArray.append("Hi")
//To add multiple elements
emptyArray += ["Hello", "How r u"]
emptyArray.extend(["am fine", "How r u"])
//Insert at specific index
emptyArray.insert("Who r u", atIndex: 1)
//To insert another array objects
var array1 = ["who", "what", "why"]
emptyArray.splice(array1, atIndex: 1)

Resources