Is it possible to increment a variable used in ForEach SWIFTUI - swiftui

ForEach(questionsManager.answerChoices, id:\.id) { answer in
AnswerRow(index: i, answer: answer).environmentObject(questionsManager)
}
"i" is a #State variable in my View Struct that is assigned to zero
I want the index of each AnswerRow to be set from 0 to 3, how to manage that?

Rather than the elements iterate the indices of the array
ForEach(questionsManager.answerChoices.indices, id: \.self) { i in
AnswerRow(index: i, answer: questionsManager.answerChoices[i]).environmentObject(questionsManager)
}
The #State variable is actually not needed.
Side note: As you pass the questionsManager in the environment the answer parameter is not needed either.

Related

SwiftUI make LazyGrid Item twice the size of other Items

I want to display a grid where one item takes twice the amount of space of the others.
Similar to this HTML Grid
Basically I want the last item Text("div4") to take up the space of two items. I do not want to use .fixed since it should take exactly twice the space of the other grids no matter the screen size.
If there is a way to archive this without LazyGrid, that is also fine with me ;)
Here is my current code:
let cols = [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())]
var body : some View {
LazyVGrid(columns: cols){
Text("div1")
Text("div2")
Text("div3")
Text("div4")
}
}
Since Swift does not support this. A solution would be to use a library like: ExyteGrid!
var body : some View {
Grid(tracks: [.fr(1),.fr(1),.fr(1),.fr(2)]){
Text("div1")
Text("div2")
Text("div3")
Text("div4")
}
}
https://cocoapods.org/pods/ExyteGrid

Delete row from Realm via SwiftUI occurs exception 'Object has been deleted or invalidated.'

I trying to delete row from SwiftUI list which load data from Realm DB, it's implemented like here:
struct MyView: View {
private let realm = try! Realm()
var body: some View {
List {
ForEach(realm.objects(MyModelDB.self)) { model in
MyRow(model: model)
}
}.onDelete { indexSet in
try? realm.write {
indexSet.forEach { index in
realm.delete(words[index])
}
}
}
}
}
}
}
but when I perform deleting, I receive an exception:
*** Terminating app due to uncaught exception 'RLMException', reason: 'Object has been deleted or invalidated.'
Whats wrong?
A couple of options are: delete the objects in reverse order OR delete all of the objects at once.
Here's why. Suppose you have three objects
a index 0
b index 1
c index 2
so the total count is 3 and your indexSet contains indexes 0 1 and 2.
If you were to iterate over that, there would be three loops, however, realm is live updating so if you delete the object at index 0, then only two indexes remain, so when it tries to perform the third loop, it will crash.
Deleting in reverse alleviates that issue as index 2 is deleted first, then index 1 and then index 0.
I would suggest gathering up the objects you want deleted into an array or list and then deleting them all at once without iterating
realm.delete(objects: Sequence>)
where Sequence would be an Array or List.

SwiftUI Make a list that shows only a certain amount of rows

I have recently started messing around with SwiftUI and so far it is great. I have however ecnountered a problem that I can't seem to find an answer to.
I am trying to create this design:
As you can see here is a tableview (a list) which rows have a smaller tableview (a list) inside them. The task was pretty simple while using IB, but with swiftUI I can't seem to find a way to limit the number of rows to only the amount I need or to manually set the lists height based on the number of rows (keep in mind those rows can also be variable in height).
My code so far only consist of creating the List and adding 2 test rows:
List {
OrderItemRow()
OrderItemRow()
}
But as you can see SwiftUI automatically stretches the List to fill all the available space. The effect:
If you know the height of your rows, this can be achieved like this:
List(self.arrayOfAllItemsInOrder(currentOrder)) { item in
OrderItemRow(currentOrder: order, item:item)
}
.environment(\.defaultMinListRowHeight, rowHeight)
.frame(height: self.arrayOfAllItemsInOrder.reduce(0) { i, _ in i + rowHeight })
This will calculate the full size of the list based on rowHeight and limit the frame's height.
Note that if the size of your row goes beyond rowHeight, the entire calculation will be messed up and you will probably be seeing half (or missing entire) cells.
I would suggest a List using a ForEach to show your orders and a nested ForEach to show items in an order. The key is to manage the Data being supplied to each ForEach to the number of items desired and also to construct appropriate Row Views for OrderHeaderRow, OrderItemRow, etc.
struct OrdersView: View {
var body: some View {
List {
Section(header: Text("Current Order")) {
OrderHeaderRow(order: currentOrder)
ForEach(self.arrayOfAllItemsInOrder(currentOrder)) { item in
OrderItemRow(currentOrder: order, item:item)
}
OrderTotalRow(order: order)
ActionButtonsRow(order:order)
}
Section(header: Text("Previous Orders")) {
ForEach(self.arrayOfAllPreviousOrders) { order in
OrderHeaderRow(order: order)
ForEach(self.arrayOfAllItemsInOrder(order)) { item in
OrderItemRow(order: order, item:item)
}
OrderTotalRow(order: order)
ActionButtonsRow(order:order)
}
}
}
}
}

issues with delete item in array with swift 3

i have an problem with delete item from array i try to solve it long time but i couldn't
my problem is :
i have dictionary[Int:String] which contain items, the user select these items from the table view cell for delete it after,
this dictionary have an item from type string and with key key is indexPath.row
the following my dictionary code:
var dictionaryOfItems = [Int:String]()
dictionaryOfItems.updateValue("Banana", forKey: 0)
dictionaryOfItems.updateValue("Cucumber", forKey: 3)
and i have an array which contains array of item type string
the following code is my array :
var array :[String] = ["Banana","Apple","Orange","Cucumber","lettuce","Milk","Tea"]
i need to delete items from array which dictionarOfItems contain it's
when i try to delete the items from array i get the error message index out off range how can i fix it please
the following is my full code:
var array :[String] = ["Banana","Apple","Orange","Cucumber","lettuce","Milk","Tea"]
var dictionaryOfItems = [Int:String]()
dictionaryOfItems.updateValue("Banana", forKey: 0)
dictionaryOfItems.updateValue("Cucumber", forKey: 3)
for (index,_) in dictionaryOfItems {
if array[index] == dictionaryOfItems[index] {
array.remove(at: index)
}
}
Instead of explicitly removing item from your array, you can simply filter using a predicate:
Filtering our elements whose associated array index (say idx) corresponds to a key in you dictionary dictionaryOfItems whose value equals that of the array element.
E.g.:
array = array.enumerated()
.filter { (idx, _) in dictionaryOfItems[idx] != array[idx] }
.map { $0.1 }
print(array) // ["Apple", "Orange", "lettuce", "Milk", "Tea"]
It seems like quite a roundabout way, however; to use a dictionary to track the every-changing element indices in your mutatable array (this, in particular, is the reason of your runtime error). Are you sure you want a dictionary to track indices and elements in an array, where the latter is, inherently, a collection of elements and associated indices?
On another note, if your predicate is in fact simpler (just removes items which are present as values in a dictionary; without need of matching tracked indices), you could use a much simpler filter approach:
array = array.filter { !dictionaryOfItems.values.contains($0) }
print(array) // ["Apple", "Orange", "lettuce", "Milk", "Tea"]
Try this:
var array :[String] = ["Banana","Apple","Orange","Cucumber","lettuce","Milk","Tea"]
var dictionaryOfItems = [Int:String]()
dictionaryOfItems.updateValue("Banana", forKey: 0)
dictionaryOfItems.updateValue("Cucumber", forKey: 3)
var indexes = dictionaryOfItems.keys.sorted().reversed()
for index in indexes {
if array[index] == dictionaryOfItems[index] {
array.remove(at: index)
}
}

Array of implicitly unwrapped optionals iterates forever in Xcode 8 beta 4

My code (fragment below) causes the Simulator to Hang.
What am I doing wrong?
To reproduce the problem, cut and paste into the Simulator.
class INK
{
var test = 1
}
var array = [INK!](repeating: nil, count: 1)
for idx in 0..<array.count
{
array[idx] = INK()
}
var idx2 = 0
for ink_item in array
{
idx2 += 1
print("idx2=\(idx2)")
}
This is a known bug, see SR-1635. Since an IUO is no longer a distinct type, it shouldn't really be possible to have an array of them in the first place.
This is confirmed by the fact that the following code fails to compile:
// compiler error: Implicitly unwrapped optionals are only allowed at top level.
// and as function results
var array: [Ink!] = []
(note I renamed your class name to Ink to conform to Swift naming conventions)
Depending on your situation, you may want to consider using a lazy property instead:
lazy var array : [Ink] = {
var array = [Ink]()
// populate array
return array
}()
Or making the array itself an implicitly unwrapped optional (and defer both the allocation and initialisation of the array):
var array : [Ink]!
Although note that IUOs should always be a last resort due to their inherent unsafety.