Список основных данных SwiftUI не сортируется, не закрывает и не открывает дочернее представление при вставке элемента - PullRequest
0 голосов
/ 08 мая 2020

Я попытался создать приложение SwiftUI для iOS У меня есть отцовское представление, которое содержит список комнат чатов, отсортированных по дате последнего действия, когда я открываю дочернее представление (представление чата) и отправляю сообщение, которое я храню в основных данных, представление закрывается и снова открывается, я пробовал FetchRequest в представлении

Обратите внимание, в приведенном ниже примере я удалил весь ненужный код и просто показываю фрагмент кода в TextField, генерирующий ошибку. мой код


struct ChatsView: View {
    @ObservedObject var chatsVM: ChatsVM = ChatsVM()

    var body: some View {
        GeometryReader { geometry in
            NavigationView {
                VStack {
                    List {

                                ForEach(self.search(self.chatsVM.rooms), id: \.self) { room in
                                    NavigationLink(destination: ChatView(room: room)){
                                        RoomItemView()
                                            .environmentObject(room)
                                            .listRowInsets(EdgeInsets())
                                    }
                                }

                    }
                }
                .navigationBarTitle(Text("Chats"))
            }
            .navigationViewStyle(StackNavigationViewStyle())
        }
    }

}

это вид чата


struct ChatView: View {
    @FetchRequest var messages: FetchedResults<MessageCD>

    init(room: RoomCD) {
        self.chatVM = ChatVM(room: room)
        // Do some kind of control flow for customizing the predicate here.
        self._messages = FetchRequest(
            entity: MessageCD.entity(),
            sortDescriptors: [NSSortDescriptor(key: "createdAt", ascending: false)],
            predicate: NSPredicate(format: "room == %@", room)
        )
    }

    var body: some View {
        GeometryReader { geometry in
            VStack {
                VStack(alignment: .center, spacing: 5) {
                    ZStack {
                        VStack(spacing: 0) {
                            if self.chatVM.isImageEditing {
                                VStack {
                                    PreviewToSendView(inputImage: self.$chatVM.imageSelected, isEditting: self.$chatVM.isImageEditing, url: self.$chatVM.urlFile)
                                }
                            } else{
                                Rectangle()
                                    .fill(Color.clear)
                                    .frame(height: 40)
                                self.messagesList

                                if self.chatVM.urlFile != nil {
                                    self.documentPreview
                                }
                            }
                            self.messageOptionsAndInput
                        }
                        VStack {
                            if !self.chatVM.isImageEditing {
                                self.countdown
                            }
                            Spacer()
                        }
                    }
                    .onReceive(
                        NotificationCenter.default.publisher(for: UIResponder.keyboardWillChangeFrameNotification)
                            .receive(on: RunLoop.main),
                        perform: self.updateKeyboardHeight
                    )
                    .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
                        print("Moving back to the foreground!")
                    }
                }

            }
                .navigationBarHidden(self.chatVM.isImageEditing)
                .navigationBarTitle("", displayMode: .inline)
                .navigationBarBackButtonHidden(true)
                .navigationBarItems(trailing:
                    HStack {
                        if self.chatVM.isImageEditing {
                            EmptyView()
                        } else {
                            self.titleBar
                            .frame(width: (geometry.size.width * 1) - 20)
                        }
                    }
                )
                .padding(.bottom, self.keyboardHeight)
                .transition(.slide)
                .animation(.easeIn(duration: self.keyboardAnimationDuration))
                .animation(.easeOut(duration: self.keyboardAnimationDuration))
                .edgesIgnoringSafeArea((self.keyboardHeight > 0) ? [.bottom] : [])
        }
    }

    func sendMessageText() {
        self.chatVM.sendMessage(text: self.typingMessage ?? "")
        self.typingMessage = nil
        self.chatVM.isImageEditing = false
        self.endEditing(true)
    }

    private var messagesList: some View {
        List {
                ForEach(messages, id: \.self) { message in
                    MessageView(currentMessage: message)
                        .transition(.fade)
                        .animation(.easeIn)
                        .scaleEffect(x: 1, y: -1, anchor: .center)
                        .listRowInsets(EdgeInsets())
                }

        }
            .listSeparatorStyleNone()
            .onAppear() {
                self.chatVM.seenMessages()
            }
            .scaleEffect(x: 1, y: -1, anchor: .center)
            .listRowInsets(EdgeInsets())
            .padding(5)
    }

}

и ObservableObject


class ChatVM: ObservableObject {
    private let managedObjectContext: NSManagedObjectContext
    private let sessionService = SessionService.shared
    private let socketIO = SocketIOManager.sharedInstance
    @Published var room: RoomCD

//    Image
    @Published var imageSelected: UIImage? = nil
    @Published var showImagePicker: Bool = false
    @Published var isImageEditing: Bool = false
//    Doc
    @Published var showDoc: Bool = false
    @Published var isLoading = false
    @Published var urlFile:URL? = nil

//    Camera
    @Published var showCameraPicker: Bool = false

//    IncidentView
    @Published var showIncidentView: Bool = false

//    Video
    @State var dataFile: Data? = nil

    init(room: RoomCD) {
        let context = AppDelegate.shared.persistentContainer.viewContext
        self.managedObjectContext = context
        self.room = room
    }

    func sendMessage(text: String) {
        let text = text.trimmingCharacters(in: .whitespacesAndNewlines)
        let message = self.handleSendMessage(text: text)

        self.sendToServer(text, message)

        self.imageSelected = nil
        self.dataFile = nil
        self.urlFile = nil
    }

    func handleSendMessage(text: String) -> MessageCD {
        let message = MessageCD(context: self.managedObjectContext)
        message.text = text
        message.isMyMessage = true
        message.id = UUID()
        message.status = 0
        message.createdAt = Date()
        message.room = room
        if let userS = self.sessionService.user,
            let userOwner = userS.getUserDB() {
            message.owner = userOwner
        }
        room.addToMessages(message)
        room.lastMessage = message
        room.lastActivity = Date()
        return message
    }

    func sendToServer(_ text: String, _ message: MessageCD) {
        var param = JsonDictionary()
        param["room"] = room.m_id ?? ""
        param["text"] = text
        DispatchQueue.global(qos: .background).async {

                APICaller.shared.callSendMessage(params: param) { (isSuccess, messageStr, json) in
                    print("json js", json)
                    DispatchQueue.global(qos: .background).async {
                        guard let newMessageJs = json["message"] as? JsonDictionary else {
                            return
                        }
                        self.managedObjectContext.perform {
                            message.initFrom(json: newMessageJs)
                            message.status = 2
                            self.managedObjectContext.saveIfNeeded()
                            self.socketIO.sendMessage(dataJs: json)
                        }
                    }
                }
    }
}

1 Ответ

0 голосов
/ 18 мая 2020
List(items, id: \.self) {
    Text("Item \($0)")
}
.id(UUID())

https://www.hackingwithswift.com/articles/210/how-to-fix-slow-list-updates-in-swiftui

...