How to make struct LazyList in SwiftUI?
2021, SwiftUI 2
Apple lies in wwdc20-10031
when telling that List is lazy.
List IS NOT LAZY on MacOS.
(I don't know about iOS)
About the question. Your code is wrong. This must work:
public struct LazyList<Data, ID, Content> where Data : RandomAccessCollection, Data.Element: Identifiable, ID : Hashable, Content: View {
public var data: Data
public var content: (Data.Element) -> Content
var body: some View {
ScrollView {
LazyVStack(spacing: 0) {
ForEach(data, content: content)
}
}
}
}
How we can Lazy load data to a Form/List in SwiftUI?
The problem is that static data source (and all internal dependencies) are allocated at once, even if later the corresponding UI rows will be shown only when needed.
Here is possible approach to solve this scenario - to make data container dynamic and load data by blocks (taking into account that List/Form reuses rows)
Tested with Xcode 12 / iOS 14
struct ContentView: View {
let max = 1000000 // even Int.max, if you want
let block = 10
@State private var indices = [0] // << initially loaded small part
var body: some View {
List {
ForEach(indices, id: \.self) { index in
Text("Row \(index)")
.onAppear {
// load next block when last row shown (or can be
// tuned to preload in advance)
if indices.last == index && index < max {
let next = max - index
indices.append(contentsOf:
Array(index + 1..<index+(next > block ? block : next)))
}
}
}
}
}
}
How to make a Horizontal List in SwiftUI?
You need to add .horizontal
property to the scrollview. otherwise it won't scroll.
ScrollView (.horizontal, showsIndicators: false) {
HStack {
//contents
}
}.frame(height: 100)
Why and when to use lazy with Array in Swift?
lazy
changes the way the array is processed. When lazy
is not used, filter
processes the entire array and stores the results into a new array. When lazy
is used, the values in the sequence or collection are produced on demand from the downstream functions. The values are not stored in an array; they are just produced when needed.
Consider this modified example in which I've used reduce
instead of count
so that we can print out what is happening:
Not using lazy
:
In this case, all items will be filtered first before anything is counted.
[1, 2, 3, -1, -2].filter({ print("filtered one"); return $0 > 0 })
.reduce(0) { (total, elem) -> Int in print("counted one"); return total + 1 }
filtered one
filtered one
filtered one
filtered one
filtered one
counted one
counted one
counted one
Using lazy
:
In this case, reduce
is asking for an item to count, and filter
will work until it finds one, then reduce
will ask for another and filter
will work until it finds another.
[1, 2, 3, -1, -2].lazy.filter({ print("filtered one"); return $0 > 0 })
.reduce(0) { (total, elem) -> Int in print("counted one"); return total + 1 }
filtered one
counted one
filtered one
counted one
filtered one
counted one
filtered one
filtered one
When to use lazy
:
option-clicking on lazy
gives this explanation:
From the Discussion for lazy
:
Use the lazy property when chaining operations:
to prevent intermediate operations from allocating storage
or
when you only need a part of the final collection to avoid unnecessary computation
I would add a third:
when you want the downstream processes to get started sooner and not have to wait for the upstream processes to do all of their work first
So, for example, you'd want to use lazy
before filter
if you were searching for the first positive Int
, because the search would stop as soon as you found one and it would save filter
from having to filter the whole array and it would save having to allocate space for the filtered array.
For the 3rd point, imagine you have a program that is displaying prime numbers in the range 1...10_000_000
using filter
on that range. You would rather show the primes as you found them than having to wait to compute them all before showing anything.
Is there a way to create a subfolder in the resources folder in Xcode?
You can select a group of files in the Xcode organizer, right click on them, and choose "Group" from the contextual popup menu. This will create a subfolder containing them. This subfolder is organizational only, and will not exist in your .app.
Related Topics
Value of Type 'Authdataresult' Has No Member 'Uid'
Convert Integer to Roman Numeral String in Swift
How to Use a Specific Gmt for a Function Which Will Be Recognised by Other Time Zones
Access Enum Associated Value as Optional
How to Make Sure Data in Variable Is Loaded Before Using It
Implementing a 'Report' Feature for Inappropriate Content Swift Firebase
How to Use Dispatchgroup/Gcd to Execute Functions Sequentially in Swift
Why Does the Completion Handler Does Not Return Anything
(Cross-)Compiling Swift for Raspberry Pi
Use Huge Numbers in Apple Swift
Undefined Symbol Objc_Class_$ When Creating iOS Framework
How to Change the Order of Functions Triggered
A Method Without Parameters Is Calling for an Argument
Make Swiftui Rectangle Same Height or Width as Another Rectangle