APIデータをUserDefaultsに保存し、リストに出力する

PlasticTrees

私のアプリでは、ユーザーがバーコードをスキャンし、製品に関する情報がAPIから取得されます。

ユーザーが最新の10個の製品を表示できる履歴セクションを作成したいと思います。

APIデータの結果は、結果タイプに保存されます。結果タイプをリストに表示するには、識別可能である必要があります。

結果は、API呼び出しからの製品の詳細を格納するために使用しているカスタムデータ型です。

結果

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

API呼び出しは次のとおりです。

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個の製品は、キーを使用してUserDefaultsに保存する必要がありますproductHistoryこれは、API呼び出しLoadData()で行われます。

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データを保存できないことです。そのため、APIデータをフェッチするときに、データをそのままuserdefualtsに保存します。次に、履歴に保存したり表示したりするなど、必要なときにデコードします。

現在、空白のリストが表示されていますが、以下のifステートメントが渡されていません。

if let decodedResponse = try? JSONDecoder().decode(History.self, from: products) {

URLをブラウザに貼り付けた場合のAPIからのJSONデータは次のとおりです。

編集

これが私のAPICall()です:

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

このセクションでは、製品に関するデータを見つけて、それに応じて処理したいと思います。したがって、上記の解決策では、画像や説明などがあるかどうかに応じて異なる値を返します...

vadianソリューションで、私はそれをこれに変更しました:

          loadData(url: "URL") { result  in
                switch result {
                case .success(product):
                    print("success")
                case .failure(error):
                    print("failure")
                }
            }
ヴァディアン

As mentioned in the comments you are mixing up Data and Result

First of all drop History and rename Result as Product. We are going to save an array of Product to 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
    }
}

In loadData use the generic Result type as closure parameter. After receiving the data decode it to a Product instance, then load the saved array, remove the first(!) item (if necessary) append the new item, save the array back and call completion with the new Product. All potential errors are passed in the failure case.

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

and call it

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

In HistoryView (please name structs with starting uppercase letter) get the data from UserDefaults and decode the Product array.

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

Note: Be aware that the UUID is not being encoded and saved.

And please use more descriptive variable names.

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

APIデータをUserDefaultsに保存し、リストに出力する

分類Dev

変数のリストを適用するためにsapplyを拡張し、出力をデータフレームのリストとしてRに保存する

分類Dev

FlaskとSQLAlchemyを使用してAPIリクエストをデータベースに保存する方法

分類Dev

userdefaultsに一時データを保存しますか?

分類Dev

swift4でuserdefaultsにjsonデータを保存する方法

分類Dev

PythonリストにAPIデータを保存する際の問題

分類Dev

リストにツリーデータを保存する方法は?

分類Dev

APIリクエストからデータベースにデータを保存する(JSON)

分類Dev

MongoDBデータを取得し、リストに保存します

分類Dev

tsvデータをリストに保存してループする

分類Dev

ストリームを使用してMediaRecorderWebAPI出力をディスクに保存する方法

分類Dev

データを汎用リストに保存し、Linqを使用する

分類Dev

リストに保存されているデータを並べ替えて出力する方法

分類Dev

Railsのデータベースに保存する前にスクリプトタグを削除します

分類Dev

データに応じて1つのデータストリームを異なる出力に出力する方法

分類Dev

過去数分のデータをredisリストに保存する

分類Dev

再帰関数のデータをリストに保存する

分類Dev

外部データをNiFiレジストリに保存する

分類Dev

TextFormからリストにデータを保存する方法

分類Dev

JSONデータをリストに保存する方法は?Angular 8

分類Dev

JSONデータをリストに保存する方法は?Angular 8

分類Dev

Alamofire リクエスト データを変数に保存する

分類Dev

データストアにデータを保存してからtable-vbaにデータを保存する

分類Dev

APIに対してスクリプトを実行し、受信したデータを保存するためのAWSサービスはありますか

分類Dev

SwiftのUserDefaultsにデフォルトのプリンターを保存するにはどうすればよいですか?

分類Dev

データをグループ化し、グループごとに新しいリストに保存する方法

分類Dev

SQLiteデータベースをAndroidタブレットの内部メモリに保存する(API 23)

分類Dev

エコー出力のリストを.txtに保存します

分類Dev

データフレームのリストに対してforループを実行し、出力ごとに個別のCSVを保存しますか?

Related 関連記事

  1. 1

    APIデータをUserDefaultsに保存し、リストに出力する

  2. 2

    変数のリストを適用するためにsapplyを拡張し、出力をデータフレームのリストとしてRに保存する

  3. 3

    FlaskとSQLAlchemyを使用してAPIリクエストをデータベースに保存する方法

  4. 4

    userdefaultsに一時データを保存しますか?

  5. 5

    swift4でuserdefaultsにjsonデータを保存する方法

  6. 6

    PythonリストにAPIデータを保存する際の問題

  7. 7

    リストにツリーデータを保存する方法は?

  8. 8

    APIリクエストからデータベースにデータを保存する(JSON)

  9. 9

    MongoDBデータを取得し、リストに保存します

  10. 10

    tsvデータをリストに保存してループする

  11. 11

    ストリームを使用してMediaRecorderWebAPI出力をディスクに保存する方法

  12. 12

    データを汎用リストに保存し、Linqを使用する

  13. 13

    リストに保存されているデータを並べ替えて出力する方法

  14. 14

    Railsのデータベースに保存する前にスクリプトタグを削除します

  15. 15

    データに応じて1つのデータストリームを異なる出力に出力する方法

  16. 16

    過去数分のデータをredisリストに保存する

  17. 17

    再帰関数のデータをリストに保存する

  18. 18

    外部データをNiFiレジストリに保存する

  19. 19

    TextFormからリストにデータを保存する方法

  20. 20

    JSONデータをリストに保存する方法は?Angular 8

  21. 21

    JSONデータをリストに保存する方法は?Angular 8

  22. 22

    Alamofire リクエスト データを変数に保存する

  23. 23

    データストアにデータを保存してからtable-vbaにデータを保存する

  24. 24

    APIに対してスクリプトを実行し、受信したデータを保存するためのAWSサービスはありますか

  25. 25

    SwiftのUserDefaultsにデフォルトのプリンターを保存するにはどうすればよいですか?

  26. 26

    データをグループ化し、グループごとに新しいリストに保存する方法

  27. 27

    SQLiteデータベースをAndroidタブレットの内部メモリに保存する(API 23)

  28. 28

    エコー出力のリストを.txtに保存します

  29. 29

    データフレームのリストに対してforループを実行し、出力ごとに個別のCSVを保存しますか?

ホットタグ

アーカイブ