Unable to place Bool value in a toggle in swiftui - xcode

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()
}
}

Related

Struggling with rapid api and swiftui

Hi I am struggling with getting football data api from rapidapi to work in swift ui . here is the code below
The errors is get are "self.team = decodedTeams" Cannot find 'self' in scope"
and in my content view i get for " $network.getTeams"
Value of type 'EnvironmentObject.Wrapper' has no dynamic member 'getTeams' using key path from root type 'Network'
I have set out what i have in 2 pages of my swiftui code below
any help would be appreciated, I am really struggling with this one
// Network.swift
// Football Scores
//
//
import Foundation
class Network: ObservableObject {
#Published var teams: [Team] = []
}
func getTeams() {
let headers = [
"X-RapidAPI-Key": "MY API KEY",
"X-RapidAPI-Host": "api-football-v1.p.rapidapi.com"
]`
let request = NSMutableURLRequest(url: NSURL(string: "https://api-football-v1.p.rapidapi.com/v3/standings?season=2022&league=39")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
DispatchQueue.main.async {
do {
let decodedTeams = try JSONDecoder().decode([Team].self, from: data)
self.team = decodedTeams
} catch let error {
print("Error decoding: ", error)
}
}
}
})
dataTask.resume()
}
and
//
// Team.swift
// Football Scores
//
//
import Foundation
struct Team: Identifiable, Decodable {
var id: Int
var name: String
var logo: String
var points: String
var goaldif: String
}
and
// Football_ScoresApp.swift
// Football Scores
//
import SwiftUI
import Foundation
#main
struct Football_ScoresApp: App {
var network = Network()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(network)
}
}
}
and
import SwiftUI
import CoreData
struct ContentView: View {
#EnvironmentObject var network: Network
var body: some View {
ScrollView {
Text("All teams")
.font(.title).bold()
}
.onAppear {
network.getTeams()
}
VStack(alignment: .leading) {
ForEach(network.teams) { team in
HStack(alignment:.top) {
Text("\(team.id)")
VStack(alignment: .leading) {
Text(team.name)
.bold()
}
}
.frame(width: 300, alignment: .leading)
.padding()
.background(Color(#colorLiteral(red: 0.6667672396, green: 0.7527905703, blue: 1, alpha: 0.2662717301)))
.cornerRadius(20)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environmentObject(Network())
}
}
To display the teams from your api request, first you need to create a set of struct models that
represent the json data that the server is sending. From the server response, you need to
extract the teams information you want to display. Here is my code
that shows how to do it, works well for me, pay attention to the details:
struct ContentView: View {
#StateObject var network = Network() // <-- for testing
var body: some View {
List {
VStack(alignment: .leading) {
ForEach(network.teams) { team in
HStack(alignment:.top) {
Text("\(team.id)")
Text(team.name).bold()
}
.frame(width: 300, alignment: .leading)
.padding()
.background(Color(#colorLiteral(red: 0.6667672396, green: 0.7527905703, blue: 1, alpha: 0.2662717301)))
.cornerRadius(20)
}
}
}
.onAppear {
network.getTeams()
}
}
}
class Network: ObservableObject {
#Published var teams: [Team] = []
func getTeams() {
let token = "your-key" // <--- here your api key
guard let url = URL(string: "https://api-football-v1.p.rapidapi.com/v3/standings?season=2022&league=39") else { return }
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("\(token)", forHTTPHeaderField: "X-RapidAPI-Key")
request.setValue("api-football-v1.p.rapidapi.com", forHTTPHeaderField: "X-RapidAPI-Host")
URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else { return }
DispatchQueue.main.async {
do {
let results = try JSONDecoder().decode(FootyResponse.self, from: data)
// extract just the teams
for response in results.response {
for stand in response.league.standings {
for league in stand {
self.teams.append(league.team)
}
}
}
} catch {
print(error) // <-- here important
}
}
}.resume()
}
}
// MARK: - FootyResponse
struct FootyResponse: Codable {
let welcomeGet: String
let parameters: Parameters
let errors: [String]
let results: Int
let paging: Paging
let response: [Response]
enum CodingKeys: String, CodingKey {
case welcomeGet = "get"
case parameters, errors, results, paging, response
}
}
// MARK: - Paging
struct Paging: Codable {
let current, total: Int
}
// MARK: - Parameters
struct Parameters: Codable {
let league, season: String
}
// MARK: - Response
struct Response: Codable {
let league: League
}
// MARK: - League
struct League: Codable {
let id: Int
let name: String
let country: String
let logo: String
let flag: String
let season: Int
let standings: [[Standing]]
}
// MARK: - Standing
struct Standing: Codable {
let rank: Int
let team: Team
let points, goalsDiff: Int
let group: String
let form: String
let status: String
let standingDescription: String?
let all, home, away: All
let update: String // <-- Date
enum CodingKeys: String, CodingKey {
case rank, team, points, goalsDiff, group, form, status
case standingDescription = "description"
case all, home, away, update
}
}
// MARK: - All
struct All: Codable {
let played, win, draw, lose: Int
let goals: Goals
}
// MARK: - Goals
struct Goals: Codable {
let goalsFor, against: Int
enum CodingKeys: String, CodingKey {
case goalsFor = "for"
case against
}
}
// MARK: - Team
struct Team: Identifiable, Codable {
let id: Int
let name: String
let logo: String
}
EDIT-1:
to get the points of each team, you need to use the Standing struct. Here is an example code to do that.
struct ContentView: View {
#StateObject var network = Network()
var body: some View {
List {
VStack(alignment: .leading) {
ForEach(network.stand) { stand in // <-- here
HStack(alignment:.top) {
Text(stand.team.name).bold() // <-- here
Text("\(stand.points) points") // <-- here
}
.frame(width: 300, alignment: .leading)
.padding()
.background(Color(#colorLiteral(red: 0.6667672396, green: 0.7527905703, blue: 1, alpha: 0.2662717301)))
.cornerRadius(20)
}
}
}
.onAppear {
network.getTeams()
}
}
}
class Network: ObservableObject {
#Published var teams: [Team] = []
#Published var stand: [Standing] = [] // <-- here
func getTeams() {
let token = "your-key" // <--- here your api key
guard let url = URL(string: "https://api-football-v1.p.rapidapi.com/v3/standings?season=2022&league=39") else { return }
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("\(token)", forHTTPHeaderField: "X-RapidAPI-Key")
request.setValue("api-football-v1.p.rapidapi.com", forHTTPHeaderField: "X-RapidAPI-Host")
URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else { return }
DispatchQueue.main.async {
do {
let results = try JSONDecoder().decode(FootyResponse.self, from: data)
// extract the teams and the standings
results.response.forEach{ response in
response.league.standings.forEach{ stand in
self.stand = stand // <--- here
stand.forEach{ league in
self.teams.append(league.team)
}
}
}
} catch {
print(error) // <-- here important
}
}
}.resume()
}
}
// MARK: - Standing
struct Standing: Identifiable, Codable {
let id = UUID() // <-- here
let rank: Int
let team: Team
let points, goalsDiff: Int
let group: String
let form: String
let status: String
let standingDescription: String?
let all, home, away: All
let update: String // <-- Date
enum CodingKeys: String, CodingKey {
case rank, team, points, goalsDiff, group, form, status
case standingDescription = "description"
case all, home, away, update
}
}

Drag&Drop works with URL, but not with String – why?

In my code the drag&drop function works fine with URL objects. But the exact same code for String objects does not. I have tried with countless casts and loadItem instead of loadObject ... no luck so far.
Can anyone help me here? It would be very much appreciated.
code for URL objects – Working
.onDrag {
return NSItemProvider(object: item.url as NSURL)
}
.onDrop(of: [UTType.url], isTargeted: $isDropping) { providers in
_ = providers.first?.loadObject(ofClass: URL.self) { url, error in
if let error = error { print(error.localizedDescription) }
if let url = url {
DispatchQueue.main.async {
self.array2.insert(Item(title: "new", url: url), at: 0)
}
}
}
return true
}
the same with String does not:
.onDrag {
return NSItemProvider(object: item.title as NSString)
}
.onDrop(of: [UTType.text], isTargeted: $isDropping) { providers in
_ = providers.first?.loadObject(ofClass: String.self) { string, error in
if let error = error { print(error.localizedDescription) }
if let string = string {
DispatchQueue.main.async {
self.array2.insert(Item(title: string, url: URL(string: "http://www.apple.com")!), at: 0)
}
}
}
return true
}
full MRE code:
import SwiftUI
import UniformTypeIdentifiers
struct Item: Identifiable {
let id = UUID()
var title: String
var url: URL
}
struct ContentView: View {
#State var array1: [Item] = [
Item(title: "One", url: URL(string: "http://www.amazon.com")!),
Item(title: "Two", url: URL(string: "http://www.apple.com")!),
Item(title: "Three", url: URL(string: "http://www.example.com")!),
]
#State var array2: [Item] = []
#State var isDropping = false
var body: some View {
HStack(alignment: .top) {
VStack(alignment: .leading) {
ForEach(array1) { item in
Text(item.title)
Text(item.url.absoluteString).foregroundColor(.secondary)
// DRAG
.onDrag {
return NSItemProvider(object: item.url as NSURL) // WORKS
// return NSItemProvider(object: item.title as NSString) // DOES NOT WORK
}
}
}
.frame(maxWidth: .infinity)
Divider()
VStack(alignment: .leading) {
ForEach(array2) { item in
Text(item.title)
Text(item.url.absoluteString).foregroundColor(.secondary)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(isDropping ? .green : .gray)
// DROP with url/NSURL -- WORKS
.onDrop(of: [UTType.url], isTargeted: $isDropping) { providers in
_ = providers.first?.loadObject(ofClass: URL.self) { url, error in
if let error = error { print(error.localizedDescription) }
if let url = url {
DispatchQueue.main.async {
self.array2.insert(Item(title: "new", url: url), at: 0)
}
}
}
return true
}
// DROP with text/NSString -- DOES NOT WORK
.onDrop(of: [UTType.text], isTargeted: $isDropping) { providers in
_ = providers.first?.loadObject(ofClass: String.self) { string, error in
if let error = error { print(error.localizedDescription) }
if let string = string {
DispatchQueue.main.async {
self.array2.insert(Item(title: string, url: URL(string: "http://www.apple.com")!), at: 0)
}
}
}
return true
}
}
}
}
As always thanks to #Asperi and his answer here:
SwiftUI: Not getting dropped NSString value in DropDelegate
This now works:
.onDrop(of: [UTType.utf8PlainText], isTargeted: $isDropping) { providers in
_ = providers.first?.loadItem(forTypeIdentifier: "public.utf8-plain-text") { data, error in
if let error = error { print(error.localizedDescription) }
if let data = data as? Data {
DispatchQueue.main.async {
let string = NSString(data: data, encoding: 4) ?? "failed"
print(string)
self.array2.insert(Item(title: string as String, url: URL(string: "http://www.apple.com")!), at: 0)
}
}
}
return true
}

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)
}

Update SwiftUI List after network request using RxSwift

I need to update a SwiftUI List after making a network request. For requests, I use Moya approach with combination of triggers(Input&Output - "Kickstarter").
I cant use Combine framework due to the structure of the project, while they have a lot of helpful advises(not sure about my case).
Simple ContactList:
struct ContactList: View {
var viewModel: UserViewModel
var body: some View {
NavigationView {
List(viewModel.users) { contact in
NavigationLink(destination: ContactDetail(user: contact)) {
ContactRow(user: contact)
}
}
.navigationBarTitle(Text("Team Members"))
}
}
}
Then ViewModel
class UserViewModel {
let disposeBag = DisposeBag()
var users: [TeamMember] = []
init(users: [TeamMember] = []) {
let networkModel = UserNetworkModel()
networkModel.output.teamMembers.subscribe { (event) in
self.users.append(contentsOf: event.element.orEmpty)
}.disposed(by: disposeBag)
networkModel.output.error.subscribe(onNext: { error in
print(error.localizedDescription)
}).disposed(by: disposeBag)
networkModel.input.loadTrigger.onNext(Void())
self.users = users
}
}
And NetworkModel
class UserNetworkModel {
let disposeBag = DisposeBag()
let input: Input
let output: Output
struct Input {
let loadTrigger: AnyObserver<Void>
let searchTrigger: AnyObserver<String>
}
struct Output {
let teamMembers: Observable<[TeamMember]>
let error: Observable<Error>
}
internal let loadSubject = PublishSubject<Void>()
internal let searchSubject = BehaviorSubject<String>(value: "")
internal let errorSubject = PublishSubject<Error>()
internal let teamMembersSubject = BehaviorSubject<[TeamMember]>(value: [])
init() {
let service = MoyaProvider<TeamTarget>()
self.input = Input(loadTrigger: loadSubject.asObserver(), searchTrigger: searchSubject.asObserver())
self.output = Output(teamMembers: teamMembersSubject.asObservable(), error: errorSubject.asObservable())
let result = loadSubject.flatMapLatest { _ -> Observable<[TeamMember]> in
service.rx.request(.get).debug().mapArray(TeamMember.self).asObservable()
}.share(replay: 1)
Observable.combineLatest(result, searchSubject).map { (arg) in
let (members, filter) = arg
if filter.isEmpty {
return members
} else {
let searchText = try! self.searchSubject.value()
return members.filter({
return [$0.firstName, $0.lastName]
.compactMap({ $0 })
.first(where: { $0.hasPrefix(searchText) }) != nil
})
}
}.bind(to: teamMembersSubject).disposed(by: disposeBag)
result.subscribe(onError: { error in
self.errorSubject.onNext(error)
}).disposed(by: self.disposeBag)
}
}
Is it possible to update users array in this way? Or only Combine can do it for me easily?
Thanks for your time.
While I've found some Combine solution. Still waiting for Rx solution.
So, I fixed it just added #ObservedObject for ContactList property and #Published for users' array in Network model. Much less code, natively but not what I was looking for.
Full answer:
struct ContactList: View {
#ObservedObject var networkModel: NetworkModel
var body: some View {
NavigationView {
List(networkModel.users) { contact in
NavigationLink(destination: ContactDetail(user: contact)) {
ContactRow(user: contact)
}
}
.navigationBarTitle(Text("Team Members"))
}
}
}
#if DEBUG
struct ContactList_Previews: PreviewProvider {
static var previews: some View {
ContactList(networkModel: .init(users: contactData))
}
}
#endif
class NetworkModel: ObservableObject {
#Published var users = [User]()
init(users: [User] = []) {
getMembers()
}
private func getMembers() {
let provider = MoyaProvider<TeamTarget>()
provider.request(.get) { [weak self] (result) in
switch result {
case .success(let response):
do {
let result = try JSONDecoder().decode([User].self, from: response.data)
self?.users.append(contentsOf: result)
} catch {
print(error.localizedDescription)
}
case .failure(let error):
print(error.errorDescription.orEmpty)
}
}
}
}

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! :)

Resources