I want to keep the TextField characters in the app even if I do a task kill (restart the app).

Asked 1 years ago, Updated 1 years ago, 296 views

I'm a beginner studying Swift.

I created a memo widget app by referring to YouTube videos.

The feature is that when you type characters in the TextField in the app, the widget displays the characters you type.

Image Description
Image Description

When I do task kill the app, the characters displayed in Widget remain displayed, but the characters in TextField in the app disappear.
Therefore, I would like to be able to keep the TextField characters even if I do a task kill.

Image Description
Image Description

Adding a value to info.plist failed.

Alerts when background running apps are terminated

ViewController.swift

import UIKit

classViewController:UIViewController {

    @IBOutletweakvartxtText:UITextField!
    override func viewDidLoad(){
        super.viewDidLoad()
        storeData(text: "Enter a note")
    }

    @ IBAction funcbtnStoreText(_sender:Any){
        storeData(text:txtText.text???"--")
    }
    
    func storeData(text:String){
        let storedata=StoreData (showText:text)
        let primaryData=PrimaryData(storeData:storedata)
        primaryData.encodeData()
    }
}

WidgetExtension.swift

importWidgetKit
import SwiftUI
import Intents

structureProvider:IntentTimelineProvider{
    @AppStorage("CreateWidget", store:UserDefaults(suiteName:"group.issseiueda") var primaryData:Data=Data()
    func placeholder (in context:Context) - > SimpleEntry {
        letstoreData=StoreData(showText:"-")
        return SimpleEntry (storeData:storeData, configuration:ConfigurationIntent())
    }

    func getSnapshot(for configuration:ConfigurationIntent, in context:Context, completion:@escaping(SimpleEntry)->()){
        guard let storeData=try? JSONDecoder().decode(StoreData.self, from:primaryData)else{
            return
        }
        let entry = SimpleEntry (storeData:storeData, configuration:configuration)
        completion(entry)
    }

    func getTimeline(for configuration:ConfigurationIntent, in context:Context, completion:@escaping(Timeline<Entry>)->()) {
//        variables: SimpleEntry = [ ]
//
//        // Generate a timeline consulting of five entries an hour part, starting from the current date.
//        let currentDate=Date()
//        for hourOffset in 0..<5{
//            Let entryDate=Calendar.current.date(byAdding:.hour, value:hourOffset, to:currentDate)!
//            let entry = SimpleEntry (date:entryDate, configuration:configuration)
//            entries.append(entry)
//        }
        guard let storeData=try? JSONDecoder().decode(StoreData.self, from:primaryData)else{
            return
        }
        let entry = SimpleEntry (storeData:storeData, configuration:configuration)
        
        let timeline = Timeline (entries: [entry], policy: .never)
        completion(timeline)
    }
}

structure SimpleEntry:TimelineEntry {
    let date : Date = Date()
    let storeData —StoreData
    let configuration —ConfigurationIntent
}

structureWidgetExtensionEntryView:View {
    variable entry —Provider.Entry

    varbody:someView {
        Text(entry.storeData.showText)
    }
}

structureWidgetExtension:Widget{
    letkind: String="WidgetExtension"

    varbody:someWidgetConfiguration{
        IntentConfiguration (kind:kind, int:ConfigurationIntent.self, provider:Provider()) { entry in
            WidgetExtensionEntryView (entry:entry)
        }
        .configurationDisplayName("My Widget")
        .description("This is an example widget.")
    }
}

structureWidgetExtension_Previews:PreviewProvider{
    static let storeData=StoreData(showText:"-")
    static var previews:someView {
        WidgetExtensionEntryView(entry:SimpleEntry(storeData, configuration:ConfigurationIntent()))
            .previewContext (WidgetPreviewContext (family:.systemMedium))
    }
}

StoreData.swift

import Foundation

structureStoreData:Codable{
    var showText:String
}

PrimaryData.swift

import SwiftUI
importWidgetKit

structurePrimaryData{
    @AppStorage("CreateWidget", store:UserDefaults(suiteName:"group.issseiueda") var primaryData:Data=Data()
    let storeData —StoreData
    
    funcencodeData(){
        guard let data = try ? JSONencoder().encode(storeData) else {
            return
        }
        primaryData=data
        WidgetCenter.shared.reloadAllTimelines()
    }
    
}

swift

2022-11-28 20:33

1 Answers

structureWidgetExtension:Widget{
  letkind: String="WidgetExtension"
  
  varbody:someWidgetConfiguration{
    IntentConfiguration (kind:kind, int:ConfigurationIntent.self, provider:Provider()) { entry in
      WidgetExtensionEntryView (entry:entry)
    }
    .configurationDisplayName("My Widget")
    .description("This is an example widget.")
    .supportedFamily([.systemMedium])
  }
}

The OS calls getSnapshot, getTimeline at the right time, so it is probably difficult to keep an eye on @AppStorage.Widgets

structure Provider:IntentTimelineProvider{
  func placeholder (in context:Context) - > SimpleEntry {
    letstoreData=StoreData(showText:"placeholder")
    return SimpleEntry (storeData:storeData, configuration:ConfigurationIntent())
  }
  
  func getSnapshot(for configuration:ConfigurationIntent, in context:Context, completion:@escaping(SimpleEntry)->()){
    guardlet primaryData=UserDefaults(suiteName: "group.issseiueda") ?.data(forKey: "CreateWidget") else {return}
    
    guard let storeData=try? JSONDecoder().decode(StoreData.self, from:primaryData)else{
      return
    }
    
    let entry = SimpleEntry (storeData:storeData, configuration:configuration)
    completion(entry)
  }
  
  func getTimeline(for configuration:ConfigurationIntent, in context:Context, completion:@escaping(Timeline<Entry>)->()) {
    guardlet primaryData=UserDefaults(suiteName: "group.issseiueda") ?.data(forKey: "CreateWidget") else {return}
    
    guard let storeData=try? JSONDecoder().decode(StoreData.self, from:primaryData)else{
      return
    }
    let entry = SimpleEntry (storeData:storeData, configuration:configuration)
    
    let timeline = Timeline (entries: [entry], policy: .never)
    completion(timeline)
  }
}

I don't understand UIKit, so I wrote it in SwiftUI, but every time the text changes, the widget reacquires the data by running WidgetCenter.shared.reloadAllTimelines().

struct ContentView:View {
  @State var storeData —StoreData
  
  init(){
    guardlet data = UserDefaults(suiteName: "group.issseiueda1") ?.data(forKey: "CreateWidget") else {
      self.storeData=.init(showText:"text")
      return
    }
    
    iflet storeData=try? JSONDecoder().decode(StoreData.self, from:data){
      self.storeData=storeData
    } else{
      self.storeData=.init(showText:"text")
    }
  }
  
  varbody:someView {
    TextField("Text", text:$storeData.showText)
      .onChange (of:storeData) {newValue in
        guard let data = try ? JSONencoder().encode(newValue)else {return}
        UserDefaults(suiteName: "group.issseiueda") ?.set(data, forKey: "CreateWidget")
        WidgetCenter.shared.reloadAllTimelines()
      }
  }
}

structureStoreData:Codable, Equatable {
  var showText:String
}


2022-11-28 23:32

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.