I'm running into a Simultaneous accesses to <ptr>, but modification requires exclusive access
issue, which IMO should actually be allowed, bc there are no overlapping accesses going on in the code.
The specific issue (i have a simplified working reproduction example below) is that i have a function which takes an inout
parameter (for which we pass a reference to an instance property) and then performs an update operation on a UITableView, which in turn calls the data source's -tableView:numberOfRowsInSection:
method, which in turn tries to access the instance property (a reference to which, however, is at this point still being passed to the function, via the inout
param).
I get why this is happening (the compiler emits a pair of swift_beginAccess
and swift_endAccess
calls before and after the call to the inout
-param-taking function), but IMO this is overly strict, because the callee doesn't actually access the reference it's passed past a certain point in its body (meaning that the scope of where the callee needs access to the passed reference ends earlier than the scope of the callee as a whole and there is a time period during the execution of the program where the still-ongoing call unnecessarily prevents accesses to the object).
I'm aware that in my specific case, I could work around this by e.g. delaying the table view update until the next layout cycle, but obviously that kind of fix only really works in this specific case, and doesn't really solve the underlying issue (of the exclusive access requirements being too restrictive in the case of inout
parameters).
Is this the intended behaviour?
Here is a small example that exhibits this issue:
class TableView {
var numSectionsProvider: () -> Int = { 0 }
func toggleAndReload(idx: Int, indices: inout Set<Int>) {
if indices.contains(idx) {
indices.remove(idx)
} else {
indices.insert(idx)
}
// The next line causes the simultaneous access violation,
// bc the Set is still being accessed by the current function (via the inout param),
// even though we don't have any further accesses to it beyond the if stmt above.
// Having the compiler insert the swift_endAccess call here instead of in the caller
// (after the call) would probably fix this (and have the tracked accesses match
// the actual accesses more closely).
let numSections = self.numSectionsProvider()
}
}
class A {
let tableView = TableView()
var collapsedSections = Set<Int>()
init() {
tableView.numSectionsProvider = { [weak self] in
return self?.collapsedSections.count ?? 0
}
tableView.toggleAndReload(idx: 0, indices: &collapsedSections)
}
}
let a = A()