在 swift ui 中创建 Json 数组

Create Json array in swift ui

我在列表中有一个复选框,单击复选框后我想创建一个 Json 数组,如下所示

{"nurseryData":[{"nurseryCode":"","SSOId":""},.....]} and so on 

我尝试了各种方法,但我无法在复选框点击时附加参数。

请提出实现方法 我是 swift ui 的初学者。

import SwiftUI
import Alamofire
struct AddNurseryCard: View {
    @State private var checked = false
    let models : AddNurseryModels.Data
    
    var data: [String: Any] = [
        "nurseryData": [String : Any]()
    ]
 
    var body: some View {
        HStack{
            Image("nursery")
            Divider()
            VStack{
                if((models.isUrban!) != 0)
                {
                    Text(models.nurseryName! + " (U)")
            
                }else{
                    Text(models.nurseryName! + " (R)")
                }
                Text(models.rANGE_NAME!)
                if((models.isActiveForGGAY!) != 0)
                {
                    Text("Is Active For GGAY : Yes")
                }
                else{
                    Text("Is Active For GGAY : NO")
                }
        }
           
            CheckBoxView(checked: $checked).onAppear(){
                if((models.isActiveForGGAY) != 0)
                {
                   
                    checked = true
                    
                }
                else{
                    checked = false
                }
            }.onChange(of: checked, perform: { value in
                if(checked)
                {
                let result = UserDefaults.standard.value(forKey: "profile")
                
                let profile = ProfileModels(dict: result as! [String : Any])
                let ssoId = (profile.data?[0].ssoid ?? "") as String
                let nurseryCode = models.nurseryCode!
                var existingItems = data["nurseryCode"] as? [[String: Any]] ?? [[String: Any]]()
                var param = ["ssoId":ssoId,"nurseryCode":nurseryCode]
                    
                param.merge(dict: param)
                  print()
                    
                    existingItems.append(param)
                                         print(existingItems)
               addNursery(params: param)
                    
                }
                
            })
            
          
    }
        Divider()
}
    func getArray(params:[[String: Any]]) -> [[String: Any]]
    {
        return params
    }
    func getChecked() -> Bool
    {
        return checked
    }
    func getNurseryCode() -> String
    
    {
        return models.nurseryCode!
    }
   
    func addNursery(params :[String:Any])
    {
        
        let url = Constants.init().devUrl + Api.init().addNursery
        
      
       
        
        let headers : HTTPHeaders = HTTPHeaders(["ApiKey" : Constants.init().apiKey])
        
        AF.request(url,method: .post,parameters: params, encoding:JSONEncoding.default, headers: headers).responseJSON { response in
            switch response.result{
            case .failure(let error):
                print(error)
            case .success(let json):
            print(json)
            
            }
        }
        
    }
}
struct AddNurseryCard_Previews: PreviewProvider {
    static var previews: some View {
        AddNurseryCard(models: AddNurseryModels.dat)
    }
}
extension Dictionary {
    mutating func merge(dict: [Key: Value]){
        for (k, v) in dict {
            updateValue(v, forKey: k)
        }
    }
}

好的...我们这里遇到的问题不是来自 SwiftUI 的问题,而是代码背后根本没有任何设计。

让我在这个回答的开头说我将对您的一些数据做出几个假设,因为目前很难确定它的形状。

一步一步来。

数据建模

您当前的数据模型是

var data: [String: Any] = [
  "nurseryData": [String : Any]()
]

在Swift中我们应该尽可能避免Any。事实上,你的数据在这里真的没有任何形状。

我建议添加一个新类型,例如...

struct NewNursery: Codable {
  let nurseryCode: String
  let SSOId: String
}

struct SelectedNurseries: Codable {
  let nurseries: [NewNursery] = []
}

使用 Codable 之后您可以使用...

let jsonData = JSONEncdoer().encode(updloadData)

这允许您删除所有合并和 [String: Any] 函数和类型。

查看模型

我们还可以将视图中的一些复杂性打包到视图模型中。您似乎也有很多强制解包,这有潜在的危险。如果你强行打开一些 nil 的东西,你的应用程序将会崩溃。如果您知道它永远不会为零,那么它首先不应该在您的数据中是可选的。

让我们创建一个包含一些逻辑的视图模型...

作为一个快速的旁注。调用一些东西 Data 并不能真正提供任何关于它里面是什么的线索。

struct AddNurseryViewModel {
  let models: AddNurseryModels.Data // I'm really not sure what this is but I'll keep the same name you use.

  var nameSuffix: String {
    if let isUrban = models.isUrban,
      isUrban != 0 {
      return "U"
    } else {
      return "R"
    }
  }

  var isActiveForGgay: Bool {
    if let isActive = models.isActiveForGGAY,
      isActive != 0 {
      return true
    } else {
      return false
    }
  }

  var ggayText: String {
    if isActiveForGgay {
      return "Is Active For GGAY : Yes"
    } else {
      return "Is Active For GGAY : No"
    }
  }
}

查看带有新数据的视图

我真的不是100%确定为什么有这么多get...函数?我猜你可能来自 Java 背景?

无论如何...既然我们有了模型,让我们看看重写视图。我还将使用一些更简洁的语法来实现您正在做的一些事情。

struct AddNurseryCard: View {
  @State private var checked = false
  let viewModel: AddNurseryViewModel

  var selectedNurseries = SelectedNurseries()
 
  var body: some View {
    HStack {
      Image("nursery")
      Divider()
      VStack {
        Text("\(models.nurseryName!) \(viewModel.nameSuffix)")
        Text(models.rANGE_NAME!)
        Text(viewModel.ggayText)
      }
           
      CheckBoxView(checked: $checked)
        .onAppear() { checked = viewModel.isActiveForGgay }
        .onChange(of: checked) { value in
          nurserySelected()
        }
  
    }
    Divider()
  }

  func nurserySelected() {
    if(checked) {
      // I'm really struggling to understand some of this but you need to apply my same thoughts of data modelling here.
      // I will write the code as it "should" be but you will need to model it for this to work.

      let profile = UserDefaults.standard.value(forKey: "profile")
            
      let ssoId = profile.ssoid // don't use [String: Any] for things like this
      let nurseryCode = models.nurseryCode!

      var newNursery = NewNursery(nurseryCode: nurseryCode, ssoId: ssoId)
                    
      selectedNurseries.nurseries.append(newNursery)
                    
      addNursery(nursery: newNursery)
    }
  }
  
  // This whole function should really be in a separate file. It's nothing to do with the view.
  func addNursery(nursery: NewNursery)
  {
    let url = Constants.init().devUrl + Api.init().addNursery
        
    let headers : HTTPHeaders = HTTPHeaders(["ApiKey" : Constants.init().apiKey])
        
    AF.request(url,method: .post,parameters: nursery, encoding:JSONEncoding.default, headers: headers).responseJSON { response in
      switch response.result{
      case .failure(let error):
        print(error)
      case .success(let json):
        print(json)    
      }
    }      
  }
}

尝试以适合您正在做的事情的方式对数据进行建模确实值得。

不花时间像这样对数据建模会导致代码变得复杂而且不是很 readable/maintainable。

此答案中的代码并不是编写此视图的唯一方法,还有其他方法可以使此方法更好、更简洁、更优雅。

这只是您如何开始改进已有内容的初步尝试。