Reputation: 5
When a user pastes a hexcode into my textfield, I want my API function to take this hexcode and use it as a parameter in the API call. This means I have to share data from my View (containing the textfield) to my Class (containing API call). What is the best way to go about this? Appreciate the time and advice 🙏
View:
import SwiftUI
struct TestingText: View {
@StateObject var fetch = fetchResults()
@Binding var text: String
var body: some View {
VStack {
TextField("Paste Clout Hexcode Here", text: $text)
.font(.title2)
.padding()
Text(fetch.clout.postFound?.body ?? "n/a")
}
}
}
struct TestingText_Previews: PreviewProvider {
static var previews: some View {
TestingText(text: .constant("8004bb672ad3f46118775cd4b2cb5306c63f6d68787457990bf0d2fda3f7993a"))
}
}
Class with API call:
class fetchResults: ObservableObject {
@Published var clout = Cloutington()
@Published var dataHasLoaded = false
@State var postHashHex: String = "8004bb672ad3f46118775cd4b2cb5306c63f6d68787457990bf0d2fda3f7993a"
init() {
getData { clout in
self.clout = clout
}
}
private func getData(completion: @escaping (Cloutington) -> ()) {
let parameters = "{\r\n \"PostHashHex\": \"\(postHashHex)\"\r\n}"
let postData = parameters.data(using: .utf8)
var request = URLRequest(url: URL(string: "https://bitclout.com/api/v0/get-single-post")!,timeoutInterval: Double.infinity)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = postData
request.httpMethod = "POST"
let task = URLSession.shared.dataTask(with: request) { (responseData, response, error) in
print(error)
print(response)
print(responseData)
if let resData = responseData {
let decoder = JSONDecoder()
do
{
let finalData = try decoder.decode(Cloutington.self, from: resData)
DispatchQueue.main.async {
completion(finalData)
self.dataHasLoaded = true
}
}
catch (let error)
{
print(error)
}
}
}
task.resume()
}
}
Model with JSON data:
import Foundation
struct Cloutington: Decodable {
var postFound: PostFound?
enum CodingKeys: String, CodingKey {
case postFound = "PostFound"
}
}
struct PostFound: Decodable {
var id: String?
var postHashHex, posterPublicKeyBase58Check, parentStakeID, body: String?
var imageURLs: [String]?
// var recloutedPostEntryResponse: JSONNull?
var creatorBasisPoints, stakeMultipleBasisPoints: Int?
var timestampNanos: Double?
var isHidden: Bool?
var confirmationBlockHeight: Int?
var inMempool: Bool?
var profileEntryResponse: ProfileEntryResponse?
var likeCount, diamondCount: Int?
var isPinned: Bool?
var commentCount, recloutCount: Int?
var diamondsFromSender: Int?
enum CodingKeys: String, CodingKey {
case postHashHex = "PostHashHex"
case posterPublicKeyBase58Check = "PosterPublicKeyBase58Check"
case parentStakeID = "ParentStakeID"
case body = "Body"
case imageURLs = "ImageURLs"
case creatorBasisPoints = "CreatorBasisPoints"
case stakeMultipleBasisPoints = "StakeMultipleBasisPoints"
case timestampNanos = "TimestampNanos"
case isHidden = "IsHidden"
case confirmationBlockHeight = "ConfirmationBlockHeight"
case inMempool = "InMempool"
case profileEntryResponse = "ProfileEntryResponse"
case likeCount = "LikeCount"
case diamondCount = "DiamondCount"
case isPinned = "IsPinned"
case commentCount = "CommentCount"
case recloutCount = "RecloutCount"
case diamondsFromSender = "DiamondsFromSender"
}
}
// MARK: - ProfileEntryResponse
struct ProfileEntryResponse: Decodable {
var publicKeyBase58Check, username, profileEntryResponseDescription, profilePic: String?
var isHidden, isReserved, isVerified: Bool?
var coinPriceBitCloutNanos, stakeMultipleBasisPoints: Int?
enum CodingKeys: String, CodingKey {
case publicKeyBase58Check = "PublicKeyBase58Check"
case username = "Username"
case profileEntryResponseDescription = "Description"
case profilePic = "ProfilePic"
case isHidden = "IsHidden"
case isReserved = "IsReserved"
case isVerified = "IsVerified"
case coinPriceBitCloutNanos = "CoinPriceBitCloutNanos"
case stakeMultipleBasisPoints = "StakeMultipleBasisPoints"
}
}
Upvotes: 0
Views: 653
Reputation: 87794
First of all, do not name classes in lowercase like fetchResults
, also don't call a class like an action: every programmer expects fetchResults()
to be a function call. Use something like ResultFetcher
to name this class. And class instance usually will be lowercased class name, or part of it:
@StateObject var resultFetcher = ResultFetcher()
// or
@StateObject var fetcher = ResultFetcher()
You can only use @State
inside SwiftUI views, you cannot use it inside ObservableObject
. Use @Published
as you already do with other variables if you need to update the view after updating that variable, or use an unannotated variable.
In your case, it doesn't look like you need to store this hash string; you can just pass it from the view.
You can use .onChange(of: text)
to track changes to the @State
or @Binding
variables:
TextField("Paste Clout Hexcode Here", text: $text)
.font(.title2)
.padding()
.onChange(of: text) { text in
resultFetcher.updateData(postHashHex: text)
}
Not sure if you need that initial call of updateData
with hardcoded hex code, anyway your view model can be updated to this:
class ResultFetcher: ObservableObject {
@Published var clout = Cloutington()
@Published var dataHasLoaded = false
private let initialPostHashHex: String = "8004bb672ad3f46118775cd4b2cb5306c63f6d68787457990bf0d2fda3f7993a"
init() {
updateData(postHashHex: initialPostHashHex)
}
func updateData(postHashHex: String) {
getData(postHashHex: postHashHex) { clout in
self.clout = clout
}
}
private func getData(postHashHex: String, completion: @escaping (Cloutington) -> ()) {
// your code
}
}
Upvotes: 1