0

I want to not show a swiftui view under several conditions, e.g. a[3]==3 or b[17]==3. This can be implemented as:

if a[3]!=3 && b[17]!=3 {
    Text("show view")
}

However, the number of elements of a and b is variable and 3 or 17 might be out of range. Therefore, one might think of the following code:

if true {
    if a.count > 3 {
        if a[3]==3 {
            break
        }
    }
    if b.count>17 {
        if b[17]==7 {
            break
        }
    }
    Text("show view")
}

However, in a swiftui view, break is not available. Furthermore, this code does not really look elegant.

phenolot
  • 43
  • 6
  • 3
    These hardcoded `3` and `17` indices are really suspicious, and even more so when they're not guaranteed to exist. What are they representing? – Alexander Sep 13 '21 at 07:21
  • Alexander, you are right to suspect that this is not the real code. 3 and 17 are just examples. In the real code, the problem occurs in several variations, e.g. with a variable index a[i] or with a hardcoded first index, i.e. a[0] – phenolot Sep 13 '21 at 07:51
  • 1
    My point still stands. Indexing into an array at arbitrary hard-coded indices is a bit suspitious: what is it you expect to find there? Is there a better way to express that? As for the first index, you'd better off using the `first` property, which returns an optional that nicely handed the empty-array case. – Alexander Sep 13 '21 at 08:12
  • 2
    You should move the logic into a view model so your view code would be something like `if viewModel.showView {` – Joakim Danielson Sep 13 '21 at 08:29
  • Alexander: b contains a list of products suggested by the app. There is a specific product with the id=3. When this product appears in the list, it indicates that the user does want to deal with any suggested products in this part of the view. Usually this specific product appears at the first position of the list. Thanks for the hint using the first property! There might be another way to implement the rest. – phenolot Sep 13 '21 at 08:39
  • Joakim, your solution is the one I chose. How can I give you credit for it? – phenolot Sep 14 '21 at 14:39

2 Answers2

2

One way is to write a safe subscript and use that to access the array:

// from https://stackoverflow.com/a/30593673/5133585
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
    }
}

// in your view...
if a[safe: 3] != 3 && b[safe: 17] != 3 {
    Text("show view")
}

Now a[safe: 3] would be of type Int? (assuming a is an [Int]). An out-of-range access will give you nil. Comparing that to 3 still works, because != and == are defined for all T? where T is Equatable.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Thanks, sweeper. I already solved the problem by using a view model, as joakim and keyvan suggested. Although the code now works, next, I am going to implement your suggestion in combination with a view model. Safe subscript is certainly much more elegant than my double break solution. – phenolot Sep 14 '21 at 14:44
  • 1
    If this answer helped you, please upvote and/or accept it. – rob mayoff Sep 14 '21 at 15:25
1

ViewModel :

@Published var showView : Bool = false

func checkShowView(){

   if a.count > 3 && b.count> 17 {
      if a[3]!=3 && b[17]!=3 {
          showView = true
      }
   }else if a.count > 3 {
      if a[3]!=3{
         showView = true
      }
   }else if b.count>17 {
      if b[17]!=3 {
           showView = true
      }
   }else {
      showView = true
   }
}

View :

@StateObject var viewModel = ViewModel()

if viewModel.showView {
   Text("show View")
}
  • Thanks, but unfortunately, this does not do what I want. If the indices are out of range, I want to show the view. – phenolot Sep 13 '21 at 07:55
  • sorry did not know that , edited the answer . – keyvan yaghoubian Sep 13 '21 at 07:57
  • still doesn't work: if a[3] is 3 and b[17] is out of range, then, in your example, the view is shown. However, I want it not to be shown since a[3]==3. – phenolot Sep 13 '21 at 08:11
  • thanks, now your answer will work. Unfortunately, it isn't really more elegant than my own initial solution... – phenolot Sep 13 '21 at 11:17
  • it's a little bit cleaner and easier to read, for better implementation you should move this logic to a ViewModel class. – keyvan yaghoubian Sep 13 '21 at 16:07
  • I just realized that my original suggestion does not work (due to "break") whereas yours does. The problem of your solution is: Text("show view") occurs three times. In the original code, this part is much longer, so I have to code it as a separate view. – phenolot Sep 14 '21 at 14:36