I am trying to call a function I have made which pulls data from an API. The function is created before the var body: some View part and is call inside of that. There are no compiler errors in the function itself or anywhere else. Before I started to use SwiftUI I had no issue with this type of function and the code is almost the exact same. Here is the code for the function including the Struct I have for the JSON data;
var postDetailsData = postDetails.self
var commentsArray = comments.self
struct postDetails: Decodable {
let count: Int?
var results: [results]
}
struct results: Decodable {
var id: String
let author: author?
let anonym: Bool
let subscribed: Bool
let created: String
let active: Bool
let text: String
let image: String?
let comments: [comments]
}
struct author: Decodable {
let user: Int
var name: String
let avatar: String?
let banned: Bool
}
struct comments: Decodable, Identifiable {
let id: Int
let text: String
let author: authorOfComment?
}
struct authorOfComment: Decodable {
let name: String
let avatar: String?
}
//And now the actual function
let tokenData = UserDefaults.standard.object(forKey: "savedToken")
var spread = Bool()
let request = NSMutableURLRequest(url: NSURL(string: "http://localhost:8000/areas/sample/")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
func pullData(){
let headers = [
"Authorization": "token \(tokenData ?? "nope")",
"cache-control": "no-cache",
"Postman-Token": "53853353-f547-410a-b289-e3c4ced8e426"
]
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)
}
guard let data = data else {return}
do{
let JSONFromServer = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print(JSONFromServer)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let postDetailsDataArray = try decoder.decode(postDetails.self, from: data)
print(postDetailsDataArray.results)
for results in postDetailsDataArray.results{
DispatchQueue.main.async {
//Account Pic Post and Other Stuff In The HStack
let accountPicAndStuff = HStack {
Button(action: /*#START_MENU_TOKEN#*/{}/*#END_MENU_TOKEN#*/) {
ImageWithActivityIndicator(imageURL: results.author?.avatar ?? "")
.frame(width: 30, height: 30)
.clipShape(Circle())
.offset(x: -75, y: 0)
}
Text(results.author?.name ?? "Annon")
.offset(x: -75)
Button(action: /*#START_MENU_TOKEN#*/{}/*#END_MENU_TOKEN#*/) {
Image("BookMark").offset(x: 70)
}
Button(action: /*#START_MENU_TOKEN#*/{}/*#END_MENU_TOKEN#*/) {
Image("more-vertical").offset(x: 70)
}
}.offset(y: 65)
//accountPicAndStuff.offset(y: 65)
//Description code (pulls data from api)
var postTextTest = results.text
Text(results.text)
//.padding(.bottom, 0)
.offset(y: 10)
.lineLimit(4)
//Image From Post Stuff
if results.image == nil{
print("no image")
}else{
ImageWithActivityIndicator(imageURL: results.image ?? "")
.offset(y: 50)
.scaledToFit()
}
//Date and time for post
Text(results.created)
.font(.footnote)
.fontWeight(.light)
.foregroundColor(Color.gray)
.multilineTextAlignment(.leading)
.offset(x: -85, y: 50)
for comments in results.comments{
print(comments)
//Comment View Code using Lists
List(results.comments){ comments in
HStack{
ImageWithActivityIndicator(imageURL: comments.author?.avatar ?? "")
.frame(width: 100.0, height: 100.0)
}
}
}
}
}
}catch{
print("Failed to decode:", error)
}
})
dataTask.resume()
}
This is how I call the function;
struct FunAreaSmall: View {
//Code from above goes here...
var body: some View {
//Smaller UI
VStack {
pullData()
HStack {
Button(action:{}) {
Image("SkipBtn")
.offset(y: 60)
.scaledToFit()
}
Button(action: {}) {
Image("IgniteBtn")
.offset(y: 60)
.scaledToFit()
}
}
}
}
}
The error itself,
'Int' is not convertible to 'CGFloat'
appears on .offset(y: 60) on the first button in the HStack which I know isn't the issue because when I comment out the call to the function, the error goes away. I have tried different ways of doing getting around this error but all I get is more errors. I have tried to look up the errors on google and nothing has helped yet.
You can't just put function call in a ViewBuilder, because it can't resolve opaque return type.
There are several possible solutions, depending on your needs:
1) Put call of pullData in init()
2) Provide explicit return in ViewBuilder (all of them)
3) Call in some closure (seems most appropriate in this use-case) as in below:
struct FunAreaSmall: View {
//Code from above goes here...
var body: some View {
//Smaller UI
VStack {
HStack {
Button(action:{}) {
Image("SkipBtn")
.offset(y: 60)
.scaledToFit()
}
Button(action: {}) {
Image("IgniteBtn")
.offset(y: 60)
.scaledToFit()
}
}
}
.onAppear() {
self.pullData()
}
}
}
Related
I'm new to SwiftUI and have worked through the server requests and JSON. I now need to programmatically transition to a new view which is where I get stuck with a "Cannot find 'json' in scope" error on the NavigationLink in ContentView.swift. I've watched videos and read articles but nothing quite matches, and everything I try just seems to make things worse.
JSON response from server
{"status":{"errno":0,"errstr":""},
"data":[
{"home_id":1,"name":"Dave's House","timezone":"Australia\/Brisbane"},
{"home_id":2,"name":"Mick's House","timezone":"Australia\/Perth"},
{"home_id":3,"name":"Jim's House","timezone":"Australia\/Melbourne"}
]}
JSON Struct file
import Foundation
struct JSONStructure: Codable {
struct Status: Codable {
let errno: Int
let errstr: String
}
struct Home: Codable, Identifiable {
var id = UUID()
let home_id: Int
let name: String
let timezone: String
}
let status: Status
let data: [Home]
}
ContentView file
import SwiftUI
struct ContentView: View {
#State private var PushViewAfterAction = false
var body: some View {
NavigationLink(destination: ListView(json: json.data), isActive: $PushViewAfterAction) {
EmptyView()
}.hidden()
Button(action: {
Task {
await performAnAction()
}
}, label: {
Text("TEST")
.padding()
.frame(maxWidth: .infinity)
.background(Color.blue.cornerRadius(10))
.foregroundColor(.white)
.font(.headline)
})
}
func performAnAction() {
PushViewAfterAction = true
return
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
ListView file
import SwiftUI
struct ListView: View {
#State var json: JSONStructure
var body: some View {
VStack {
List (self.json.data) { (home) in
HStack {
Text(home.name).bold()
Text(home.timezone)
}
}
}.onAppear(perform: {
guard let url: URL = URL(string: "https://... ***removed*** ") else {
print("invalid URL")
return
}
var urlRequest: URLRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
URLSession.shared.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
// check if response is okay
guard let data = data, error == nil else { // check for fundamental networking error
print((error?.localizedDescription)!)
return
}
let httpResponse = (response as? HTTPURLResponse)!
if httpResponse.statusCode != 200 { // check for http errors
print("httpResponse Error: \(httpResponse.statusCode)")
return
}
// convert JSON response
do {
self.json = try JSONDecoder().decode(JSONStructure.self, from: data)
} catch {
print(error.localizedDescription)
print(String(data: data, encoding: String.Encoding.utf8)!)
}
print(json)
if (json.status.errno != 0) {
print(json.status.errstr)
}
print("1. \(json.data[0].name)), \(json.data[0].timezone)")
print("2. \(json.data[1].name)), \(json.data[1].timezone)")
}).resume()
})
}
}
struct ListView_Previews: PreviewProvider {
static var previews: some View {
ListView()
}
}
I've tried to keep the code to a minimum for clarity.
It's because there is no "json" in ContentView, you need to pass json object to ListView, but since you load json in ListView, then you need to initialize json in ListView like:
struct ListView: View {
#State var json: JSONStructure = JSONStructure(status: JSONStructure.Status(errno: 0, errstr: ""), data: [JSONStructure.Home(home_id: 0, name: "", timezone: "")])
var body: some View {
and remove it form NavigationLink in ContentView like:
NavigationLink(destination: ListView(), isActive: $PushViewAfterAction) {
or you could build your JSONStructure to accept optional like:
import Foundation
struct JSONStructure: Codable {
struct Status: Codable {
let errno: Int?
let errstr: String?
init() {
errno = nil
errstr = nil
}
}
struct Home: Codable, Identifiable {
var id = UUID()
let home_id: Int?
let name: String?
let timezone: String?
init() {
home_id = nil
name = nil
timezone = nil
}
}
let status: Status?
let data: [Home]
init() {
status = nil
data = []
}
}
but then you need to check for optionals or provide default value like:
struct ListView: View {
#State var json: JSONStructure = JSONStructure()
var body: some View {
VStack {
List (self.json.data) { (home) in
HStack {
Text(home.name ?? "Could not get name").bold()
Text(home.timezone ?? "Could not get timeZone")
}
}
}.onAppear(perform: {
guard let url: URL = URL(string: "https://... ***removed*** ") else {
print("invalid URL")
return
}
var urlRequest: URLRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
URLSession.shared.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
// check if response is okay
guard let data = data, error == nil else { // check for fundamental networking error
print((error?.localizedDescription)!)
return
}
let httpResponse = (response as? HTTPURLResponse)!
if httpResponse.statusCode != 200 { // check for http errors
print("httpResponse Error: \(httpResponse.statusCode)")
return
}
// convert JSON response
do {
self.json = try JSONDecoder().decode(JSONStructure.self, from: data)
} catch {
print(error.localizedDescription)
print(String(data: data, encoding: String.Encoding.utf8)!)
}
print(json)
if (json.status?.errno != 0) {
print(json.status?.errstr)
}
print("1. \(json.data[0].name)), \(json.data[0].timezone)")
print("2. \(json.data[1].name)), \(json.data[1].timezone)")
}).resume()
})
}
}
I am having issues trying to get this data. I heard there is a trick. Can anyone create a simple call to view the data from this api? Would truly appreciate it. Been trying for a week. I cant for the life of me get this simple api call to work.
http://api.citybik.es/v2/networks
Model.swift
import Foundation
// MARK: - Welcome
struct Dataset: Codable {
let networks: [Network]
}
// MARK: - Network
struct Network: Codable {
let company: [String]
let href, id: String
let location: Location
let name: String
}
// MARK: - Location
struct Location: Codable {
let city, country: String
let latitude, longitude: Double
}
Contentview.swift
import SwiftUI
struct ContentView: View {
#State var results = [Network]()
func loadData() {
guard let url = URL(string: "http://api.citybik.es/v2/networks") else {
print("Your API end point is Invalid")
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
if let response = try? JSONDecoder().decode([Network].self, from: data) {
DispatchQueue.main.async {
self.results = response
}
return
}
}
}.resume()
}
var body: some View {
List(results, id: \.name) { item in
VStack(alignment: .leading) {
Text("\(item.name)")
}
}.onAppear(perform: loadData)
}
}
copy the whole of the json from : "https://api.citybik.es/v2/networks"
into "https://app.quicktype.io/" and get the (correct) swift data structures from that.
Rename "Welcome" to "Response" and use that in your code.
use: "https://api.citybik.es/v2/networks" note the https.
EDIT: In your code:
struct ContentView: View {
#State var networks = [Network]()
var body: some View {
List(networks, id: \.id) { network in
VStack {
Text(network.name)
Text(network.location.city)
}
}.onAppear(perform: loadData)
}
func loadData() {
guard let url = URL(string: "https://api.citybik.es/v2/networks") else {
print("Your API end point is Invalid")
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
if let response = try? JSONDecoder().decode(Response.self, from: data) {
DispatchQueue.main.async {
self.networks = response.networks
}
return
}
}
}.resume()
}
}
Once you have all the data structures,
and if you are using Swift 5.5 for ios 15 or macos 12, you can use something like this:
struct ContentView: View {
#State var networks = [Network]()
var body: some View {
List(networks, id: \.id) { network in
VStack {
Text(network.name)
Text(network.location.city)
}
}
.task {
let response: Response? = await fetchNetworks()
if let resp = response {
networks = resp.networks
}
}
}
func fetchNetworks<T: Decodable>() async -> T? {
let url = URL(string: "https://api.citybik.es/v2/networks")!
let request = URLRequest(url: url)
do {
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
// throw URLError(.badServerResponse) // todo
print(URLError(.badServerResponse))
return nil
}
let results = try JSONDecoder().decode(T.self, from: data)
return results
}
catch {
return nil
}
}
}
Yesterday, I asked a related question here.
I now have this script:
#available(OSX 11.0, *)
struct Mods_UI: View {
#State private var falseerror = false
#State var jsonDataList = [jsonData]()
var body: some View {
VStack {
List(jsonDataList, id: \.id) { jsonDataList in
VStack(alignment: .leading) {
HStack {
VStack(alignment: .leading) {
Text(jsonDataList.display)
.font(.title3)
.fontWeight(.bold)
Text(String(jsonDataList.description))
.font(.subheadline)
}
Spacer()
Image(systemName: jsonDataList.enabled ?? false ? "checkmark.square": "square")
}
Spacer()
}
}
.onAppear(perform: loadData)
}
}
func loadData() {
guard let modsURL = URL(string: "https://raw.githubusercontent.com/nacrt/SkyblockClient-REPO/main/files/mods.json") else {
print("Invalid URL")
return
}
let task = URLSession.shared.dataTask(with: modsURL) { (data, _, error) in
if let error = error { print(error); return }
do {
let result = try JSONDecoder().decode([jsonData].self, from: data!)
jsonDataList = result
print("Response:",jsonDataList)
} catch {
print(error)
}
}
task.resume()
}
}
#available(OSX 11.0, *)
struct Mods_UI_Previews: PreviewProvider {
static var previews: some View {
Mods_UI()
}
}
struct jsonData: Codable, Identifiable {
let id: String
let display: String
let description: String
let url: String?
let config: Bool?
let enabled: Bool?
let hidden: Bool?
let icon: String?
let categories: [String]?
}
I would like to format the checkbox: Image(systemName: jsonDataList.enabled ?? false ? "checkmark.square": "square") as a Toggle: Toggle("", isOn: $jsonDataList.enabled). I have tried a few ways of formatting this, and it always seems to return an error. My plan for this is to be able to check if the box is checked, and if so, install a file somewhere.
Another thing that I'd like to do is only show the items in the JSON that either have jsonDataList.hidden as false or just do not have jsonDataList.hidden.
There are a couple of things that need to happen in order to make this work. The first is that your model should probably have enabled be a var instead of a let -- that way, its value can be changed when the Toggle is manipulated:
struct jsonData: Codable, Identifiable {
let id: String
let display: String
let description: String
let url: String?
let config: Bool?
var enabled: Bool? //<-- Here
let hidden: Bool?
let icon: String?
let categories: [String]?
}
Next, you'll need to create a Binding to use with the Toggle. Because your model is in an array, the Binding will need to know which item to update (its index in the array). You'll see that in my code as the enabledBindingForIndex function.
Lastly, in order to get the index for each item that you'll be passing into the enabledBindingForIndex function, the ForEach code will have to be changed a little bit so that it passes in both the JSON item and the index. I like using .enumerated() for this. Note that the id of the item is now .1.id because you'll be getting a tuple with both the index (.0) and the item (.1). I also filter out the hidden items in that same line.
struct Mods_UI: View {
#State private var falseerror = false
#State var jsonDataList = [jsonData]()
func enabledBindingForIndex(index: Int) -> Binding<Bool> {
Binding<Bool> { () -> Bool in
return jsonDataList[index].enabled ?? false
} set: { (newValue) in
jsonDataList[index].enabled = newValue
}
}
var body: some View {
VStack {
List(Array(jsonDataList.filter { $0.hidden != true }.enumerated()), //<-- Here
id: \.1.id) { (index,jsonDataList) in //<-- Here
VStack(alignment: .leading) {
HStack {
VStack(alignment: .leading) {
Text(jsonDataList.display)
.font(.title3)
.fontWeight(.bold)
Text(String(jsonDataList.description))
.font(.subheadline)
}
Spacer()
Toggle(isOn: enabledBindingForIndex(index: index)) { } //Here
}
Spacer()
}
}
.onAppear(perform: loadData)
}
}
func loadData() {
guard let modsURL = URL(string: "https://raw.githubusercontent.com/nacrt/SkyblockClient-REPO/main/files/mods.json") else {
print("Invalid URL")
return
}
let task = URLSession.shared.dataTask(with: modsURL) { (data, _, error) in
if let error = error { print(error); return }
do {
let result = try JSONDecoder().decode([jsonData].self, from: data!)
jsonDataList = result
print("Response:",jsonDataList)
} catch {
print(error)
}
}
task.resume()
}
}
If you wanted to have some side effect that takes place when the Toggle is enabled/disabled, you could do so in the enabledBindingForIndex set closure.
I need to post a https request to login view (SwiftUI), my code follow I have in getres.swift:
so I neet to get value from response and put it in the text
import Foundation
import Combine
struct result: Decodable {
let res, ordercount, rate: String
}
class getres: ObservableObject {
let objectWillChange = PassthroughSubject<getres, Never>()
#Published var authenticated = ""
#Published var todos = [result]() {
didSet {
objectWillChange.send(self)
}
}
func auth(username: String, password: String) {
guard let url = URL(string: "http://company.com/auth.php") else { return }
let body: [String: String] = ["username": username, "password": password]
let finalBody = try! JSONSerialization.data(withJSONObject: body)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = finalBody
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data=data else{return}
let fineldata=try! JSONDecoder().decode(result.self, from: data)
DispatchQueue.main.async {
self.todos = [fineldata]
self.authenticated=fineldata.res
}
print(fineldata)
}.resume()
}
}
and in the login page I try to show other view
in this code I will get values from function as json response I will get ordercount and rate I put it in the other view
import SwiftUI
struct ContentView: View {
#State private var username: String = ""
#State private var password: String = ""
#ObservedObject var manager = getres()
var body: some View {
VStack(alignment: .leading) {
if manager.authenticated == "2"{
userdetails()
}else{
Text("Username")
TextField("placeholder", text: $username)
.textFieldStyle(RoundedBorderTextFieldStyle())
.border(Color.green)
.autocapitalization(.none)
Text("Password")
SecureField("placeholder", text: $password)
.textFieldStyle(RoundedBorderTextFieldStyle())
.border(Color.green)
Button(action: {
self.manager.auth(username: self.username, password: self.password)
}) {
HStack{
Spacer()
Text("Login")
Spacer()
}
.accentColor(Color.white)
.padding(.vertical, 10)
.background(Color.red)
.cornerRadius(5)
.padding(.horizontal, 40)
}
}.padding()}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
and in userdetails this so I need to get values from response
struct userdetails: View {
#State var controller = getres()
var body : some View{
ScrollView(Axis.Set.vertical, showsIndicators: true) {
VStack(spacing: 20){
Image("wlogo").renderingMode(.original); HStack(spacing: 15){
Spacer()
VStack(alignment: .center, spacing: 10) {
Text(???).foregroundColor(Color.white).bold()
.font(.largeTitle)
Text("")
.foregroundColor(Color.white)
.font(.headline) }
Spacer()
}}}}
how can I get ordercount from response and put in
text(???)
in the view userdetails
for example controller.todos.ordercount
I get this error
Value of type '[result]' has no member 'ordercount'
when I try
Text(controller.todos.ordercount)
json response
{"res":"2","ordercount":"20","rate":"5"}
UPDATED ANSWER
1.) it would be helpful if you copy your code in just one part - this is easier for all of us to copy
2.) you should try out your code yourself before you copy or change something in your code manually. it is annoying to find mistakes like:
if manager.authenticated == "2"{
userdetails()
} else{
Text("Username")
TextField("placeholder", text: $username)
.textFieldStyle(RoundedBorderTextFieldStyle())
.border(Color.green)
.autocapitalization(.none)
Text("Password")
SecureField("placeholder", text: $password)
.textFieldStyle(RoundedBorderTextFieldStyle())
.border(Color.green)
Button(action: {
self.manager.auth(username: self.username, password: self.password)
}) {
HStack{
Spacer()
Text("Login")
Spacer()
}
.accentColor(Color.white)
.padding(.vertical, 10)
.background(Color.red)
.cornerRadius(5)
.padding(.horizontal, 40)
}
}.padding()}
}
where you are adding .padding() to an if-statement....
3.) you should name class names in that way people can understand what the class if for and start with a capitalized letter like Apple does with all class names
4.) you should also begin View names capitalized (like Apple does)
5.) since i have to access to your page and you did not provide example data and/or password i have no idea what data are coming there...
here is my solution code so far:
i added some faking data, because i cannot access your data ....so you can see something in details.
struct ToDo: Decodable, Identifiable {
var id = UUID().uuidString
let res, ordercount, rate: String
}
class ToDoGetter: ObservableObject {
let objectWillChange = PassthroughSubject<ToDoGetter, Never>()
#Published var authenticated = ""
#Published var todos = [ToDo]() {
didSet {
objectWillChange.send(self)
}
}
let someFakingTodos = [
ToDo(res: "a", ordercount: "5", rate: "75%"),
ToDo(res: "b", ordercount: "52", rate: "5%"),
ToDo(res: "c", ordercount: "566", rate: "7%"),
ToDo(res: "d", ordercount: "53", rate: "33%"),
ToDo(res: "e", ordercount: "15", rate: "44%"),
ToDo(res: "f", ordercount: "345", rate: "10%")
]
func auth(username: String, password: String) {
guard let url = URL(string: "http://company.com/auth.php") else { return }
let body: [String: String] = ["username": username, "password": password]
let finalBody = try! JSONSerialization.data(withJSONObject: body)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = finalBody
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data=data else{return}
let fineldata=try! JSONDecoder().decode(ToDo.self, from: data)
DispatchQueue.main.async {
self.todos = [fineldata]
self.authenticated=fineldata.res
}
print(fineldata)
}.resume()
}
}
struct ContentView: View {
#EnvironmentObject var todoGetter : ToDoGetter
#State private var username: String = ""
#State private var password: String = ""
#State var navigateToDetail : Bool = false
var body: some View {
NavigationView {
VStack(alignment: .leading) {
if todoGetter.authenticated == "2"{
Userdetails().environmentObject(todoGetter)
} else{
Text("Username")
TextField("placeholder", text: $username)
.textFieldStyle(RoundedBorderTextFieldStyle())
.border(Color.green)
.autocapitalization(.none)
Text("Password")
SecureField("placeholder", text: $password)
.textFieldStyle(RoundedBorderTextFieldStyle())
.border(Color.green)
NavigationLink(destination: Userdetails(), isActive: self.$navigateToDetail) {
EmptyView() }
.hidden()
.padding()
Button(action: {
self.todoGetter.auth(username: self.username, password: self.password)
self.navigateToDetail.toggle()
}) {
HStack{
Spacer()
Text("Login")
Spacer()
}
.accentColor(Color.white)
.padding(.vertical, 10)
.background(Color.red)
.cornerRadius(5)
.padding(.horizontal, 40)
}
}
}
}
}
}
struct Userdetails: View {
#EnvironmentObject var todoGetter : ToDoGetter
var body : some View{
VStack(spacing: 20) {
Image("wlogo").renderingMode(.original); HStack(spacing: 15){
Spacer()
List(todoGetter.someFakingTodos) { todo in
VStack(alignment: .center, spacing: 10) {
HStack {
Text(todo.res).foregroundColor(Color.white).bold()
.font(.largeTitle)
Text(todo.ordercount)
.foregroundColor(Color.white)
.font(.headline)
Text(todo.rate)
.foregroundColor(Color.white)
.font(.headline)
}
}.background(Color.black)
Spacer()
}
}
}
}
}
OLD ANSWER
you call getres 2 times. you have to call it just once and then give the value to the detailview.
the model should only be created once per app.
I have a function that sends a GET request to my API and then will parse data into a struct. From there I have Text views that use the data from the struct and are set up like this;
func pullData(){
...
Text(results.text)
.offset(y: 10)
.lineLimit(4)
//Date and time for post
Text(results.created )
.font(.footnote)
.fontWeight(.light)
.foregroundColor(Color.gray)
.multilineTextAlignment(.leading)
.offset(x: -85, y: 50)
}
On the last modifier for each Text view I get the error (example);
Result of call to 'offset(x:y:)' is unused
When I call the function none of the text views appear in the actual view. I have tired to research this warning/error but haven't found anything remotely close to a solution. The full function looks like this;
var spread = Bool()
let request = NSMutableURLRequest(url: NSURL(string: "http://localhost:8000/areas/sample/")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
func pullData(){
let headers = [
//"Authorization": "token \(tokenData ?? "nope")",
"Authorization": "token 9a591156c0b828e2cc80b7c7cba2972ff8eb08df",
"cache-control": "no-cache",
"Postman-Token": "53853353-f547-410a-b289-e3c4ced8e426"
]
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)
}
guard let data = data else {return}
do{
let JSONFromServer = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print(JSONFromServer)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let postDetailsDataArray = try decoder.decode(postDetails.self, from: data)
print(postDetailsDataArray.results)
for results in postDetailsDataArray.results{
DispatchQueue.main.async {
//Account Pic Post and Other Stuff In The HStack
HStack {
Button(action: {}) {
ImageWithActivityIndicator(imageURL: results.author?.avatar ?? "")
.frame(width: 30, height: 30)
.clipShape(Circle())
.offset(x: -75, y: 0)
}
Text(results.author?.name ?? "Annon")
.offset(x: -75)
Button(action: {}) {
Image("BookMark").offset(x: 70)
}
Button(action: {}) {
Image("more-vertical").offset(x: 70)
}
}.offset(y: 65)
//Description code (pulls data from api)
Text(results.text)
//.padding(.bottom, 0)
.offset(y: 10)
.lineLimit(4)
//Image From Post Stuff
if results.image == nil{
print("no image")
}else{
ImageWithActivityIndicator(imageURL: results.image ?? "")
.offset(y: 50)
.scaledToFit()
}
//Date and time for post
Text(results.created )
.font(.footnote)
.fontWeight(.light)
.foregroundColor(Color.gray)
.multilineTextAlignment(.leading)
.offset(x: -85, y: 50)
for comments in results.comments{
print(comments)
//Comment View Code using Lists
List(results.comments){ comments in
HStack{
ImageWithActivityIndicator(imageURL: comments.author?.avatar ?? "")
.frame(width: 100.0, height: 100.0)
}
}
}
}
}
}catch{
print("Failed to decode:", error)
}
})
dataTask.resume()
}
I am calling the function inside the view like so;
var body: some View {
//Smaller UI
VStack {
...
}.onAppear() {
self.pullData()
}
}
The data is parsed successfully because I am able to print out the data in the struct. I have tried to find ways around this warning/error such as moving the text views to the view instead of having them inside the function but I ran into other issues with that. I'm new to SwiftUI so any help in as always appreciated!
Your function must return View for you to see it.
func pullData() -> some View { return Text("some View") }
Right now it isn't returning anything at all, all that view that you have written in your function is unused, that's why the result is unused.
And use it like this to see
struct User: Codable {
var title: String = ""
}
struct ContentView: View {
#State var users = User()
var body: some View {
VStack{
pullData()
}
}
func pullData()-> some View{
let string = "https://jsonplaceholder.typicode.com/todos/1"
let url = URL(string: string)!
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard error == nil && data != nil else {
print("error getting data from url"); return }
if let result = try? JSONDecoder().decode(User.self, from: data!){
self.users = result
}
}.resume()
return Text(users.title)
}
}