16.9 C
London
Thursday, May 16, 2024

ios – Stopwatch going into background when person interacts with totally different ingredient solely on pages utilizing SwiftData in SwiftUI


I’m constructing my first app retailer app, a knitting/crochet app.

In my app are tasks which can be saved to SwiftData. On these undertaking pages are counters, notepad and many others & a stopwatch choice.

I seen a bug that when the stopwatch is turned on and is counting high quality, if the person is to work together with say the counter, then the stopwatch hangs for a second then carries on.

I’ve tried totally different choices with attempting to save lots of any knowledge on a background thread, however that simply made the app sluggish and un-usable. I’m on the level of a lot confusion whether or not its the timer that has a difficulty, the database or certainly the counter

In my app there’s additionally fundamental counter that doesn’t save to the database. I added the timer view to verify if the identical bug occurs and it doesn’t. The stopwatch retains counting while the person interacts with the counter no points which makes me suspect that its one thing to do with the counter & the stopwatch knowledge being saved.

I’ve additionally tried a stopwatch class utilizing Date() as a substitute of Timer however that did the very same factor…am I going mad or is that this a factor with the information?

Right here is my Timer

import SwiftUI
import SwiftData


struct TimerView: View {
    
    var projectPart: MultiProjectParts?
    var singleProject: SingleProject?
    
    @State var isSingleProject: Bool
    @Surroundings(.modelContext) personal var context
    
    @State personal var timeElapsed: TimeInterval = 0
    @State personal var isRunning = false
    
    personal let timer = Timer.publish(each: 1, on: .principal, in: .widespread).autoconnect()

    
    var physique: some View {
        
        @State var updatedMultiTimer = projectPart?.timer
        @State var updatedSingleTimer = singleProject?.timer
        
        ZStack {
            RoundedRectangle(cornerRadius: 8)
                .fill(.white)
                .shadow(radius: 5)
                .body(width: 257, peak: 100)
            
            HStack(spacing: 36) {
                // Cease
                Button {
                   cease()
                } label: {
                    ZStack {
                        Circle()
                            .fill(.sunflower)
                            .body(width: 37)
                        
                        Picture(systemName: Constants.timerStop)
                            .resizable()
                            .aspectRatio(contentMode: .match)
                            .body(width: 30)
                            .foregroundStyle(.white)
                        
                    }
                }
                .padding(.main, 10)
                // Counter
                VStack (spacing:10) {
                    
                    Textual content(isSingleProject ? timeFormatted(time: updatedSingleTimer!) : timeFormatted(time: updatedMultiTimer!))
                        .font(.system(dimension: 24))
                        .foregroundStyle(.darkGreyText)
                        .body(width: 100, peak: 50)
                }
                
                // Play/pause
                Button {
                    if !isRunning {
                       begin()
                    }
                    
                    else if isRunning {
                        pause()
                    }
                   
                    
                } label: {
                    ZStack {
                        Circle()
                            .fill(.sunflower)
                            .body(width: 37)
                        
                        Picture(systemName: isRunning ? Constants.timerPause : Constants.timerPlay)
                            .resizable()
                            .aspectRatio(contentMode: .match)
                            .body(width: 30)
                            .foregroundStyle(.white)
                        
                    }
                }
                .padding(.trailing, 10)
                
            }
        }
        .onAppear {
            if projectPart?.timer ?? 0.0 > 0 {
                // If there's a reminiscence of a timer, load the reminiscence on seem
                timeElapsed = projectPart!.timer
            }
            if singleProject?.timer ?? 0.0 > 0 {
                timeElapsed = singleProject!.timer
            }
            
        }
        .onReceive(timer, carry out: { _ in
            if self.isRunning {
                if !isSingleProject {
                    
                self.timeElapsed += 1
                // Save to multi mannequin
                projectPart?.timer = timeElapsed
                attempt? context.save()
                    
                } else {
                    // Is a single undertaking
                    self.timeElapsed += 1
                    singleProject?.timer = timeElapsed
                    // Save to single mannequin
                    attempt? context.save()
                }
                
                
            } else if !self.isRunning && timeElapsed == 0 {
                if !isSingleProject {
                    // Save to multi mannequin
                    projectPart?.timer = timeElapsed
                    attempt? context.save()
                } else {
                    // Is a single undertaking
                    singleProject?.timer = timeElapsed
                    attempt? context.save()
                }
            }
        })
    }
    
// MARK: - Features
    /// Begin the timer
   personal func begin() {
       isRunning = true
    }
    
    /// Pause the timer
    personal func pause() {
        isRunning = false
    }
    
    /// Cease & reset the timer
   personal  func cease() {
       isRunning = false
       timeElapsed = 0
    }
    
    /// Format the timer for 00:00:00 string
    func timeFormatted(time: TimeInterval) -> String {
        let hours = Int(time) / 3600
        let minutes = Int(time.truncatingRemainder(dividingBy: 3600)) / 60
        let seconds = Int(time) % 60
        return String(format: Constants.timerFormat, hours, minutes, seconds)
    }
    
}

Right here is my counter view

import SwiftUI

struct CounterViewSingle: View {
    
    @Surroundings(.modelContext) personal var context
    
    @State var isSecondCounter: Bool
    
    @ObservedObject var settings = SettingsData()
    
    var singleProject: SingleProject?
    
    var isBasic: Bool
    
    @State personal var counterBasic = 00
    @State personal var singleCounter1 = 0
    @State personal var singleCounter2 = 0
    
    @State personal var startNumber = 0
    
    var physique: some View {
        
        ZStack {
            RoundedRectangle(cornerRadius: 8)
                .fill(.white)
                .shadow(radius: 5)
                .body(width: 257, peak: 100)
            
            HStack(spacing: 36) {
                // Minus
                Button {
                    if isBasic {
                        counterBasic -= settings.counterInterval
                    }
                    if !isBasic {
                        if !isSecondCounter {
                            singleCounter1 -= settings.counterInterval
                        } else if isSecondCounter {
                            singleCounter2 -= settings.counterInterval
                        }
                    }
                    // Save to mannequin
                    saveCounter(counter1: singleCounter1, counter2: singleCounter2)
                } label: {
                    ZStack {
                        Circle()
                            .fill(.sunflower)
                            .body(width: 37)
                        
                        Picture(systemName: Constants.counterMinus)
                            .resizable()
                            .aspectRatio(contentMode: .match)
                            .body(width: 30)
                            .foregroundStyle(.white)
                        
                    }
                }
                
                // Counter & Reset
                VStack (spacing:10) {
                    if isBasic {
                        Textual content("(counterBasic)")
                            .font(.system(dimension: 50))
                            .foregroundStyle(.darkGreyText)
                            .body(width: 95, peak: 50)
                    }
                    if !isBasic {
                        if isSecondCounter {
                            Textual content("(singleCounter2)")
                                .font(.system(dimension: 50))
                                .foregroundStyle(.darkGreyText)
                                .body(width: 95, peak: 50)
                        } else {
                            Textual content("(singleCounter1)")
                                .font(.system(dimension: 50))
                                .foregroundStyle(.darkGreyText)
                                .body(width: 95, peak: 50)
                        }
                    }
                    
                    // Reset
                    Button {
                        if isBasic {
                            counterBasic = settings.startNumberOfCounter
                        }
                        if !isBasic {
                            if !isSecondCounter {
                                singleCounter1 = startNumber
                            } else if isSecondCounter {
                                singleCounter2 = startNumber
                            }
                        }
                        // Save to mannequin
                        saveCounter(counter1: singleCounter1, counter2: singleCounter2)
                        
                    } label: {
                        ZStack {
                            RoundedRectangle(cornerRadius: 15)
                                .fill(.sunflower)
                                .body(width: 90, peak: 18)
                            Textual content(Constants.counterReset)
                                .font(.notesText)
                                .foregroundStyle(.darkGreyText)
                        }
                    }
                }
                
                // Plus
                Button {
                    if isBasic {
                        counterBasic += settings.counterInterval
                    }
                    if !isBasic {
                        if !isSecondCounter {
                            singleCounter1 += settings.counterInterval
                        } else if isSecondCounter {
                            singleCounter2 += settings.counterInterval
                        }
                    }
                    // Save to mannequin
                    saveCounter(counter1: singleCounter1, counter2: singleCounter2)
                } label: {
                    ZStack {
                        Circle()
                            .fill(.sunflower)
                            .body(width: 37)
                        
                        Picture(systemName: Constants.counterAdd)
                            .resizable()
                            .aspectRatio(contentMode: .match)
                            .body(width: 30)
                            .foregroundStyle(.white)
                        
                    }
                }
            }
        }
        .onAppear {
            /// Verify for knowledge being held for rely on tasks and verify person settings for adjustments
            // Verify for a undertaking first
            if !isBasic {
                
                // Load any reminiscence of counters
                if singleProject?.counter1 ?? 0 > 0 {
                    singleCounter1 = singleProject!.counter1
                }
                
                if singleProject?.counter2 ?? 0 > 0 {
                    singleCounter2 = singleProject!.counter2
                }
                
                // Type beginning quantity
                if settings.startNumberOfCounter != startNumber {
                    // Verify if the unique rely matched the previous begin quantity to then be reset for counter 1
                    if singleCounter1 == startNumber {
                        // Set the brand new baseline quantity
                        singleCounter1 = settings.startNumberOfCounter
                        // Set the brand new begin quantity
                        startNumber = settings.startNumberOfCounter
                    } 
                    // The baseline is already decrease than the person has set
                    else if singleCounter1 < settings.startNumberOfCounter {
                        // Set the brand new baseline quantity
                        singleCounter1 = settings.startNumberOfCounter
                        // Set the brand new begin quantity
                        startNumber = settings.startNumberOfCounter
                    }
                    else {
                        // Counter already in use, don't reset to new quantity however change the beginning quantity for the subsequent iteration
                        startNumber = settings.startNumberOfCounter
                    }
                    
                    // Verify if the unique rely matched the previous begin quantity to then be reset for counter 2
                    if singleCounter2 == startNumber {
                        // Set the brand new baseline quantity
                        singleCounter2 = settings.startNumberOfCounter
                        // Set the brand new begin quantity
                        startNumber = settings.startNumberOfCounter
                    } 
                    // The baseline is already decrease than the person has set
                    else if singleCounter2 < settings.startNumberOfCounter {
                        // Set the brand new baseline quantity
                        singleCounter2 = settings.startNumberOfCounter
                        // Set the brand new begin quantity
                        startNumber = settings.startNumberOfCounter
                    }
                    else {
                        // Counter already in use, don't reset to new quantity however change the beginning quantity for the subsequent iteration
                        startNumber = settings.startNumberOfCounter
                    }
                }
            } else {
                // Change fundamental counter to new begin quantity
                counterBasic = settings.startNumberOfCounter
            }
        }
    }
    /// Save counters to the database relying on what counters are being utilized by person
    func saveCounter(counter1: Int, counter2: Int) {
        if !isSecondCounter {
            singleProject?.counter1 = counter1
        } else if isSecondCounter {
            singleProject?.counter2 = counter2
        }
        
        attempt? context.save()
    }
}```

Latest news
Related news

LEAVE A REPLY

Please enter your comment!
Please enter your name here