how to add object to one array from another - ios

what i am trying to do is loop through an array of images (parentArray) to add the image to 5 different arrays according to what kind of image it is and when i add an image i want to remove that image from the parentArray. ive tried this but i get a thread error. any ideas would help. thanks in advance.
the code :
var index = parentArray.count
for i in parentArray {
if i.Type == Kind.S && i.cState == Color.blue {
parentArray.removeAtIndex(index)
childArray1.append(i)
}

Indexing starts at zero, so parentArray.count will be accessing out of bounds memory.
A second error is that once you have removed one element from parentArray (assuming you were accessing the last index), its total size is less. However, next element you try to remove is the same number, which causes another array indexing issue. Good luck.

Your error is because you are trying to remove the object from the index parentArray.count which will always be out of the bounds of the array index. You also never change the value of index. So each time your if statement is met, it will try and remove from the index parentArray.count.
var index = 0
for i in parentArray {
if i.Type == Kind.S && i.cState == Color.blue {
parentArray.removeAtIndex(index)
childArray1.append(i)
}
else {
i++
}
}

Related

Find multiple elements that are equal to a condition in array?

I am a new to SwiftUI, so I apologise if this a dumb question but I came upon a problem that I cant find a solution to.
I am searching something similar to this code below, but instead of finding the first element I would like to retrieve all elements that have the status == 0.
if let new = array.first(where: {$0.status == 0}) {
// do something with foo
} else {
// item could not be found
}
Swift collections have a filter method which allows you to select all elements that match a given condition. You already have a matching condition, so to adapt your example text you'd write:
let newItems = array.filter { $0.status == 0 }

index of out of range error based on selected button tag

I am currently attempting to select a player by passing the button tag property inside of an array as shown in this line of code below:
selectedPlayer = players[sender.tag]
When I compiled the application, it crashes and displays a index out of range error, which I figure is because I'm accessing passed the size of the array. I am aware that make sure that I don't exceed the bounds of the array I need to do something like this:
players.count - 1
Although I am not entirely sure how to implement the same idea with the previous line of code. Any suggestions?
You can use ternary operator ?::
selectedPlayer = (sender.tag < players.count) ? players[sender.tag] : nil
If you want to use one liner code.
You have an array players of N elements make sure that
0 <= buttonTag < N
so max value of the button tag should be = N - 1 , you can avoid the crash with
if sender.tag < players.count {
selectedPlayer = players[sender.tag]
}
but the above may not accomplish the needed functionality , you have to adhere to the rule above

index(where:) method in swift is producing the wrong index

I have received an array index out of range error. I have two arrays cardsCurrentlyInPlay and currentCardsSelected. Every card that is in this game has a unique ID. I am attempting to find find the index of the card in cardsCurrentlyInPlay whose cardID matches the cardID of the card in currentCardsSelected. I am doing this by using the index(where:) method that takes a closure. My closure just checks if the IDs match, they obviously match because I am using the ! to unwrap them and the app does not crash there. It seems as though the index(where:) method is returning the wrong index. I have looked at this for hours and I do not understand whats going on.
Heres the code:
let indexOfFirstCard = cardsCurrentlyInPlay.index(where: ({($0?.cardID == currentCardsSelected[0].cardID)}))!
let indexOfSecondCard = cardsCurrentlyInPlay.index(where: ({($0?.cardID == currentCardsSelected[1].cardID)}))!
let indexOfThirdCard = cardsCurrentlyInPlay.index(where: ({($0?.cardID == currentCardsSelected[2].cardID)}))!
if deck.isEmpty && selectedCardsMakeASet() {
/* Remove the old cards */
cardsCurrentlyInPlay.remove(at: indexOfFirstCard)
cardsCurrentlyInPlay.remove(at: indexOfSecondCard)
cardsCurrentlyInPlay.remove(at: indexOfThirdCard) // where code is blowing up
currentCardsSelected.removeAll()
/* Return indicies of cards to clear from the UI */
return .deckIsEmpty(indexOfFirstCard, indexOfSecondCard, indexOfThirdCard)
}
The index you’re getting is correct when your get it, but it becomes wrong when you remove other cards. Consider:
var a = ["x", "y", "z"]
let indexOfX = a.index(of: "x")! // returns 0
let indexOfZ = a.index(of: "z")! // returns 2
a.remove(at: indexOfX) // removes "x"; now a = ["y", "z"]
a.remove(at: indexOfZ) // index 2 is now out of bounds
You could interleave the calls to index(of:) and remove(at:), but a better approach would be to remove all three cards in a single pass, something like this:
let selectedCardIDs = currentCardsSelected.map { $0.cardID }
cardsCurrentlyInPlay = cardsCurrentlyInPlay.filter { card in
!selectedCardIDs.contains(card.cardID)
}
Note that this has the added benefit of avoiding the force unwrap, a sign of sounder logic.
This is because of out of bounds.
After the first two code excuted.
cardsCurrentlyInPlay.remove(at: indexOfFirstCard) &
cardsCurrentlyInPlay.remove(at: indexOfSecondCard)
there is only one element in the cardsCurrentlyInPlay .
Then if you excute cardsCurrentlyInPlay.remove(at: indexOfThirdCard), the program will crash.

Enumerating with a for-in loop

I've got a loop that's throwing an error "Int is not convertible to Range< Int >":
var summaryValues:[Int]=[Int]();
for (dayIndex,valuesPerDay) in enumerate(allValuesPerDay){
if (valuesPerDay>0){
while summaryValues[dayIndex]==nil{ // ERROR
summaryValues.append(0);
}
summaryValues[dayIndex]++
}
}
That fourth line should simply be checking if there is a value at summaryValues in position dayIndex, but I'm a little unclear on the Swift syntax. Any ideas on how to fix this? Thanks for reading.
EDIT:
The work-around I've implemented is to replace the error line with
while cohortRetension.count<dayIndex+1 but I'd still like to better understand why summaryValues[dayIndex] was incorrect.
while summaryValues[dayIndex]==nil{ // ERROR
summaryValues is an array and array[i] won't return nil. It will either return the element or it will crash if your index is out of range. First, the compiler is probably confused from comparing Int and nil. Second, trying to access summaryValues[dayIndex] here will crash, because at the time you are checking it the array is empty and the index does not exist.
Repeatedly appending to an array is inappropriate when you know the size up front. Initialize your summaryValues as:
var summaryValues = [Int](count: allValuesPerDay.count, repeatedValue: 0)
then iterate over your allValuesPerDay simply with:
for dayIndex in 0..<allValuesPerDay.count {
if allValuesPerDay[dayIndex] > 0 {
summaryValues[dayIndex]++
}
}

I want to add the values of 2 UILabels together to display the results in a separate UILabel

//un-wrap string in label and cast to Int
let made = ShotsMadeLabel.text?.toInt() //shots made Int
let miss = ShotsMissedLabel.text?.toInt() //shots missed Int
// check to see if both values are not equal to zero
// add values and display answer (ans)in TotshotShotsMadelabel
if (miss != 0) || (made != 0){
var ans = made! + miss!
TotalShotsMadeLabel.text = "\(ans)"
println(ans) // check results
per request provided clarity to my question.. please let me know if there is a better way to do this..
Your code looks good but it fails to cover the case where one of the labels' text is empty or not a number. In that case, made or miss can be nil and you will crash when you force-unwrap it (with the exclamation mark).
So, you'd need to add another level of safety:
if (miss != 0) || (made != 0) {
if (miss != nil) && (made != nil) {
var ans = made! + miss!
}
}
But the truth is that you should not be doing this in the first place. Do not store state in a view like a label! This whole business of extracting the text from a label and turning it into a number is just wrong. You should have model variables in your code that are actual numbers, maintaining this information. When they change, change the labels. And that way, you can just add them. MVC, model-view-controller. Do not use View as Model, which is what you are doing.

Resources