在 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。
此答案中的代码并不是编写此视图的唯一方法,还有其他方法可以使此方法更好、更简洁、更优雅。
这只是您如何开始改进已有内容的初步尝试。
我在列表中有一个复选框,单击复选框后我想创建一个 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。
此答案中的代码并不是编写此视图的唯一方法,还有其他方法可以使此方法更好、更简洁、更优雅。
这只是您如何开始改进已有内容的初步尝试。