0

In the view whose code you see below I have a button that calls the searchView function. It displays an alert and in it we enter the number by which we are looking for an object and this object is returned by the getSong function. Up to this point everything is working fine. The problem I have encountered is that it now calls view and passes this found object, but the view does not refresh. I must have made some mistake that I can't locate or that I have forgotten. I would appreciate some help with this.

DetailView:

import CoreData
import SwiftUI

struct DetailView: View {
    @State var song : Song
    @State var isSelected: Bool
    var body: some View {
        VStack{
            Text(song.content ?? "No content")
                .padding()
            Spacer()
        }
        .navigationBarTitle("\(song.number). \(song.title ?? "No title")", displayMode: .inline)
        .toolbar {
            ToolbarItemGroup(placement: .navigationBarTrailing) {
                HStack{
                    Button(action: {
                        song.favorite.toggle()
                        isSelected=song.favorite
                    }) {
                        Image(systemName: "heart.fill")
                            .foregroundColor(isSelected ? .red : .blue)
                    }
                    
                    Button(action: {
                        searchView()
                    }) {
                        Image(systemName: "magnifyingglass")
                    }
                }
            }
        }
    }
    func searchView(){
        
        let search = UIAlertController(title: "Go to the song", message: "Enter the number of the song you want to jump to.", preferredStyle: .alert)
        search.addTextField {(number) in
            number.placeholder = "Song number"
        }
        
        let go = UIAlertAction(title: "Go", style: .default) { (_) in
            let songFound = PersistenceController.shared.getSong(number: (search.textFields![0].text)!)
            DetailView(song: songFound!, isSelected: songFound!.favorite)
        }
        let cancel = UIAlertAction(title: "Cancel", style: .destructive) { (_) in
            print("Cancel")
        }
        search.addAction(cancel)
        search.addAction(go)
        
        UIApplication.shared.windows.first?.rootViewController?.present(search, animated: true, completion: {
           
        })
    }
}

struct SongDetail_Previews: PreviewProvider {
    static let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    static var previews: some View {
        let song = Song(context: moc)
        song.number=0
        song.title="Title"
        song.content="Content"
        song.author="Author"
        song.favorite=false
        return NavigationView {
            DetailView(song: song, isSelected: song.favorite)
        }
    }
}

PersistenceController:

import CoreData

struct PersistenceController {
    static let shared = PersistenceController()
    let container: NSPersistentContainer
    
    init() {
        container = NSPersistentContainer(name: "Model")
        container.loadPersistentStores { (description, error) in
            if let error = error {
                fatalError("Error \(error.localizedDescription)")
            }
        }
    }
    
    func save(completion: @escaping (Error?) -> () = {_ in}) {
        let context = container.viewContext
        if context.hasChanges {
            do {
                try context.save()
                completion(nil)
            } catch {
                completion(error)
            }
        }
    }
        
    func delete(_ object: NSManagedObject, completion: @escaping (Error?) -> () = {_ in}) {
        let context = container.viewContext
        context.delete(object)
        save(completion: completion)
    }
    
    func getSong(number: String) -> Song? {
        guard let songNumber = Int64(number) else { return nil }
        let context = container.viewContext
        let request = NSFetchRequest<Song>(entityName: "Song")
        request.predicate = NSPredicate(format: "number == %ld", songNumber)
        do {
            return try context.fetch(request).first
        } catch {
            print(error)
            return nil
        }
    }
}
oculorum
  • 49
  • 5
  • 2
    You are mixing up UIKit and SwiftUI code. Calling `DetailView(...` in a UIKit environment creates an instance and throws it away. I recommend to use SwiftUI to show the dialog with a Binding to `song` and `selected`. And – once again – don't force unwrap the result of `getSong`. – vadian Jul 24 '21 at 18:47
  • How to create an alert with a text field in SwiftUI? – oculorum Jul 27 '21 at 16:11
  • Please see https://stackoverflow.com/questions/56726663/how-to-add-a-textfield-to-alert-in-swiftui – vadian Jul 27 '21 at 16:21

0 Answers0