मेरे ऐप में, उपयोगकर्ता बारकोड को स्कैन करते हैं और उत्पाद के बारे में जानकारी एक एपीआई से प्राप्त की जाती है।
मैं एक इतिहास अनुभाग बनाना चाहता हूं, जहां उपयोगकर्ता पिछले 10 उत्पादों को देख सकें।
एपीआई डेटा से परिणाम एक परिणाम प्रकार में संग्रहीत किया जाता है, जिसे सूची में दिखाए जाने में सक्षम होने के लिए, पहचान योग्य होना चाहिए।
परिणाम एक कस्टम डेटा प्रकार है जिसका उपयोग मैं एपीआई कॉल से उत्पादों के विवरण को स्टोर करने के लिए कर रहा हूं।
परिणाम
struct Result: Codable, Identifiable {
var id = UUID()
var description: String?
var brand: String?
var ingredients: String?
var image: String?
var upc_code: String?
var return_message: String?
var return_code: String?
enum CodingKeys: String, CodingKey {
case description, brand, ingredients, image, upc_code, return_message, return_code
}
}
यह डेटा प्रकार परिणाम की सरणी को संग्रहीत करता है जिसे मैं एक सूची के रूप में प्रदर्शित करूंगा
इतिहास
struct History: Codable {
var results: [Result]
}
यहाँ एपीआई कॉल है:
func loadData(url: String, completion: @escaping (Error?, Result?) -> Void ) {
if let url = URL(string: url) {
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else {return}
do {
let defaults = UserDefaults.standard
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(data) {
var sizeCheck = defaults.object(forKey:"productHistory") as? [Data] ?? [Data]()
if (sizeCheck.count == 10) { //Check if there's more than 10 products already on the history list
sizeCheck.removeLast()
}
sizeCheck.append(encoded) //Add new product to list
defaults.set(sizeCheck, forKey: "productHistory") //Add new list to userDefaults
}
let decoder = JSONDecoder()
let result: Result = try decoder.decode(Result.self, from: data)
completion(nil, result) //Used elsewhere to display the scanned product after it's been added to the history list
}
catch let e {
print(e)
completion(e, nil)
}
}
task.resume()
}
}
यह मेरा विचार है जो एक बटन दबाए जाने पर सूची में अंतिम 10 उत्पादों को दिखाता है।
अंतिम 10 उत्पादों को productHistory
कुंजी के साथ UserDefaults में संग्रहित किया जाना चाहिए। यह एपीआई कॉल लोडडाटा () में किया जाता है
struct historyView: View {
@Binding var showingHistory: Bool
@State private var results = [Result]()
var body: some View {
let defaults = UserDefaults.standard
if let products = defaults.object(forKey: "productHistory") as? Data {
if let decodedResponse = try? JSONDecoder().decode(History.self, from: products) {
self.results = decodedResponse.results
}
}
return List(self.results, id: \.id) { item in
Text(item.description!)
}
}
}
मेरी समझ में, समस्या यह है कि UserDefaults JSON डेटा संग्रहीत नहीं कर सकता है। तो जब एपीआई डेटा लाया जाता है, तो मैं डेटा को उपयोगकर्ता डिफॉल्ट्स में संग्रहीत करता हूं। फिर जब मुझे इसकी आवश्यकता हो, इसे डीकोड करें, जैसे इसे इतिहास में संग्रहीत करना या इसे प्रदर्शित करना।
वर्तमान में मुझे एक खाली सूची मिल रही है और अगर नीचे दिया गया कथन पास नहीं हो रहा है।
if let decodedResponse = try? JSONDecoder().decode(History.self, from: products) {
अगर मैं ब्राउज़र में यूआरएल पेस्ट करता हूं तो एपीआई से JSON डेटा यहां दिया गया है:
संपादित करें
यहां मेरा एपीआईकॉल है ():
func callAPI() -> String {
if (scannedCode.barcode == "") {
return "noneScanned"
}
else {
let hashedValue = scannedCode.barcode.hashedValue("API ID")
//print(hashedValue!)
loadData(url: "URL") { error, result in
if let err = error {
self.APIresult = err.localizedDescription
print(APIresult)
//output error
}
else if (result?.ingredients == nil) {
DispatchQueue.main.async {
self.APIresult = "noIngredients"
}
}
else if (result?.description == nil) {
DispatchQueue.main.async {
self.APIresult = "noDescription"
}
}
else {
DispatchQueue.main.async {
self.APIresult = "success"
}
}
DispatchQueue.main.async {
product.result = result!
//updates view that show's the scanned product, as it's @Published
}
}
return APIresult
}
}
इस खंड में, मैं यह जानना चाहता हूं कि मेरे पास उत्पाद के बारे में क्या डेटा है और उसके अनुसार इसे संसाधित करें। इसलिए उपरोक्त समाधान के साथ, मैं एक छवि या विवरण आदि के आधार पर एक अलग मूल्य लौटाता हूं ...
वाडियन समाधान के साथ, मैंने इसे इसमें बदल दिया है:
loadData(url: "URL") { result in
switch result {
case .success(product):
print("success")
case .failure(error):
print("failure")
}
}
1 उत्तर
जैसा कि टिप्पणियों में बताया गया है कि आप Data
और Result
को मिला रहे हैं
सबसे पहले History
ड्रॉप करें और Result
का नाम बदलकर Product
कर दें। हम Product
की एक सरणी को UserDefaults
में सहेजने जा रहे हैं
struct Product: Codable, Identifiable {
var id = UUID()
var description: String?
var image: String?
var upc_code: String?
var return_message: String?
var return_code: String?
private enum CodingKeys: String, CodingKey {
case description, image, upc_code, return_message, return_code
}
}
loadData
में जेनेरिक Result
टाइप को क्लोजर पैरामीटर के रूप में इस्तेमाल करें। डेटा प्राप्त करने के बाद इसे Product
उदाहरण में डीकोड करें, फिर सहेजे गए सरणी को लोड करें, पहले (!) आइटम को हटा दें (यदि आवश्यक हो) नया आइटम संलग्न करें, सरणी को वापस सहेजें और नए के साथ कॉल पूरा करें Product
. failure
मामले में सभी संभावित त्रुटियां पास कर दी जाती हैं।
func loadData(url: String, completion: @escaping (Result<Product,Error>) -> Void ) {
guard let url = URL(string: url) else { return }
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error { completion(.failure(error)); return }
do {
let decoder = JSONDecoder()
let product = try decoder.decode(Product.self, from: data!)
let defaults = UserDefaults.standard
var history = [Product]()
if let readData = defaults.data(forKey:"productHistory") {
do {
history = try decoder.decode([Product].self, from: readData)
if history.count == 10 { history.removeFirst() }
} catch { print(error) }
}
history.append(product)
let saveData = try JSONEncoder().encode(history)
defaults.set(saveData, forKey: "productHistory")
completion(.success(product))
}
catch {
print(error)
completion(.failure(error))
}
}
task.resume()
}
और इसे बुलाओ
loadData(url: "URL") { result in
switch result {
case .success(let product):
if product.ingredients == nil {
self.APIresult = "noIngredients"
} else if product.description == nil {
self.APIresult = "noDescription"
} else {
self.APIresult = "success"
}
product.result = product
case .failure(let error):
self.APIresult = error.localizedDescription
print(APIresult)
}
}
HistoryView
में (कृपया अपरकेस अक्षर के साथ नाम संरचनाएँ) UserDefaults
से डेटा प्राप्त करें और Product
सरणी को डीकोड करें।
struct HistoryView: View {
@Binding var showingHistory: Bool
@State private var results = [Product]()
var body: some View {
let defaults = UserDefaults.standard
if let historyData = defaults.data(forKey: "productHistory") {
do {
self.results = try JSONDecoder().decode([Product].self, from: historyData)
} catch { print(error) }
}
return List(self.results, id: \.id) { item in
Text(item.description ?? "n/a")
}
}
}
नोट: ध्यान रखें कि UUID को एन्कोड और सेव नहीं किया जा रहा है।
और कृपया अधिक वर्णनात्मक चर नामों का उपयोग करें।
संबंधित सवाल
नए सवाल
ios
iOS, Apple iPhone, iPod टच और iPad पर चलने वाला मोबाइल ऑपरेटिंग सिस्टम है। IOS प्लेटफॉर्म पर प्रोग्रामिंग से संबंधित प्रश्नों के लिए इस टैग [ios] का उपयोग करें। उन प्रोग्रामिंग भाषाओं के लिए विशिष्ट मुद्दों के लिए संबंधित टैग [उद्देश्य-सी] और [स्विफ्ट] का उपयोग करें।