Access environment variable inside global function - SwiftUI + CoreData
Possible approach is to use shared instance, like
class GlobalVariableClass: ObservableObject {
static var shared = GlobalVariableClass() // << here !!
@Published var itemObjects: [NSManagedObject] = []
}
so you can use it
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var globalVariables = GlobalVariableClass.shared
and
do {
let results = try managedContext.fetch(fetchRequest)
// make sure to modify itemObjects always in main queue
DispatchQueue.main.async { // << must !!
GlobalVariableClass.shared.itemObjects = results
}
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
Access and modify a @EnvironmentObject on global functions
You could change the signature of the global functions to allow receiving the model:
func loadFiles(dataModel: DataModel) { ... }
This way, you have access to the model instance within the function, what's left to do is to pass it at the call site:
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(self.dataModel)
.onAppear {
loadFiles(dataModel: self.dataModel)
}
You can do the same if the global functions calls originate from the views.
Trying to access/modify SwiftUI variable from within a function
I moved the get request to its own class so we can leverage ObservableObject
and Publish
the data. Publishing the data allows the subscribing views to update data when the published data changes. In this case, your ContentView
is subscribing to the data via the @ObservedObject var geoData: ResponseData
line of code.
Additionally, I added how to access two pieces of relevant data in your view, and displayed it in a list for easy reading. This should give you an idea of how to access/display the data.
Hopefully this provides enough information for you to tweak the answer to get it work the way you desire.
import SwiftUI
struct GeoService: Codable {
var status: String?
var results: [GeoResult]?
}
struct GeoResult: Codable {
struct Geometry: Codable {
struct Location: Codable {
let lat: Float
let lng: Float
init() {
lat = 32
lng = 30
}
}
let location: Location
}
let formatted_address: String
let geometry: Geometry
}
struct ContentView: View {
@ObservedObject var geoData: ResponseData
var body: some View {
NavigationView {
if #available(iOS 15.0, *) {
List {
Text(geoData.geoResultsData?.results?[0].formatted_address ?? "Loading")
Text(String(geoData.geoResultsData?.results?[0].geometry.location.lat ?? 0))
}
.navigationTitle("Quotes")
.task {
await geoData.handleData()
print(geoData.geoResultsData, "yessssss")
}
} else {
Text("failure")
}
}
}
}
class ResponseData: ObservableObject {
@Published var geoResultsData: GeoService?
func handleData() async {
let geoResult="""
{
"results": [
{
"formatted_address": "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA",
"geometry": {
"location": {
"lat": 37.4224764,
"lng": -122.0842499
}
}
},
{
"formatted_address": "Test addresss",
"geometry": {
"location": {
"lat": 120.32132145,
"lng": -43.90235469
}
}
}
],
"status": "OK"
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
print("executing handleData()")
do {
let obj = try decoder.decode(GeoService.self, from: geoResult)
geoResultsData = obj
} catch {
print("Did not work :(")
}
}
}
EDIT:
You will need to initialize some data within your app. You can initialize it as empty for the time being, if desired. This can be done by doing something like the following: ContentView(geoData: ResponseData.init())
How to access an @State variable inside a separate function
You should pass arguments inside view, like
Button(action: {
// here you have access to all view's internal states
createUser(withEmail: email, password: password, username: username) // << here !!
}, label: {
Text("Sign Up")
How to access a variable of an instance of a view in ContentView SwiftUI?
For whatever reason it is needed technically it is possible to do via callback closure.
Caution: the action in such callback should not lead to refresh sender view, otherwise it would be just either cycle or value lost
Here is a demo of usage & solution. Tested with Xcode 11.4 / iOS 13.4
ViewName { sender in
print("Use value: \(sender.vm.text)")
}
and
struct ViewName: View {
@ObservedObject var vm = ViewNameViewModel()
var callback: ((ViewName) -> Void)? = nil // << declare
var body: some View {
HStack {
TextField("Enter:", text: $vm.text)
}.onReceive(vm.$text) { _ in
if let callback = self.callback {
callback(self) // << demo of usage
}
}
}
}
class ViewNameViewModel: ObservableObject {
@Published var text: String = ""
}
Use of unresolved identifier when declaring variable inside a function declaration in SwiftUI
If you don't care about the result of a TextField, you can pass it a .constant
. You also need to return the TextField, however, so that the caller can use it.
func FieldText() -> some View {
TextField("Type here", text: .constant(""))
}
How do I access and use an entity using Core Data
The key missing piece from the above example are NSManagedObject subclasses, and in Swift, the @NSManaged
Swift annotation. NSManagedObject is a generic class which, in its most simple form, can be extended to simply provide access to attributes of a Core Data entity, but in reality this is where traditional model logic should live.
Creating NSManagedObject Subclasses
You can automatically generate these objects by viewing the Core Data model, and using the menu command: Editor->Create NSManagedObject Subclass
.
This will generate Job.swift
(or whatever your entity name is)
import Foundation
import CoreData
class Job: NSManagedObject {
@NSManaged var dateCreated: NSDate
@NSManaged var salary: NSNumber
}
Using NSManagedObject Subclasses
Your new class is now available for use, and you can typecast the fetched result accordingly! For completion, here's the updated version of the previously broken example
import UIKit
import CoreData
class JobViewController: UIViewController {
@IBOutlet var salaryLabel: UILabel!
let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext
func updateLabel() {
var job:Job = getCurrentJob()
salaryLabel.text = job.salary // ERRORS
}
func getCurrentJob()->Job {
var error: NSError?
if let fetchedResults = managedObjectContext!.executeFetchRequest(NSFetchRequest(entityName:"Job"), error: &error) {
return fetchedResults[0]
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Related Topics
Sandbox Entitlement to Script Itunes via Nsapplescript
Create Skspritenode with an Asset Programmatically
Mkpolyline Broken When Using Type Satelliteflyover
Decrypting Des with Commoncrypto in Swift 3
Preload a Scene to Prevent Lag
How to Show Cluster for Mkpolyline with Geojson Data View in iOS Swift
How to Access Camera with Swiping Gesture
Get Children of Children in Firebase Using Swift
Swift Corebluetooth Reading a Float Array from Ble
Issues While Lightweight Core Data Migration
Allow Siri Remote Menu Button When Play/Pause Button Is Overridden
How to Get The Range of The First Line in a String
How to Custom The Image of Mkannotation Pin
Abstract Class and Abstract Function in Swift
How to Read a File from The Filesystem in a Swift Command Line App