I am using beta 4 Xcode and simply have a list of string items that is modally presented from a main view.
var body: some View {
NavigationView {
List {
Section() {
Button(action: {
self.shouldShowModal = true
self.areasModal = true
self.accountsModal = false
}) {
Text("Areas")
}
}
}
}
.sheet(isPresented: $shouldShowModal, onDismiss: {
// on dismiss
}) {
if self.accountsModal {
Text("Accounts")
} else if self.areasModal {
AreaListView()
}
}
}
in the AreaListView
I have the following
class MockModel: BindableObject {
struct MockItem: Identifiable {
var id: String
}
var willChange = PassthroughSubject<Void, Never>()
var items: [MockItem] = [] {
willSet {
self.willChange.send()
}
}
init() {
self.performFetch()
}
func performFetch() {
DispatchQueue.main.async { [weak self] in
self?.items = [MockItem(id: "first"), MockItem(id: "fjirst"), MockItem(id: "fiklkrst"), MockItem(id: "fijlkrst")]
}
}
deinit {
print("deinit")
}
}
in perform fetch function I simulate cases where the model does a background process and then I need to return to the main thread.
and in the AreasListView I have
struct AreaListView: View {
@ObjectBinding var model = MockModel()
var body: some View {
NavigationView {
List {
ForEach(model.items) { (item) -> Text in
return Text(item.id)
}
}
}
}
}
it works just fine when I open the areas for the first time but the second time it stops populating the list. I observed then having the async removed from the performFetch()
everything works as expected. I also observe that deinit
is called not when the modal(sheet) is closed (by pulling down) but when I open the AreasListView for the second time. Could someone explain why the dispatch async causes Mal-function and also why deinitiation happens upon second opening of the AreasListView? many thanks,
p.s. also when adding the dispatch async to my model I see the following errors in the console log
=== AttributeGraph: cycle detected through attribute 18 ===
=== AttributeGraph: cycle detected through attribute 18 ===
=== AttributeGraph: cycle detected through attribute 104 ==
I have also tried the following not using the dispatch queue
func getItem() -> Future<[MockItem], Never> {
return Future { promise in
let t = [MockItem(id: "first"), MockItem(id: "fjirst"), MockItem(id: "fiklkrst"), MockItem(id: "fijlkrst")]
promise(.success(t))
}
}
func performFetch() {
temp = getItem().eraseToAnyPublisher().receive(on: RunLoop.main)
.sink(receiveValue: { [weak self] (items) in
self?.items = items
})
}