I have some code that takes a while to write to a database, so I have an activity indicator which only behaves properly the first time it's called. When the user causes this code to run again, the activity indictor only shows briefly once the database work has been finished, instead of during the database work.
The isShowing boolean variable is set to true on the main thread, and the database work is put onto a separate thread.
import SwiftUI
struct LanguagePickerWheel: View {
@State private var selectedLanguage: String = ""
@State private var isShowing = false
var availableLanguages: [String] = []
@Environment(\.presentationMode) var presentation
@Environment(\.managedObjectContext) private var viewContext
private func dismiss() {
self.presentation.wrappedValue.dismiss()
}
var body: some View {
GeometryReader { geometry in
VStack {
HStack {
Button("Cancel") { self.dismiss() }
.padding(.top)
.padding(.trailing, 125)
Button("Select") {
DispatchQueue.main.async {
isShowing = true
}
let queue = DispatchQueue(label: "work-queue-1", qos: .userInitiated)
queue.async {
if selectedLanguage == "" {
selectedLanguage = availableLanguages[0]
}
// submit language to the addAndSaveLanguage method
let newLanguage = Language(context: viewContext)
newLanguage.name = selectedLanguage
newLanguage.setAsRevision = false
PersistenceController.shared.saveDB()
do {
// This solution assumes you've got the file in your bundle
if let path = Bundle.main.path(forResource: "\(selectedLanguage)_English_Over_2500_Words", ofType: "txt") {
let data = try String(contentsOfFile:path, encoding: String.Encoding.utf8)
var arrayOfStrings: [String]
arrayOfStrings = data.components(separatedBy: ";")
for string in arrayOfStrings {
let newCommonWord = CommonWordThing(context: viewContext)
newCommonWord.native = string.components(separatedBy: "_")[1]
newCommonWord.foreign = string.components(separatedBy: "_")[0]
newCommonWord.ckimage = false
newCommonWord.inUse = false
newCommonWord.typingTestCorrect = 0
newCommonWord.arrangeWordsCorrect = 0
newCommonWord.ckreference = newLanguage.ckrecordname
newCommonWord.attempts = 0
newCommonWord.image = nil
newCommonWord.repetitionInterval = 0
newCommonWord.testsUntilPresented = 0
newCommonWord.setAsRevision = false
newCommonWord.language = newLanguage
var stringNumber = string.split(separator: "_")[2]
if stringNumber.contains("\r\n") {
stringNumber.removeLast(1)
}
newCommonWord.count = NumberFormatter().number(from: String(stringNumber) as String)?.int64Value ?? 0
}
}
} catch let err as NSError {
// do something with Error
print("Couldn't save new language to database: \(err)")
}
}
PersistenceController.shared.saveDB()
isShowing = false
self.dismiss()
}
.padding(.top)
.padding(.leading, 125)
}
Text("Choose a language:")
.font(.title)
.padding(.top, 50)
Picker("Choose a language:", selection: $selectedLanguage, content: {
ForEach(Array(availableLanguages), id: \.self) { language in
Text(language)
}
})
.pickerStyle(WheelPickerStyle())
.padding(.leading)
.padding(.trailing)
}
Text("Please wait, creating common words...")
.position(x: geometry.frame(in: .local).midX, y: geometry.frame(in: .local).midY)
.foregroundColor(isShowing ? .gray : .clear)
}
}
}
Code in queue is async soma be executed after end of Button action closure :
EDIT : removed the Task