Swift Access Array with Index Gives Following Error. Any Idea Why

Swift access array with index gives following error. Any idea why?

you have to convert the index to Int like e.g. this:

let index1: UInt32 = arc4random_uniform(10); // with the type of the value
let x = array[Int(index1)];

the Int is the proper index type rather than UInt32.

UPDATE

if you are not quiet happy to convert the index every individual time, you can also add an extension to Array with defining a new subscript for your generic index type(s), e.g. such extension would look with UInt32 like this:

extension Array {
subscript (index: UInt32) -> T {
get {
let intIndex : Int = Int(index)
return self[intIndex]
}
}
}

NOTE: I have not worked out the setter here.

Is there a reason why array[index] doesn't return an optional?

This was one of my first Swift radars, which was closed as "Behaves Correctly." It was also discussed in the dev forums. As noted by Dave Abrahams:

As to rationale, It’s easy and very common to have static knowledge that the index is in range.... In this case it’s much better to establish a precondition that the index is valid so that common use-cases don’t have to cope syntactically with a failure that can’t happen. Contrast this with dictionary indexing on keys, where it’s commonly not known whether the key is already in the dictionary.

As I've grown more experienced in Swift, I've come to agree. I do sometimes wish there were a "safe subscript" (like Mike Ash's) built-in, but I've come to agree that it shouldn't be the default.

Making it the default would make Arrays very difficult to work with, not just because of the required unwrap, but because the Index type would no longer be Int. It is required that subscript(Index) return Element (not Element?). This is why the Index of Dictionary isn't Key; it's DictionaryIndex<Key,Value>. Creating a special ArrayIndex would likely have a lot of annoying side-effects. (Maybe it would all work out in the end, but it's questionable whether it's worth it.)

The real lesson here is that you should avoid arbitrarily subscripting Arrays anyway. When practical, you should prefer to use it as a CollectionType. That means subscripting only with indexes that you fetched (with indexOf or indices for instance), and strongly favoring iteration (for-in, map) rather than subscripting. Use xs.first rather than xs[0]. If you treat it as a collection rather than an array, then you get the safety you're describing, while still leaving subscripts available when you need to solve special problems where you know the subscript is in range.

Here's an illustrative example. Consider this common loop, which you may think requires subscripting:

let xs = [1,2,3]

for i in 0..<xs.count {
print("\(i): \(xs[i])")
}

We can do this a little better and not rely on our special knowledge of array indexing and make it work for all Collections:

for i in xs.indices {
print("\(i): \(xs[i])")
}

But even that isn't necessary. We can do much better and make it work for all Sequences:

for (i, x) in xs.enumerate() {
print("\(i): \(x)")
}

No subscript required.

fatal error: Array index out of range Swift

Seeing from your other comments in this thread it appears you are trying to filter out spaces and commas from a string that may look like "1, 2, 3". Correct me if this is wrong. The completely swifty solution to this is as follows:

do {
var data = try String(contentsOfFile: documentsDirectoryPath as String, encoding: NSASCIIStringEncoding)
print(data)

let newarray = data.characters.filter { Int(String($0)) != nil }.map { Int(String($0))! }
} catch {
print("error")
}

Explanation

filter will return an array of Characters that convert to integers. map will then take that array and then transform each element into an integer. We have to convert the Character to a String type because there is no Int constructor that takes a Character.

Why Is My Array Index Out Of Range Using An If Statement?

When you look at the documentation of the insert function, it says the following about the i parameter:

i

The position at which to insert the new element. index must be a valid index of the array or equal to its endIndex property.

You need to insert the element to an existing index or add it to the end of the array. It might help to add a print statement to print index, i and the array you are inserting it in to see what is exactly going on.

Swift Array - Check if an index exists

An elegant way in Swift:

let isIndexValid = array.indices.contains(index)

Looping through an array to get index of item - swift

I have managed to solve this error myself in a slightly different way.

In my function which populates the nameArray and the UIPicker I have placed the following code:

                var i : Int = 0
while (self.nameArray[i] != name)
{
print(self.nameArray[i])
i=i+1
}
self.scroll_owners.selectRow(i, inComponent: 0, animated: true)

The reason the code was crashing was due to the fact that the nameArray was not finishing being populated before I was trying to do the comparisons. I know this may not be the accepted swift way of doing this but it works.

The issues were caused due to the function being run on a seperate thread I believe.

How to find index of list item in Swift?

As swift is in some regards more functional than object-oriented (and Arrays are structs, not objects), use the function "find" to operate on the array, which returns an optional value, so be prepared to handle a nil value:

let arr:Array = ["a","b","c"]
find(arr, "c")! // 2
find(arr, "d") // nil

Use firstIndex and lastIndex - depending on whether you are looking for the first or last index of the item:

let arr = ["a","b","c","a"]

let indexOfA = arr.firstIndex(of: "a") // 0
let indexOfB = arr.lastIndex(of: "a") // 3

Impossible Index of of Range crash

Are you, by any chance, doing any of your updating from a background thread/queue? If so, make sure your UI interactions are done on the main thread/queue and that you aren't changing the array contents behind your UI's back.

That is, if you're changing the array contents in one queue and trying to update your UI while this is happening, your guard statement could be passing just before the array is modified elsewhere, then by the time the rest of your UI-interacting code executes, the index my no longer be valid.

Without a more complete picture, it's hard to say what's going on, but all these bounds checks you're adding in order to guard against mysteriously-changing array indexes are a big clue to multithreading shenanigans.

Iterate an array with index in Swift 3

You forgot to call a.enumerated(), which is what gives you the (index, value) tuples. for value in a is what gives you each element without the index.

Safe (bounds-checked) array lookup in Swift, through optional bindings?

Alex's answer has good advice and solution for the question, however, I've happened to stumble on a nicer way of implementing this functionality:

extension Collection {
/// Returns the element at the specified index if it is within bounds, otherwise nil.
subscript (safe index: Index) -> Element? {
return indices.contains(index) ? self[index] : nil
}
}


Example

let array = [1, 2, 3]

for index in -20...20 {
if let item = array[safe: index] {
print(item)
}
}


Related Topics



Leave a reply



Submit