SwiftUI Bug - Список изменений пользовательского интерфейса блокировки - (СТАРЫЕ НАЗВАНИЯ: SwiftUI CoreData выборка очень медленная) - PullRequest
0 голосов
/ 14 октября 2019

Обновление # 4

  • Я переупорядочил этот пост, чтобы его было легче читать. То, что вы прочтете ниже, подробно расскажет об ошибке, с которой я столкнулся при использовании SwiftUI. Недавно я запросил поддержку на уровне кода у Apple, который подтвердил то же самое и попросил обратиться к отзыву о разрешении (что также было сделано, пока нет ответа).

Ошибка заключается в следующем : После отображения List или ForEach в представлении SwiftUI, если вы изменяете это представление, изменяя количество элементов в списке, пользовательский интерфейс блокируется, пока он пытается вычислить количество строк, которые изменились / должны быть изменены.

Я видел других, кто сталкивался с этой ошибкой на форумах разработчиков Apple. Их временное решение состояло в том, чтобы «установить массив пустым», таким образом полностью очистив список в течение примерно 100 миллисекунд, прежде чем изменять указанный набор данных. Это позволит избежать достаточной блокировки для пользователей, выполняющих итерацию List или ForEach с использованием массива данных.

Проблема в том, что при использовании CoreData, как описано в этом посте, нет никакого способа очистить список между нажимаемыми буквами (запросами на выборку).

В обновлении #3, есть проект GitHub, который показывает образец этой проблемы с примерами данных.

Любой вклад в обходные пути приветствуется.

Обновление # 3

Не очень хорошо. Как описано в этом посте , я смог перейти от использования CoreData к локальной базе данных SQLiteфайл. Мои результаты заключались в том, что поиск был таким же медленным, как при использовании CoreData. Я не знаю, что здесь происходит. Но, может быть, это что-то с отображением результатов на выходе SwiftUI? В любом случае, поиск и отображение большого количества данных кажется невозможным.

Я опубликовал пример проекта, который демонстрирует эту проблему на GitHub, согласно запросу Дж. Доу. Этот проект можно найти здесь

Надеюсь, кто-нибудь увидит, что я делаю не так. Мне трудно поверить, что это всего лишь ограничение iOS ..

Оригинальный пост

Есть идеи?

Я чувствую, что япропустить что-то фундаментальное. Мой запрос на выборку (код ниже) очень медленный. Я попытался добавить индекс к модели CoreData с отрицательным улучшением (предложение Дж. Доу ниже). Я думаю, может быть, мне нужно как-то добавить объявление fetchBatchSize в запрос на выборку (разобрался с этим - см. Обновление № 2 ниже - без помощи), но с помощью обёртки свойства @FetchRequest в SwiftUI, похоже, нет способасделай это.

Приведенный ниже код работает с тестовым набором данных из примерно 5000 записей. При поиске при каждом изменении ввода (с введением каждой буквы) поиск запускается снова, что приводит к остановке системы (более 100% загрузки ЦП и увеличение использования памяти).

В предыдущих приложениях я выполнял аналогичные задачи, но эти приложения использовали файл данных SQLite и были написаны в ObjC. В этих случаях все было очень быстро: этот тестовый набор более чем в 3 раза.

Если кто-нибудь может указать мне правильное направление, чтобы ускорить мою выборку CoreData, я был бы очень благодарен. Я не хочу возвращаться к файлу SQLite, если мне не нужно ..

Большое спасибо!

Используя SwiftUI, вот мой код:

struct SearchView: View {


    @Binding var searchTerm:String
    var titleBar:String

    var fetch: FetchRequest<MyData>
    var records: FetchedResults<MyData>{fetch.wrappedValue}

    init(searchTerm:Binding<String>, titleBar:String) {
        self._searchTerm = searchTerm
        self.titleBar = titleBar
        self.fetch = FetchRequest(entity: MyData.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \ MyData.header, ascending: true)], predicate: NSCompoundPredicate(type: .and, subpredicates: [ NSCompoundPredicate(type: .or, subpredicates: [NSPredicate(format: "%K CONTAINS[cd] %@", #keyPath(MyData.title),searchTerm.wrappedValue), NSPredicate(format: "%K CONTAINS[cd] %@", #keyPath(MyData.details),searchTerm.wrappedValue)]), NSPredicate(format: "%K == %@", #keyPath(MyData.titleBar),titleBar)])) //fetch request contains logic for module and search data - need to fix sort order later
    }

    var body: some View {


        List{

            Section(header: SearchBar(text: $searchTerm)) {

                ForEach(records, id: \.self) { fetchedData in

                    VStack {
                        NavigationLink(destination: DetailView(titleBar: fetchedData.title!, statuteData: fetchedData.details!, isFavorite: fetchedData.isFavorite)) {

                            HStack {
                                Text(fetchedData.header!)
                                    .font(.subheadline)

                                VStack(alignment: .leading) {
                                    Text(fetchedData.title!)
                                }
                                .scaledToFit()

                                Spacer()

                                if fetchedData.isFavorite {
                                    Image(systemName: "star.fill")
                                        .imageScale(.small)
                                        .foregroundColor(.yellow)
                                }
                            }
                        }
                    }
                }
            }.navigationBarTitle(Text("Search"))
        }
    }
}

Спасибо за вашу помощь.

Обновление:

Перед редактированием я сообщил о другой проблеме с хранением данных, однако эта проблема была решенас постом ниже:

Объекты CoreData медленно пишут

Обновление № 2:

Мой оригинальный вопрос спрашивал, как добавитьлимит партии на мой выбор, чтобы посмотреть, поможет ли это. Я был в состоянии переписать выборку без использования оболочки FetchRequest, используя NSFetchRequest и добавил ограничение партии. Ничего не помогло.

Еще раз спасибо

1 Ответ

0 голосов
/ 27 октября 2019

Вот обходной путь, который, я могу добавить, совершенно неприемлем. Это делает приложение технически работоспособным, но настолько медленным, что похоже на загрузку Windows 10 на 8086. Смешно.

Кроме того, до сих пор нет ответа или даже подтверждения от Apple Feedback. И мой запрос на поддержку уровня кода был удален, хотя они заявили, что не могут мне помочь. Не рад ..

В любом случае, если вы хотите создать приложение, которое выглядит как копание в грязи, используя CoreData и возможность поиска этих данных, вот ваш обходной путь ..

1st:Создайте хешируемую модель ваших данных или, по крайней мере, часть данных, которые вам нужно будет искать и / или отображать:

struct MyDataModel: Hashable {
  let title: String
  let name: String
  let myData: String
}

2-й: Создайте класс ObservableObject, который публикует переменную, содержащую массивкласса модели ваших данных, который вы только что создали:

class MyData:ObservableObject {
  @Published var searchDataArray = [MyDataModel]()
}

3-й: убедитесь, что вы передали переменную среды в представления, которые вы планируете использовать, это: (Этот пример находится в моем файле SceneDelegate.swift

let myData = MyData()

и добавьте .environmentObject(myData) к любому представлению, в котором оно вам нужно.

4-й: доступ к переменной Env из вашего представления: @EnvironmentObject var myData: MyData и загрузка результатов выборки в массив опубликованных данных, т.е. использовал эту функцию для выполнения задачи:

func arrayFiller(){ 

    if self.myData.searchDataArray.count > 0 {
        self.myData.searchDataArray.removeAll()
    }

    for item in self.fetchRequest {
        self.myData.searchDataArray.append(MyDataModel(title: item.title!, name: item.name!, myData: item:myData!))
    }
}

Наконец, из представления, которое вы хотите искать, вы можете выполнить итерацию вашего опубликованного env var и очистить массив между изменениями вкритерий поиска с задержкой, чтобы избежать ошибки.

ForEach(self.myData.searchDataArray, id: \.self) { fetchedItem in
    Text(fetchedItem.name)
}

Затем я использую .onReceive, чтобы посмотреть переменную searchTerm на предмет изменений, стереть опубликованный массив, подождать 10 миллисекунд и заполнить массив даннымиэто соответствует моим условиям поиска.

Это действительно медленно и отвратительно. Это работает, но я не думаю, что смогу приблизиться к производству с этим беспорядком.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...