Provide a catch if index is out of range (Swift 5) [closed] - ios

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
When I fetch data through a GET method in Swift it is presented as an Array:
URLSession.shared.dataTask(with: request as URLRequest) { (data, response, error) in
guard let data = data else { return }
do {
let obj: Response = try JSONDecoder().decode(Response.self, from: data)
let cit = obj.assetProfile?.city
let coun = obj.assetProfile?.country
let negociosLocacion = ("\(cit ?? "N/A"), \(coun ?? "N/A")")
let object = EObject(marketOpen: (obj.price?.regularMarketOpen?.fmt ?? "N/A"))
self.e.append(object)
But how do I create a catch method where if the index is out of range will present a segue, for example, as to not crash the app?

You can use indices to check if an array contains an index prior to accessing it:
guard myArray.indices.contains(1) else { return }
let value = myArray[1]
Apple documentation: indices

You can handle it through various ways for example I am showing you some code snippets below. See what case is similar to yours.
If you are getting items by index from an array then you can avoid array index out of range error like:
if yourIndex <= yourArray.endIndex {
//Then do your desired operation by getting items by your index
} else {
//Do not get items by your index because it is out of range.
//Do anything else
}
You can check that your array is empty or not? like:
if yourArray.isEmpty {
// Don't do any array item get operations because your array is empty
} else {
// Your array is not empty
}
You can check that at least your array has a fixed number of elements or not? like:
if yourArray.count >= yourDesiredNumberOfElements {
// Your array have at least your desired number of elements.
} else {
// Your array does not have your desired number of elements.
// your array has less elements than you desire.
}

A good solution is to use a safe subscript with returns optional element.
extension Array {
public subscript(safeIndex index: Int) -> Element? {
guard index >= startIndex, index < endIndex else {
return nil
}
return self[index]
}
}

In order to check if the index is out of bounds so as to not cause the app to crash and to handle the situation in another way,
if (yourArray.count - 1) >= yourIndex {
//Not out of bounds, carry on.
} else {
//This is when your app would crash due to being out of bounds.
}

Related

Read contents of an array out of a Firebase / Firestore query [duplicate]

This question already has answers here:
Missing return in a function expected to return 'Int'
(2 answers)
Closed 1 year ago.
Hi all I'm working with Firebase - Firestore for saving data. I just created a database call which returns me a Date from which I extract the hours and minutes.
The hours and minutes must be saved within an array with a tuple.
Everything seems to work but when I go to read my array outside of the clousure its value is always zero.
I need to read the contents of the array also outside the Firestore query method ..
Can anyone help me with this?
private var timeArray: [(Int, Int)] = []
private func getReservations() -> Void {
Service.Database.reservationRoot.whereField("date", isGreaterThan: Date()).getDocuments() { (querySnapshot, error) in
guard error == nil else { fatalError("Errore durante il recupero delle prenotazioni \(error!.localizedDescription)") }
for document in querySnapshot!.documents {
if let timestamp = document["date"] as? Timestamp {
let hour = timestamp.dateValue().component(.hour)
let minute = timestamp.dateValue().component(.minute)
self.timeArray.append((hour, minute))
// The array count is 2
print(self.timeArray.count)
}
}
}
// The array count is 0
print(self.timeArray.count)
}
for document in querySnapshot!.documents {
if let timestamp = document.data()["date"] as? Timestamp {
let hour = timestamp.dateValue().component(.hour)
let minute = timestamp.dateValue().component(.minute)
self.timeArray.append((hour, minute))
}
}
Can you try this code

getting crash on null data with callback function [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
Here is my code:
func getProduct(productId: String, callback: #escaping (String) -> () ){
Transport.sharedInstance.getProduct(productId: productId) { (data, err) in
if let _ = err{
}else{
if let dt = data as? String{
let pro = Mapper<SubCategoryProducts>().map(JSONString: dt)
let com = ComboData()
com.price = pro?.Price ?? 0
com.type = pro?.type ?? ""
com.amount = pro?.quantity ?? ""
if (pro?.combodata == nil) {
pro?.combodata?.append(com)
} else if ((pro?.combodata?.contains(where: {$0.type == pro?.type})))! {
} else {
pro?.combodata?.append(com)
}
self.arrayForCombo.removeAll()
pro?.combodata?.forEach({ (com) in
let str = "\(com.amount) " + "\(com.type)" + " - " + "₹ \(com.price)"
self.arrayForCombo.append(str)
})
callback(self.arrayForCombo[0])
}
}
}
}
I am getting nil pro?.combodata so only I have checked wether I am getting nil value or not and then when it comes to callback it getting crash on here callback(self.arrayForCombo[0]). Because its not appending the values. I don't know why, but not able to achieve that. Any solution it would be helpful.
Check if forEach is even stepped into.
At this point it can be that either pro or pro.combodata are nil and forEach is not called on nil collection.
Probably you're trying to access [0] index element after self.arrayForCombo.removeAll().
Try using this:
guard let pro = Mapper<SubCategoryProducts>().map(JSONString: dt) else { return }
let com = ComboData()
com.price = pro.Price ?? 0
com.type = pro.type ?? ""
com.amount = pro.quantity ?? ""
if (pro.combodata == nil) {
pro.combodata = [com]
}
The problem is that when combodata of pro is nil than you are trying to append the object that means you are trying nil.append() while it should be [ComboData].append().
I hope this will help you.
When the optional array is nil then calling append will do nothing, you need to initialize it first
if (pro?.combodata == nil) {
pro?.combodata = []
pro?.combodata?.append(com)
}
After executing self.arrayForCombo.removeAll() statement, arrayForCombo become empty. If your pro?.combodata is nil then forEach statement could not execute. So still your arrayForCombo is empty.
But in the callBack statement you forcefully try to access the first item of arrayForCombo whether it's empty or not. That's why it crushes when the array is empty.
You can safely by pass the cruhes like that:
if let firstItem = arrayForCombo.first {
callback(firstItem)
}

Swift 3 - Update key:value in dictionary in an array of dictionaries after comparison. Please assist

I have an array of dictionaries that I get as a JSON response to a URL
JSONResponse1 =
[{"id":"100", "name":"Matt", "phone":"0404040404", "address":"TBC"}
,{"id":"110", "name":"Sean", "phone":"0404040404", "address":"TBC"}
, {"id":"120", "name":"Luke", "phone":"0404040404", "address":"TBC"}]
I have another array of dictionaries that I get as a JSON response to another URL
JSONResponse2 =
[{"id":"100", "address":"1 Main Street"}
, {"id":"120", "address":"3 Main Street"}]
Both these response are linked by the key "id". I want to compare JSONResponse2 against JSONResponse1, and update JSONResponse1 so as to show the addresses as well. So the output of JSONResponse1 becomes:
JSONResponse1 =
[{"id":"100", "name":"Matt", "phone":"0404040404", "address":"1 Main Street"}
,{"id":"110", "name":"Sean", "phone":"0404040404", "address":"TBC"}
, {"id":"120", "name":"Luke", "phone":"0404040404", "address":"3 Main Street"}]
Note that all "id"s are not always present in JSONResponse2, in that case I want to leave it as it is
Here is my attempt:
for item in JSONResponse2.enumerated() {
for var items in JSONresponse1 {
if item.element["id"] == items["id"] {
let address_correct = item.element["address"] as! String
items["address"] = address_correct
self.finalDictionary.append(items)
} else {
self.finalDictionary2.append(items)
}
}
}
But this creates a really long finalDictionary2, because of for loop repetition. Any way around this?
Of course it happens, because of the else branch in the inner loop, which is not executed when the item from JSONResponse1 is not present in JSONResponse2, but is executed when the current item from JSONresponse1 is not equal to current item from JSONresponse2 - which is by far not the same thing as what you want.
Drop the else branch and add a new for loop after that, which will take care of finding those items that are not in JSONresponse2. So something like this:
for item in JSONResponse2.enumerated() {
for var items in JSONresponse1 {
if item.element["id"] == items["id"] {
let address_correct = item.element["address"] as! String
items["address"] = address_correct
self.finalDictionary.append(items)
}
}
}
for item in JSONResponse1 {
if !(JSONresponse2.contains { (item2) -> Bool in
return item["id"] == item2["id"]
}) {
self.finalDictionary2.append(item)
}
}

Missing argument for parameter #1 in call to Swift function

Very new to Swift and coding in general.
Just need some help getting my random selector to work. I am trying to make it choose a random number between 1 and 9 and check if that number is the same as the button you click.
enter image description here
I'm guessing you're trying to compare the random number to the title (displayed number) on the clicked button?
If so, add this line above your if statement:
guard let buttonInt = sender.titleLabel?.text.flatMap(Int.init) else { return }
Then, change your if statement to look like so:
if randomNumber == buttonInt {
// do what you want if it matches
} else {
// handle no match
}
// EDIT: Props to Alexander for the flatMap version
Please check :
let rand = Int(arc4random_uniform(9))
guard let buttonInt = Int(sender.currentTitle!) else { return }
if rand == buttonInt {
} else {
}

Array return optional value? [duplicate]

If I have an array in Swift, and try to access an index that is out of bounds, there is an unsurprising runtime error:
var str = ["Apple", "Banana", "Coconut"]
str[0] // "Apple"
str[3] // EXC_BAD_INSTRUCTION
However, I would have thought with all the optional chaining and safety that Swift brings, it would be trivial to do something like:
let theIndex = 3
if let nonexistent = str[theIndex] { // Bounds check + Lookup
print(nonexistent)
...do other things with nonexistent...
}
Instead of:
let theIndex = 3
if (theIndex < str.count) { // Bounds check
let nonexistent = str[theIndex] // Lookup
print(nonexistent)
...do other things with nonexistent...
}
But this is not the case - I have to use the ol' if statement to check and ensure the index is less than str.count.
I tried adding my own subscript() implementation, but I'm not sure how to pass the call to the original implementation, or to access the items (index-based) without using subscript notation:
extension Array {
subscript(var index: Int) -> AnyObject? {
if index >= self.count {
NSLog("Womp!")
return nil
}
return ... // What?
}
}
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)
}
}
If you really want this behavior, it smells like you want a Dictionary instead of an Array. Dictionaries return nil when accessing missing keys, which makes sense because it's much harder to know if a key is present in a dictionary since those keys can be anything, where in an array the key must in a range of: 0 to count. And it's incredibly common to iterate over this range, where you can be absolutely sure have a real value on each iteration of a loop.
I think the reason it doesn't work this way is a design choice made by the Swift developers. Take your example:
var fruits: [String] = ["Apple", "Banana", "Coconut"]
var str: String = "I ate a \( fruits[0] )"
If you already know the index exists, as you do in most cases where you use an array, this code is great. However, if accessing a subscript could possibly return nil then you have changed the return type of Array's subscript method to be an optional. This changes your code to:
var fruits: [String] = ["Apple", "Banana", "Coconut"]
var str: String = "I ate a \( fruits[0]! )"
// ^ Added
Which means you would need to unwrap an optional every time you iterated through an array, or did anything else with a known index, just because rarely you might access an out of bounds index. The Swift designers opted for less unwrapping of optionals, at the expense of a runtime exception when accessing out of bounds indexes. And a crash is preferable to a logic error caused by a nil you didn't expect in your data somewhere.
And I agree with them. So you won't be changing the default Array implementation because you would break all the code that expects a non-optional values from arrays.
Instead, you could subclass Array, and override subscript to return an optional. Or, more practically, you could extend Array with a non-subscript method that does this.
extension Array {
// Safely lookup an index that might be out of bounds,
// returning nil if it does not exist
func get(index: Int) -> T? {
if 0 <= index && index < count {
return self[index]
} else {
return nil
}
}
}
var fruits: [String] = ["Apple", "Banana", "Coconut"]
if let fruit = fruits.get(1) {
print("I ate a \( fruit )")
// I ate a Banana
}
if let fruit = fruits.get(3) {
print("I ate a \( fruit )")
// never runs, get returned nil
}
Swift 3 Update
func get(index: Int) ->T? needs to be replaced by func get(index: Int) ->Element?
To build on Nikita Kukushkin's answer, sometimes you need to safely assign to array indexes as well as read from them, i.e.
myArray[safe: badIndex] = newValue
So here is an update to Nikita's answer (Swift 3.2) that also allows safely writing to mutable array indexes, by adding the safe: parameter name.
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
}
}
extension MutableCollection {
subscript(safe index: Index) -> Element? {
get {
return indices.contains(index) ? self[index] : nil
}
set(newValue) {
if let newValue = newValue, indices.contains(index) {
self[index] = newValue
}
}
}
}
extension Array {
subscript (safe index: Index) -> Element? {
0 <= index && index < count ? self[index] : nil
}
}
O(1) performance
type safe
correctly deals with Optionals for [MyType?] (returns MyType??, that can be unwrapped on both levels)
does not lead to problems for Sets
concise code
Here are some tests I ran for you:
let itms: [Int?] = [0, nil]
let a = itms[safe: 0] // 0 : Int??
a ?? 5 // 0 : Int?
let b = itms[safe: 1] // nil : Int??
b ?? 5 // nil : Int? (`b` contains a value and that value is `nil`)
let c = itms[safe: 2] // nil : Int??
c ?? 5 // 5 : Int?
Swift 4
An extension for those who prefer a more traditional syntax:
extension Array {
func item(at index: Int) -> Element? {
return indices.contains(index) ? self[index] : nil
}
}
Valid in Swift 2
Even though this has been answered plenty of times already, I'd like to present an answer more in line in where the fashion of Swift programming is going, which in Crusty's words¹ is: "Think protocols first"
• What do we want to do?
- Get an Element of an Array given an Index only when it's safe, and nil otherwise
• What should this functionality base it's implementation on?
- Array subscripting
• Where does it get this feature from?
- Its definition of struct Array in the Swift module has it
• Nothing more generic/abstract?
- It adopts protocol CollectionType which ensures it as well
• Nothing more generic/abstract?
- It adopts protocol Indexable as well...
• Yup, sounds like the best we can do. Can we then extend it to have this feature we want?
- But we have very limited types (no Int) and properties (no count) to work with now!
• It will be enough. Swift's stdlib is done pretty well ;)
extension Indexable {
public subscript(safe safeIndex: Index) -> _Element? {
return safeIndex.distanceTo(endIndex) > 0 ? self[safeIndex] : nil
}
}
¹: not true, but it gives the idea
Because arrays may store nil values, it does not make sense to return a nil if an array[index] call is out of bounds.
Because we do not know how a user would like to handle out of bounds problems, it does not make sense to use custom operators.
In contrast, use traditional control flow for unwrapping objects and ensure type safety.
if let index = array.checkIndexForSafety(index:Int)
let item = array[safeIndex: index]
if let index = array.checkIndexForSafety(index:Int)
array[safeIndex: safeIndex] = myObject
extension Array {
#warn_unused_result public func checkIndexForSafety(index: Int) -> SafeIndex? {
if indices.contains(index) {
// wrap index number in object, so can ensure type safety
return SafeIndex(indexNumber: index)
} else {
return nil
}
}
subscript(index:SafeIndex) -> Element {
get {
return self[index.indexNumber]
}
set {
self[index.indexNumber] = newValue
}
}
// second version of same subscript, but with different method signature, allowing user to highlight using safe index
subscript(safeIndex index:SafeIndex) -> Element {
get {
return self[index.indexNumber]
}
set {
self[index.indexNumber] = newValue
}
}
}
public class SafeIndex {
var indexNumber:Int
init(indexNumber:Int){
self.indexNumber = indexNumber
}
}
I realize this is an old question. I'm using Swift5.1 at this point, the OP was for Swift 1 or 2?
I needed something like this today, but I didn't want to add a full scale extension for just the one place and wanted something more functional (more thread safe?). I also didn't need to protect against negative indices, just those that might be past the end of an array:
let fruit = ["Apple", "Banana", "Coconut"]
let a = fruit.dropFirst(2).first // -> "Coconut"
let b = fruit.dropFirst(0).first // -> "Apple"
let c = fruit.dropFirst(10).first // -> nil
For those arguing about Sequences with nil's, what do you do about the first and last properties that return nil for empty collections?
I liked this because I could just grab at existing stuff and use it to get the result I wanted. I also know that dropFirst(n) is not a whole collection copy, just a slice. And then the already existent behavior of first takes over for me.
I found safe array get, set, insert, remove very useful. I prefer to log and ignore the errors as all else soon gets hard to manage. Full code bellow
/**
Safe array get, set, insert and delete.
All action that would cause an error are ignored.
*/
extension Array {
/**
Removes element at index.
Action that would cause an error are ignored.
*/
mutating func remove(safeAt index: Index) {
guard index >= 0 && index < count else {
print("Index out of bounds while deleting item at index \(index) in \(self). This action is ignored.")
return
}
remove(at: index)
}
/**
Inserts element at index.
Action that would cause an error are ignored.
*/
mutating func insert(_ element: Element, safeAt index: Index) {
guard index >= 0 && index <= count else {
print("Index out of bounds while inserting item at index \(index) in \(self). This action is ignored")
return
}
insert(element, at: index)
}
/**
Safe get set subscript.
Action that would cause an error are ignored.
*/
subscript (safe index: Index) -> Element? {
get {
return indices.contains(index) ? self[index] : nil
}
set {
remove(safeAt: index)
if let element = newValue {
insert(element, safeAt: index)
}
}
}
}
Tests
import XCTest
class SafeArrayTest: XCTestCase {
func testRemove_Successful() {
var array = [1, 2, 3]
array.remove(safeAt: 1)
XCTAssert(array == [1, 3])
}
func testRemove_Failure() {
var array = [1, 2, 3]
array.remove(safeAt: 3)
XCTAssert(array == [1, 2, 3])
}
func testInsert_Successful() {
var array = [1, 2, 3]
array.insert(4, safeAt: 1)
XCTAssert(array == [1, 4, 2, 3])
}
func testInsert_Successful_AtEnd() {
var array = [1, 2, 3]
array.insert(4, safeAt: 3)
XCTAssert(array == [1, 2, 3, 4])
}
func testInsert_Failure() {
var array = [1, 2, 3]
array.insert(4, safeAt: 5)
XCTAssert(array == [1, 2, 3])
}
func testGet_Successful() {
var array = [1, 2, 3]
let element = array[safe: 1]
XCTAssert(element == 2)
}
func testGet_Failure() {
var array = [1, 2, 3]
let element = array[safe: 4]
XCTAssert(element == nil)
}
func testSet_Successful() {
var array = [1, 2, 3]
array[safe: 1] = 4
XCTAssert(array == [1, 4, 3])
}
func testSet_Successful_AtEnd() {
var array = [1, 2, 3]
array[safe: 3] = 4
XCTAssert(array == [1, 2, 3, 4])
}
func testSet_Failure() {
var array = [1, 2, 3]
array[safe: 4] = 4
XCTAssert(array == [1, 2, 3])
}
}
Swift 5.x
An extension on RandomAccessCollection means that this can also work for ArraySlice from a single implementation. We use startIndex and endIndex as array slices use the indexes from the underlying parent Array.
public extension RandomAccessCollection {
/// Returns the element at the specified index if it is within bounds, otherwise nil.
/// - complexity: O(1)
subscript (safe index: Index) -> Element? {
guard index >= startIndex, index < endIndex else {
return nil
}
return self[index]
}
}
extension Array {
subscript (safe index: UInt) -> Element? {
return Int(index) < count ? self[Int(index)] : nil
}
}
Using Above mention extension return nil if anytime index goes out of bound.
let fruits = ["apple","banana"]
print("result-\(fruits[safe : 2])")
result - nil
I have padded the array with nils in my use case:
let components = [1, 2]
var nilComponents = components.map { $0 as Int? }
nilComponents += [nil, nil, nil]
switch (nilComponents[0], nilComponents[1], nilComponents[2]) {
case (_, _, .Some(5)):
// process last component with 5
default:
break
}
Also check the subscript extension with safe: label by Erica Sadun / Mike Ash: http://ericasadun.com/2015/06/01/swift-safe-array-indexing-my-favorite-thing-of-the-new-week/
The "Commonly Rejected Changes" for Swift list contains a mention of changing Array subscript access to return an optional rather than crashing:
Make Array<T> subscript access return T? or T! instead of T: The current array behavior is intentional, as it accurately reflects the fact that out-of-bounds array access is a logic error. Changing the current behavior would slow Array accesses to an unacceptable degree. This topic has come up multiple times before but is very unlikely to be accepted.
https://github.com/apple/swift-evolution/blob/master/commonly_proposed.md#strings-characters-and-collection-types
So the basic subscript access will not be changing to return an optional.
However, the Swift team/community does seem open to adding a new optional-returning access pattern to Arrays, either via a function or subscript.
This has been proposed and discussed on the Swift Evolution forum here:
https://forums.swift.org/t/add-accessor-with-bounds-check-to-array/16871
Notably, Chris Lattner gave the idea a "+1":
Agreed, the most frequently suggested spelling for this is: yourArray[safe: idx], which seems great to me. I am very +1 for adding this.
https://forums.swift.org/t/add-accessor-with-bounds-check-to-array/16871/13
So this may be possible out of the box in some future version of Swift. I'd encourage anyone who wants it to contribute to that Swift Evolution thread.
Not sure why no one, has put up an extension that also has a setter to automatically grow the array
extension Array where Element: ExpressibleByNilLiteral {
public subscript(safe index: Int) -> Element? {
get {
guard index >= 0, index < endIndex else {
return nil
}
return self[index]
}
set(newValue) {
if index >= endIndex {
self.append(contentsOf: Array(repeating: nil, count: index - endIndex + 1))
}
self[index] = newValue ?? nil
}
}
}
Usage is easy and works as of Swift 5.1
var arr:[String?] = ["A","B","C"]
print(arr) // Output: [Optional("A"), Optional("B"), Optional("C")]
arr[safe:10] = "Z"
print(arr) // [Optional("A"), Optional("B"), Optional("C"), nil, nil, nil, nil, nil, nil, nil, Optional("Z")]
Note: You should understand the performance cost (both in time/space) when growing an array in swift - but for small problems sometimes you just need to get Swift to stop Swifting itself in the foot
To propagate why operations fail, errors are better than optionals.
public extension Collection {
/// Ensure an index is valid before accessing an element of the collection.
/// - Returns: The same as the unlabeled subscript, if an error is not thrown.
/// - Throws: `AnyCollection<Element>.IndexingError`
/// if `indices` does not contain `index`.
subscript(validating index: Index) -> Element {
get throws {
guard indices.contains(index)
else { throw AnyCollection<Element>.IndexingError() }
return self[index]
}
}
}
public extension AnyCollection {
/// Thrown when `[validating:]` is called with an invalid index.
struct IndexingError: Error { }
}
XCTAssertThrowsError(try ["🐾", "🥝"][validating: 2])
let collection = Array(1...10)
XCTAssertEqual(try collection[validating: 0], 1)
XCTAssertThrowsError(try collection[validating: collection.endIndex]) {
XCTAssert($0 is AnyCollection<Int>.IndexingError)
}
I think this is not a good idea. It seems preferable to build solid code that does not result in trying to apply out-of-bounds indexes.
Please consider that having such an error fail silently (as suggested by your code above) by returning nil is prone to producing even more complex, more intractable errors.
You could do your override in a similar fashion you used and just write the subscripts in your own way. Only drawback is that existing code will not be compatible. I think to find a hook to override the generic x[i] (also without a text preprocessor as in C) will be challenging.
The closest I can think of is
// compile error:
if theIndex < str.count && let existing = str[theIndex]
EDIT: This actually works. One-liner!!
func ifInBounds(array: [AnyObject], idx: Int) -> AnyObject? {
return idx < array.count ? array[idx] : nil
}
if let x: AnyObject = ifInBounds(swiftarray, 3) {
println(x)
}
else {
println("Out of bounds")
}
I have made a simple extension for array
extension Array where Iterator.Element : AnyObject {
func iof (_ i : Int ) -> Iterator.Element? {
if self.count > i {
return self[i] as Iterator.Element
}
else {
return nil
}
}
}
it works perfectly as designed
Example
if let firstElemntToLoad = roots.iof(0)?.children?.iof(0)?.cNode,
You can try
if index >= 0 && index < array.count {
print(array[index])
}
To be honest I faced this issue too. And from performance point of view a Swift array should be able to throw.
let x = try a[y]
This would be nice and understandable.
When you only need to get values from an array and you don't mind a small performance penalty (i.e. if your collection isn't huge), there is a Dictionary-based alternative that doesn't involve (a too generic, for my taste) collection extension:
// Assuming you have a collection named array:
let safeArray = Dictionary(uniqueKeysWithValues: zip(0..., array))
let value = safeArray[index] ?? defaultValue;
2022
infinite index access and safe idx access(returns nil in case no such idex):
public extension Collection {
subscript (safe index: Index) -> Element? {
return indices.contains(index) ? self[index] : nil
}
subscript (infinityIdx idx: Index) -> Element where Index == Int {
return self[ abs(idx) % self.count ]
}
}
but be careful, it will throw an exception in case of array/collection is empty
usage
(0...10)[safe: 11] // nil
(0...10)[infinityIdx: 11] // 0
(0...10)[infinityIdx: 12] // 1
(0...10)[infinityIdx: 21] // 0
(0...10)[infinityIdx: 22] // 1
Swift 5 Usage
extension WKNavigationType {
var name : String {
get {
let names = ["linkAct","formSubm","backForw","reload","formRelo"]
return names.indices.contains(self.rawValue) ? names[self.rawValue] : "other"
}
}
}
ended up with but really wanted to do generally like
[<collection>][<index>] ?? <default>
but as the collection is contextual I guess it's proper.

Resources