Observe property change in custom view SwiftUI - view

I created a custom view, NetworkImage, to load image asynchronously.
import Combine
import SwiftUI
struct NetworkImage<Placeholder: View>: View {
#StateObject private var viewModel = NetworkImageViewModel()
let url: String?
let placeholder: Placeholder
let saveLocally:Bool
init(_ url: String?, #ViewBuilder placeholder: () -> Placeholder, saveLocally:Bool = false) {
self.url = url
self.placeholder = placeholder()
self.saveLocally = saveLocally
}
func loadImage(_ url:String?) {
if let url = url {
viewModel.loadImage(from: url, saveLocally: saveLocally)
}
}
var body: some View {
Group {
if let uiImage = viewModel.image {
Image(uiImage: uiImage)
.resizable()
} else {
placeholder
}
}
.onAppear {
if let url = url {
viewModel.loadImage(from: url, saveLocally: saveLocally)
}
}
}
}
I use this in my views and it works really well. But now I would like to be able to replace the image with a new one each time the url change.
How can I do that? How can I pass a #Published property of my view's viewmodel to this NetworkImage view and make it work?
Thanks

Use the onChange modifier to see if the url parameter has changed:
struct NetworkImage<Placeholder: View>: View {
#StateObject private var viewModel = NetworkImageViewModel()
let url: String?
let placeholder: Placeholder
let saveLocally:Bool = false
func loadImage(_ url:String?) {
if let url = url {
viewModel.loadImage(from: url, saveLocally: saveLocally)
}
}
var body: some View {
Group {
if let uiImage = viewModel.image {
Image(uiImage: uiImage)
.resizable()
} else {
placeholder
}
}
.onAppear {
self.loadImage(url)
}
.onChange(of: url) { url in
self.loadImage(url)
}
}
}

Related

Unable to place Bool value in a toggle in swiftui

Hey all I have been trying to fix this issue for 2 days now and just can't seem to get what I am lookinhg for.
My working code:
struct User: Decodable {
let name: String
let description: String
let isOn: Bool
}
struct ContentView: View {
#State var users = [User]()
var body: some View {
List{
ForEach(users, id: \.name) { item in
HStack {
Toggle(isOn: .constant(true)) {
Label {
Text(item.description)
} icon: {
//list.img
}
}
}.padding(7)
}
}
.onAppear(perform: loadData)
}
func loadData() {
guard let url = URL(string: "https://-----.---/jsontest.json") else {
print("Invalid URL")
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) {data, response, error in
if let data = data {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
if let decodedResponse = try?
decoder.decode([User].self, from: data) {
DispatchQueue.main.async {
self.users = decodedResponse
}
return
}
}
print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
}.resume()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
the Json its pulling looks like this:
{
"name": "J",
"description": "Echo Show",
"isOn": true
},...
Like I said above this code works as-is. Where the problem I am having comes into play is the toggle part. It doesn't seem to be happens with the item.isOn for seeing if its true or false. The only thing it likes is the .constant(). Naturally this will not work for my case due to me needing to change the toggles to either true or false.
If it's anything other than .constant it has the error of:
Cannot convert value of type 'Bool' to expected argument type 'Binding'
I can perhaps if I do this
#State var ison = false
var body: some View {
List{
ForEach(users, id: \.name) { item in
HStack {
Toggle(isOn: $ison)) {
That seems to take that error away.... but how can it get the value thats looping for isOn that way?
What am I missing here?
try this approach, making isOn a var in User, and using bindings, the $ in the ForEach and Toggle, works for me:
struct User: Decodable {
let name: String
let description: String
var isOn: Bool // <-- here
}
struct ContentView: View {
#State var users = [User]()
var body: some View {
List{
ForEach($users, id: \.name) { $item in // <-- here
HStack {
Toggle(isOn: $item.isOn) { // <-- here
Label {
Text(item.description)
} icon: {
//list.img
}
}
}.padding(7)
}
}
.onAppear(perform: loadData)
}
func loadData() {
guard let url = URL(string: "https://-----.---/jsontest.json") else {
print("Invalid URL")
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) {data, response, error in
if let data = data {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
if let decodedResponse = try?
decoder.decode([User].self, from: data) {
DispatchQueue.main.async {
self.users = decodedResponse
}
return
}
}
print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
}.resume()
}
}

Passing a Value from App to ContentView in SwiftUI

I find a lot of resources out there as to how to let the user select a menu item and then open a folder. The following is what I have.
import SwiftUI
#main
struct Oh_My_App: App {
var body: some Scene {
WindowGroup {
ContentView()
.frame(width: 480.0, height: 320.0)
}.commands {
CommandGroup(after: .newItem) {
Button {
if let url = showFileOpenPanel() {
print(url.path)
}
} label: {
Text("Open file...")
}
.keyboardShortcut("O")
}
}
}
func showFileOpenPanel() -> URL? {
let openPanel = NSOpenPanel()
openPanel.canChooseDirectories = true
openPanel.canCreateDirectories = false
openPanel.canChooseFiles = false
openPanel.title = "Selecting a folder..."
openPanel.message = "Please select a folder containing one or more files."
let response = openPanel.runModal()
return response == .OK ? openPanel.url : nil
}
}
Okay. That's no problem. I can print the file path. Well, my actual question is how to return this value to ContentView? It is ContentView that is virtually running the show in this sample application. So I use ObservableObject as follows.
import SwiftUI
#main
struct Oh_My_App: App {
#StateObject var menuObservable = MenuObservable()
#NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}.commands {
CommandGroup(after: .newItem) {
Button {
menuObservable.openFile()
} label: {
Text("Open file...")
}
.keyboardShortcut("O")
}
}
}
}
class MenuObservable: ObservableObject {
#Published var fileURL: URL = URL(fileURLWithPath: "")
func openFile() {
if let openURL = showFileOpenPanel() {
fileURL = openURL
}
}
func showFileOpenPanel() -> URL? {
let openPanel = NSOpenPanel()
openPanel.canChooseDirectories = true
openPanel.canCreateDirectories = false
openPanel.canChooseFiles = false
openPanel.title = "Selecting a folder..."
openPanel.message = "Please select a folder containing one or more files."
let response = openPanel.runModal()
return response == .OK ? openPanel.url : nil
}
}
// ContentView.swift //
import SwiftUI
struct ContentView: View {
#ObservedObject var menuObservable = MenuObservable()
#State var filePath: String = ""
var body: some View {
ZStack {
VStack {
Text("Hello: \(filePath)")
}.onChange(of: menuObservable.fileURL) { newValue in
filePath = newValue.path
}
}
}
}
My ContentView won't get updated. So how do I get ContentView to receive a value from the menu call from App? Thanks.
Right now, you're creating a new instance of MenuObservable in ContentView, so it doesn't have any connection to the instance that received the menu command. You need to pass a reference to your existing instance (ie the one owned by Oh_My_App).
In your ContentView, change #ObservedObject var menuObservable = MenuObservable() to:
#ObservedObject var menuObservable : MenuObservable
And in your Oh_My_App:
WindowGroup {
ContentView(menuObservable: menuObservable)
}

Update list after HTTP POST request in SwiftUI

I want to add an object to a local server and then see the updated list in my view.
I have a ViewModelClass that handles the REST requests:
class CupcakeViewModel : ObservableObject {
let objectWillChange = PassthroughSubject<CupcakeViewModel,Never>()
init() {
get()
}
var cupcakes : [Cupcake] = [Cupcake]() {
didSet {
objectWillChange.send(self)
}
}
static let url = URL(string: "http://localhost:1337/cupcakes")!
func get() {
URLSession.shared.dataTask(with: CupcakeViewModel.url) { (data, response, error) in
if let data = data {
do {
print(data)
let cupcakes = try JSONDecoder().decode([Cupcake].self, from: data)
DispatchQueue.main.async {
self.cupcakes = cupcakes
}
} catch {
print("ERROR")
}
}
}.resume()
}
func post(cupcake : Cupcake) {
AF.request(CupcakeViewModel.url, method: .post, parameters: cupcake, encoder: JSONParameterEncoder.default).responseDecodable { (response: DataResponse<Cupcake, AFError>) in
if let value = response.value {
DispatchQueue.main.async {
self.cupcakes.append(value)
}
}
}
}
}
and in my MainView I have:
struct CupcakesView: View {
#ObservedObject var VM = CupcakeViewModel()
#State var showed = false
var body: some View {
NavigationView {
List(VM.cupcakes,id:\.self) {cupcake in
Text(cupcake.gusto)
}.padding(.top,1)
.sheet(isPresented: $showed, content: {
AggiungiCupcake(showed: self.$showed)
})
.navigationBarItems(trailing:
Button(action: {
self.showed = true
}) {
Text("ADD")
}
)
}
}
}
struct AggiungiCupcake : View {
#State var gusto = ""
#State var prezzo : Float = 0
#Binding var showed : Bool
#ObservedObject var VM = CupcakeViewModel()
var body : some View {
VStack {
TextField("Gusto", text: $gusto)
TextField("Prezzo", value: $prezzo, formatter: NumberFormatter())
Button(action: {
let c = Cupcake(gusto: self.gusto, prezzo: self.prezzo)
self.VM.post(cupcake: c)
self.showed = false
}) {
Text("ADD")
}
}.padding(30)
}
}
Both the get and the post requests go fine and on my server everything is updated, but my view does not add the new Object in the list. I use AlamoFire (AF) for the post request.
Anyone can help?
I think the issue is probably that you are calling send on your publisher in a didSet observer, rather than in a willSet observer. As the publisher name implies, you need to do this before your changes are made.
Try changing:
didSet {
objectWillChange.send(self)
}
to this:
willSet {
objectWillChange.send(self)
}

Why does my TabView change back to Home tab when image loads?

I created a TabView with two tabs. One is Home and the other loads text and an image from NASA pic of the day API. When I change to the NASA pic of the day, I see "Loading data" until the data loads. Once the data is loaded, for some reason the tab switches back to the "Home" tab. After this bug happens, I can switch back and forth between the two tabs normally and everything is loaded. Why does the tab get switched back to the home tab? Thank you!!
APIImageView Code:
import SwiftUI
struct ApiImageView: View {
#ObservedObject var apiImage = ApiImage()
var body: some View {
Group {
if apiImage.dataHasLoaded {
VStack {
Text(apiImage.title!)
.font(.largeTitle)
Image(uiImage: apiImage.image!).resizable()
.cornerRadius(10)
.padding()
ScrollView(.vertical, showsIndicators: false) {
Text(apiImage.explanation!)
.font(.subheadline)
.padding()
}
}
} else {
Text("Loading Data")
}
}.onAppear {
self.apiImage.loadImageFromApi(urlString: "https://api.nasa.gov/planetary/apod?api_key=eaRYg7fgTemadUv1bQawGRqCWBgktMjolYwiRrHK")
}
}
}
struct ApiImageView_Previews: PreviewProvider {
static var previews: some View {
ApiImageView()
}
}
APIImage Code:
import SwiftUI
class ApiImage: ObservableObject {
#Published var dataHasLoaded = false
#Published var image: UIImage? = nil
#Published var title: String? = nil
#Published var explanation: String? = nil
}
extension ApiImage {
func loadImageFromApi(urlString: String) {
let url = URL(string: urlString)!
var request = URLRequest(url: url)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request, completionHandler: parseJsonObject)
task.resume()
}
func parseJsonObject(data: Data?, urlResponse: URLResponse?, error: Error?) {
guard error == nil else {
print("\(error!)")
return
}
guard let content = data else {
print("No data")
return
}
let json = try! JSONSerialization.jsonObject(with: content)
let jsonmap = json as! [String : Any]
let titleText = jsonmap["title"] as! String
let explanationText = jsonmap["explanation"] as! String
let urlString = jsonmap["url"] as! String
print("\(urlString)")
print("\(titleText)")
print("\(explanationText)")
DispatchQueue.main.async {
self.title = titleText
self.explanation = explanationText
}
let url = URL(string: urlString)!
var request = URLRequest(url: url)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request, completionHandler: setImageFromData)
task.resume()
}
func setImageFromData(data: Data?, urlResponse: URLResponse?, error: Error?) {
guard error == nil else {
print("\(error!)")
return
}
guard let content = data else {
print("No data")
return
}
DispatchQueue.main.async {
self.image = UIImage(data: content)
self.dataHasLoaded = true
}
}
}
MainTabView Code:
import SwiftUI
struct MainTabView: View {
var body: some View {
TabView {
CategoryHome()
.tabItem {
Image(systemName: "house.fill")
Text("Landmarks")
.tag(0)
}
ApiImageView()
.tabItem {
Image(systemName: "flame.fill")
Text("NASA Pic")
//.tag(1)
}
}
}
}
struct MainTabView_Previews: PreviewProvider {
static var previews: some View {
MainTabView()
}
}
Maybe not directly a solution, but also important: it seems that the MainTabView is not entirely correct (the .tag() should be outside the .tabItem closure). This would be a correct version:
import SwiftUI
struct MainTabView: View {
var body: some View {
TabView {
CategoryHome()
.tabItem {
Image(systemName: "house.fill")
Text("Landmarks")
}.tag(0)
ApiImageView()
.tabItem {
Image(systemName: "flame.fill")
Text("NASA Pic")
}.tag(1)
}
}
}
struct MainTabView_Previews: PreviewProvider {
static var previews: some View {
MainTabView()
}
}
Maybe this is already the solution; if not, I hope it is still helpful! :)

Change State with DocumentPicker SwiftUI

I'm trying to get a List View to appear after selecting a document with documentPicker. Getting the following error...
Fatal error: No ObservableObject of type Switcher found.
A View.environmentObject(_:) for Switcher may be missing as an ancestor of this view.: file /BuildRoot/Library/Caches/com.apple.xbs/Sources/Monoceros/Monoceros-30.4/Core/EnvironmentObject.swift, line 55
It seems like I should use an EnviromentObject binding to have all views be able to read, access and update the Switcher class. Under the Coordinator Class in CSVDocumentPicker.swift is where things seem to go wrong.
I'm using #EnvironmentObject var switcher:Switcher and using the documentPicker function to toggle the switcher state so the Lists View will be displayed. I'm stumped.
SceneDelegate.swift
import UIKit
import SwiftUI
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
var switcher = Switcher()
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let contentView = ContentView().environmentObject(Switcher())
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView.environmentObject(switcher))
self.window = window
window.makeKeyAndVisible()
}
}
func sceneDidDisconnect(_ scene: UIScene) {
}
func sceneDidBecomeActive(_ scene: UIScene) {
}
func sceneWillResignActive(_ scene: UIScene) {
}
func sceneWillEnterForeground(_ scene: UIScene) {
}
func sceneDidEnterBackground(_ scene: UIScene) {
}
}
CSVDocumentPicker.swift
import Combine
import SwiftUI
class Switcher: ObservableObject {
var didChange = PassthroughSubject<Bool, Never>()
var isEnabled = false {
didSet {
didChange.send(self.isEnabled)
}
}
}
struct CSVDocumentPicker: View {
#EnvironmentObject var switcher:Switcher
#State private var isPresented = false
var body: some View {
VStack{
Text("csvSearch")
Button(action: {self.isPresented = true
})
{Text("import")
Image(systemName: "folder").scaledToFit()
}.sheet(isPresented: $isPresented) {
() -> DocumentPickerViewController in
DocumentPickerViewController.init(onDismiss: {
self.isPresented = false
})
}
if switcher.isEnabled {
ListView()
}
}
}
}
struct CSVDocumentPicker_Previews: PreviewProvider {
static var previews: some View {
CSVDocumentPicker().environmentObject(Switcher())
}
}
/// Wrapper around the `UIDocumentPickerViewController`.
struct DocumentPickerViewController {
private let supportedTypes: [String] = ["public.item"]
// Callback to be executed when users close the document picker.
private let onDismiss: () -> Void
init(onDismiss: #escaping () -> Void) {
self.onDismiss = onDismiss
}
}
// MARK: - UIViewControllerRepresentable
extension DocumentPickerViewController: UIViewControllerRepresentable {
typealias UIViewControllerType = UIDocumentPickerViewController
func makeUIViewController(context: Context) -> DocumentPickerViewController.UIViewControllerType {
let documentPickerController = UIDocumentPickerViewController(documentTypes: supportedTypes, in: .import)
documentPickerController.allowsMultipleSelection = false
documentPickerController.delegate = context.coordinator
return documentPickerController
}
func updateUIViewController(_ uiViewController: DocumentPickerViewController.UIViewControllerType, context: Context) {}
// MARK: Coordinator
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UIDocumentPickerDelegate, ObservableObject {
#EnvironmentObject var switcher:Switcher
var parent: DocumentPickerViewController
init(_ documentPickerController: DocumentPickerViewController) {
parent = documentPickerController
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
globalPathToCsv = url
loadCSV()
switcher.isEnabled.toggle()
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
parent.onDismiss()
}
}
}
ContentView.swift
import SwiftUI
import UIKit
var globalPathToCsv:URL!
var csvArray = [[String:String]]()
var csv = CSVaccessability()
func loadCSV(){
csv.csvToList()
// print(csvArray)
}
struct ContentView: View {
#EnvironmentObject var switcher:Switcher
var body: some View {
VStack{
CSVDocumentPicker().environmentObject(Switcher())
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environmentObject(Switcher())
}
}
ListView.swift
import SwiftUI
struct ListView: View {
var body: some View {
HStack{
List {
ForEach(csvArray, id:\.self) { dict in Section {DataList(dict: dict)} }
}
}}
}
struct DataList : View {
#State var dict = [String: String]()
var body: some View {
let keys = dict.map{$0.key}
let values = dict.map {$0.value}
return ForEach(keys.indices) {index in
HStack {
Text(keys[index])
Text("\(values[index])")
}
}
}
}
struct ListView_Previews: PreviewProvider {
static var previews: some View {
ListView()
}
}
CSVaccessability.swift
import Foundation
import SwiftCSV
var csvData:[[String]]!
var headers:[String] = []
class CSVaccessability {
var numberOfColumns:Int!
var masterList = [[String:Any]]()
func csvToList(){
if let url = globalPathToCsv {
do {
print(url)
let csvFile: CSV = try CSV(url: globalPathToCsv)
let csv = csvFile
//print(stream)
//print(csvFile)
headers = csv.header
csvArray=csv.namedRows
} catch {print("contents could not be loaded")}}
else {print("the URL was bad!")}
}
}
I've imported SwiftCSV for this project...
Created a new class...
ToggleView.swift
import Foundation
class ToggleView: ObservableObject {
#Published var toggleView: Bool = false
}
Added the Environment Object to ContentView.swift
#EnvironmentObject var viewToggle: ToggleView
Also added .environmentObject(ToggleView()) to any view that would be called and cause a crash the crash logs helped with this...
Text("csvSearch")
Button(action: {self.isPresented = true
self.viewToggle.toggleView.toggle()
// self.switcher = true
})
{Text("import")
Image(systemName: "folder").scaledToFit()
}.sheet(isPresented: $isPresented) {
() -> DocumentPickerViewController in
DocumentPickerViewController.init()
}
if self.picker {
DocumentPickerViewController().environmentObject(ToggleView())
}
if self.viewToggle.toggleView{
ListView()
}
}
}
}
Did you ever get this working? The only problem I found was with the line var csv = CSVaccessability() in the ContentView. CSVaccessability does not exist.
This is my solution for the Catalyst app for Mac, but to avoid pressing theImage (systemName: "book")button a second time to update the data in the text fields, I have implemented a hidden view in GeoFolderReadFileView to force the view update.
//File: GeoFolderCodStruct
import Foundation
struct GeoFolderCodStruct:Codable {
var isActive:Bool = true
var dataCreazione:Date = Date()
var geoFolderPath:String = ""
var nomeCartella:String = ""
var nomeCommittente:String = ""
var nomeArchivio:String = ""
var note:String = ""
var latitudine:Double? = nil
var longitudine:Double? = nil
var radiusCircle:Int16? = nil
//Roma 42.1234 13.1234
}
//File: PickerForReadFile
import SwiftUI
final class PickerForReadFile: NSObject, UIViewControllerRepresentable, ObservableObject {
#Published var geoFolder = GeoFolderCodStruct()
lazy var viewController:UIDocumentPickerViewController = {
let vc = UIDocumentPickerViewController(documentTypes: ["geof"], in: .open)
vc.allowsMultipleSelection = false
vc.delegate = self
return vc
}()
func makeUIViewController(context: UIViewControllerRepresentableContext<PickerForReadFile>) -> UIDocumentPickerViewController {
viewController.delegate = self
return viewController
}
func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: UIViewControllerRepresentableContext<PickerForReadFile>) {
print("updateUIViewController")
}
}
extension PickerForReadFile: UIDocumentPickerDelegate {
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
if urls.count > 0 {
DispatchQueue.main.async {
let url = urls[0]
do {
let data = try Data(contentsOf: url)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(dateFormatter)
let jsonData = try decoder.decode(GeoFolderCodStruct.self, from: data)
self.geoFolder = jsonData
print("geoFolder: \(self.geoFolder.nomeArchivio)")
} catch {
print("error:\(error)")
}
}
}
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
controller.dismiss(animated: true) {
print("Cancel from picker view controller")
}
}
}
//File: GeoFolderReadFileView
import SwiftUI
struct GeoFolderReadFileView: View {
#ObservedObject var picker = PickerForReadFile()
#Binding var geoFolder: GeoFolderCodStruct
var body: some View {
VStack(alignment: .trailing){
Button(action: {
#if targetEnvironment(macCatalyst)
print("Press open file")
let vc = UIApplication.shared.windows[0].rootViewController!
vc.present(self.picker.viewController, animated: true) {
self.geoFolder = self.picker.geoFolder
}
#endif
}) {
Image(systemName: "book")
}
urlPickedView()
.hidden()
}
}
private func urlPickedView() -> some View {
DispatchQueue.main.async {
let geoF = self.picker.geoFolder
print("Committente: \(geoF.nomeCommittente) - Archivio: \(geoF.nomeArchivio)")
self.geoFolder = geoF
}
return TextField("", text: $geoFolder.geoFolderPath)
}
}
//File: ContentView
import SwiftUI
struct ContentView: View {
#State private var geoFolder = GeoFolderCodStruct()
var body: some View {
VStack {
HStack {
Text("Open GeoFolder File:")
.padding()
Spacer()
GeoFolderReadFileView(geoFolder: $geoFolder)
.padding()
}
.padding()
Group {
TextField("", text: $geoFolder.geoFolderPath)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
TextField("", text: $geoFolder.nomeCartella)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
TextField("", text: $geoFolder.nomeCommittente)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
TextField("", text: $geoFolder.nomeArchivio)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
TextField("", text: $geoFolder.note)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
}
.padding()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
and the last, the json file to read for test the code.
{
"nomeCommittente" : "Appple",
"note" : "Image from Cupertino (CA).",
"latitudine" : 37.332161,
"longitudine" : -122.030352,
"nomeCartella" : "Foto",
"geoFolderPath" : "\/Users\/cesare\/Desktop",
"radiusCircle" : 50,
"dataCreazione" : "20\/03\/2020",
"nomeArchivio" : "AppleCampus-Image",
"isActive" : true
}
I was unable to implement the solution proposed by #Mdoyle1. I hope someone can edit the code to make it work as it should, without create hidden view.

Resources