0

I know, this is a very unusual thing to do, but I noticed that SwiftUI view won't update when a @State property is assigned from a pointer:

struct ContentView: View {
    @State private var numbers: [Int32] = []

    var body: some View {
        VStack {
            Text("\(numbers.description)")

            Button(action: {
                self.numbers.append(Int32.random(in: 0..<1000))
            }) {
                Text("Add a random number!")
            }

            Button(action: {
                var pointer: UnsafeMutableBufferPointer<Int32>!
                self.numbers.withUnsafeBufferPointer {
                    pointer = UnsafeMutableBufferPointer(mutating: $0)
                    sortMyArr(pointer.baseAddress!, Int32(self.numbers.count))
                }
                self.numbers = Array(pointer)
            }) {
                Text("Sort!")
            }
        }
    }
}

The sortMyArr is a dumb bubble sort in C:

void sortMyArr(int *arr, const int size)
{
    for (int i = 0; i < size; ++i) {
        for (int j = i; j < size; ++j) {
            if (arr[i] < arr[j]) {
                int tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
            }
        }
    }
}

The view updates when using self.numbers.sort() or self.numbers = self.numebers.sorted(), but not the way I used above.

As a hack, I can update the view with

    @State private var numbers: [Int32] = [] {
        didSet { self.needsUpdate = true }
    }
    @State private var needsUpdate = false {
        didSet { if self.needsUpdate { self.needsUpdate = false } }
    }

    // body view ...
    .background(Text("\(needsUpdate).description)").hidden())

Is there a way to notice SwiftUI without such a hack? This can be a problem when a project uses a bridge to C/C++.

EDIT: The same happens for NSMutableArray, using

self.someNSArray.sort(using: [NSSortDescriptor(key: "self", ascending: true)])
Jay Lee
  • 1,684
  • 1
  • 15
  • 27
  • It is not updated, because it is not actually changed (ie. sorted), try with local copy `var sorted = self.numbers` in button action. – Asperi Apr 27 '20 at 06:47
  • I realized that NSArray is a reference type, so making a local copy worked. However, it doesn't work for the pointer based approach. It seems that Swift Array is not noticed about its *internal* state change. I printed out the pointer addresses, and `.sort()` of Swift Array method indeed modified the begining pointer address, while the manual sort via C did not (which is obvious, because it was sorted in-place using a pointer). I don't think there is a non-hacky way to notify Swift Array about the change. – Jay Lee Apr 27 '20 at 10:42

0 Answers0