我的项目访问一个包含200多个country元素的JSON文件,其中一个名称/值对是flag:包含我认为是Base64加密的内容-示例如下。我已成功包含名称:和:标志。Picker工作正常,显示所选国家/地区,并使用这两个标志更新CoreData & CloudKit(ClientEntity)记录。挑战是调用记录进行显示或编辑。我无法显示标志Image-只有默认值。它在clientFlag字段中存储了一些内容。我希望它存储标志:1920字节的JSON数据-相反(从控制台复制),它存储的是"CD_clientFlag"="{length = 1458,sha256 = c1572719d906e1df50fdf296845b0942ef148060c609d58543477b6276a67e9}";\n
很明显,我的逻辑有问题,或者这个字段包含了不同的数据格式,或者两者都有。任何帮助都将受到欢迎。当然,更好的方法是通过id引用JSON数据:或名称:,但由于缺乏经验,我放弃了这一点,并选择存储这两个名称:并标记
相关代码如下:
- 视图中成功的选取器代码**
NavigationStack {
Form {
VStack(alignment: .leading) {
clientNameAddress
Group {
Picker(selection: $selectedCountry,
label: Text("")) {
ForEach(countryVM.countries) { country in
HStack {
Text(country.name)
if let flagImage = country.flagImage {
Image(uiImage: flagImage)
} else {
Image(systemName: "questionmark")
}
}.tag(country as Country?)//: HSTACK6
}
}
.padding(.horizontal, 10)
.pickerStyle(MenuPickerStyle())
VStack {
Text("Selected Country: \(selectedCountry?.name ?? "No Name")")
.foregroundColor(.secondary)
if let flagImage = selectedCountry?.flagImage {
Image(uiImage: flagImage)
}
}.padding(.horizontal, 10)
}
Toggle("Existing Client?", isOn: $clientVM.clientExisting)
.toggleStyle(.switch)
.foregroundColor(.blue)
.padding(.horizontal, 10)
// SelectContact()
Button(action: {
assignFlag()
print("AddView \(clientVM.clientHostCountry)")
clientVM.addClient(context: viewContext)
dismiss()
}, label: {
if clientVM.clientItem == nil {
Text("Add Account")
.frame(minWidth: 0, maxWidth: 200)
} else {
Text("Save Modified Client")
.frame(minWidth: 0, maxWidth: 200)
}
})
.tint(.purple)
.buttonStyle(.bordered)
.buttonBorderShape(.roundedRectangle)
}
.navigationTitle(clientVM.clientItem == nil ? "Add Account" : "Edit Account \(clientVM.clientName)")
}.disableAutocorrection(true)
#if os(iOS)
.navigationBarTitle("Add Account")
.navigationBarTitleDisplayMode(.inline)
#endif
}
- JSON示例**
{
"id": 2,
"name": "Albania",
"isoAlpha2": "AL",
"isoAlpha3": "ALB",
"isoNumeric": 8,
"currency": {
"code": "ALL",
"name": "Lek",
"symbol": "Lek"
},
"flag": "iVBORw0KGgoAAAANSUhEUgAAAB4AAAAUCAIAAAAVyRqTAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoyRDFBRDI0NTE3NkYxMUUyODY3Q0FBOTFCQzlGNjlDRiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoyRDFBRDI0NjE3NkYxMUUyODY3Q0FBOTFCQzlGNjlDRiI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjdERDBDNDA4MTc1MzExRTI4NjdDQUE5MUJDOUY2OUNGIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjJEMUFEMjQ0MTc2RjExRTI4NjdDQUE5MUJDOUY2OUNGIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+GPq/agAAAiRJREFUeNrEVb9rFEEUfm9m9nb3bhNz50UMClopRAsFrUURW1tBrSzsLPwfbPwDbGz8F8QiIkLAKiCkUIKiGBEFwXAhd7fZH7Mz83zZtbC4TdyF4LDF8N7ON9/73jczuN4/A4czBBzaqIUmAA+Q0wjQRzkUCsv4USEHKKs4/0DtWOdAgxLxrUk+mqyHIkLx2eg1k1gA3kwDtYFeFOqVnj5NRwXQip7eGG9+svlPV1wff3mejwuiZ9n2i3zCRWANAta1kaFX9OS1jkdkHdGyCt6blMmel8E3p1OgY6iueL2b/pEtZ5qx5kRCLIhMyK4WMQFt2HzdpEzypZ5OnOVUSoT1gqi6BOvA7ZoDUan5JB3BXxPeOALBahigxloLQO4SFy5hBjMOpuA0zc4ebL4OYExuZl0dxNiRh63MZ4jYXjzJiG77/cuqW8UvqvBO0Ge+jjsplKHmgrCIIeICyke9pXPKZ+kvqPCS1+X6T4vO42iJN/YB22jNIo6cYWN9dfqdya560TxKruKaF32w2abVW2VWtNCa6fRQnpTeD1vcD4anZOdNEa8VCZN9EA6/2+KE9Ob3dUit+XbJHRfqXjBgTZjYhk3nUDAQN/CsDJbDYIfcbvlhU+hqQUpuSo6tcstfYMp8q9z1+7+cyfZMuUe4zZGp/GfLxRm4bbIPu4scYbIJOO6EO+hSVf9y8zLQmGxUKrNDRu7HtSH0n+NHrpr8/1fmtwADAEjB+xzEjgF0AAAAAElFTkSuQmCC"
}
- 国家视图模型**
import SwiftUI
import Foundation
struct Country: Codable, Identifiable, Comparable, Hashable {
let id = UUID() // New
let name: String
let isoAlpha3: String
let flag: Data?
enum CodingKeys: String, CodingKey {
case name, isoAlpha3, flag
}
var flagImage: UIImage? {
guard let flagData = flag else { return nil }
return UIImage(data: flagData)
}
static func == (lhs: Country, rhs: Country) -> Bool {
lhs.name == rhs.name
}
static func < (lhs: Country, rhs: Country) -> Bool {
lhs.name < rhs.name
}
struct HeadingData: Codable, Identifiable, Hashable {
let id: Int
let name: String
let isoAlpha3: String
let flag: Data
}
struct CurrencyData: Codable, Equatable, Identifiable, Hashable {
let id: UUID
let code: String
let name: String
let symbol: String
}
}
class CountryModel: ObservableObject {
@Published var countries: [Country] = []
init() {
self.countries = Bundle.main.decode("Countries.json")
// let data = self.countries
// let json = try? JSONSerialization.jsonObject(with: data, options: [])
}
}
- 用于解码clientFlag的计算属性**
extension ClientEntity {
var showFlag: Image {
let str = clientFlag ?? Data()
if str.isEmpty {
let flagImage = Image(systemName: "plus.circle")
return flagImage
} else {
let dataDecoded : Data = Data(base64Encoded: str) ?? Data()
guard let flagImage = UIImage.init(data: dataDecoded) else { return Image(systemName: "plus.circle") }
return Image(uiImage: flagImage)
}
}
}
- 客户端视图模型**
import Foundation
import Combine
import CoreData
class ClientViewModel: ObservableObject {
@Published var clientName = ""
@Published var clientAddress1 = ""
@Published var clientAddress2 = ""
@Published var clientPhoneNumber = ""
@Published var clientHostCountry = ""
@Published var clientFlag: Data?
@Published var clientIndustry = ""
@Published var clientLogo: Data?
@Published var clientComments = ""
@Published var clientExisting = false
@Published var clientWebSite: URL?
@Published var clientUpdated: Date = Date()
@Published var clientCreated: Date = Date()
@Published var clientItem: ClientEntity!
@Published var selectedContact: [ContactEntity] = []
func addClient(context: NSManagedObjectContext) {
if clientItem == nil {
let client = ClientEntity(context: context)
client.clientName = clientName
client.clientAddress1 = clientAddress1
client.clientAddress2 = clientAddress2
client.clientPhoneNumber = clientPhoneNumber
print("clientVM \(clientHostCountry)")
client.clientHostCountry = clientHostCountry
client.clientFlag = clientFlag
client.clientIndustry = clientIndustry
// client.clientLogo = clientLogo
client.clientComments = clientComments
client.clientExisting = clientExisting
// client.clientWebSite = clientWebSite
client.clientUpdated = clientUpdated
client.clientCreated = clientCreated
print("Selected Contact: \(selectedContact.description)")
let uniqueContact = Set(selectedContact)
for contact in uniqueContact {
client.addToContacts(contact)
}
} else {
clientItem.clientName = clientName
clientItem.clientAddress1 = clientAddress1
clientItem.clientAddress2 = clientAddress2
clientItem.clientPhoneNumber = clientPhoneNumber
clientItem.clientHostCountry = clientHostCountry
clientItem.clientFlag = clientFlag
clientItem.clientIndustry = clientIndustry
// clientItem.clientLogo = clientLogo
clientItem.clientComments = clientComments
clientItem.clientExisting = clientExisting
// clientItem.clientWebSite = clientWebSite
clientItem.clientUpdated = clientUpdated
clientItem.clientCreated = clientCreated
print("Selected Contact: \(selectedContact.description)")
let uniqueContact = Set(selectedContact)
for contact in uniqueContact {
clientItem.addToContacts(contact)
}
}
save(context: context)
clientName = ""
clientAddress1 = ""
clientAddress2 = ""
clientPhoneNumber = ""
clientHostCountry = ""
clientFlag = Data()
clientIndustry = ""
// clientLogo = Data()
clientComments = ""
clientExisting = false
// clientWebSite = URL(string: "")!
clientUpdated = Date()
clientCreated = Date()
}
func editClient(client: ClientEntity) {
clientItem = client
}
func delete(client: ClientEntity, context: NSManagedObjectContext) {
context.delete(client)
save(context: context)
}
func save(context: NSManagedObjectContext) {
do {
try context.save()
} catch {
fatalError("Error saving: \(error.localizedDescription)")
}
}
func isExisting(client: ClientEntity, context: NSManagedObjectContext) {
client.clientExisting.toggle()
save(context: context)
}
}
我试着添加. jpeg和. png参数以及成功的picker代码的相反部分。没有运气。
- 新问题**程序在线程1时崩溃:断点1.2(1)在选取器中的. tag(country as Country)处出现错误(绿色背景?)。将鼠标悬停在"country"属性上显示它包含JSON文件中的第一个国家。"变量"窗口显示:
国家B2Bv5.国家
统一用户标识符uuid(UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8)
名称字符串
_内脏_字符串内脏_对象_字符串对象
_计数和标志位UInt64 13835058055282163723_对象内置桥接对象0x4000600001ef0ec0 isoAlpha3字符串
_内脏_字符串内脏_对象_字符串对象
_计数和标志位UInt64 4671041_对象NSTagged指针字符串"RCp1xmeaxi" 0xe300000000000000标志字符串?一些_guts_字符串Guts_对象_字符串对象
_计数和标志位UInt64 13835058055282165492_对象内置桥接对象0x4000000128065000
- 国家视图模型**
import SwiftUI
结构国家:可编码、可识别、可比较、可散列{
let id = UUID() // New
let name: String
let isoAlpha3: String
let flag: String?
enum CodingKeys: String, CodingKey {
case name, isoAlpha3, flag
}
var flagImage: UIImage? {
if let flagString = flag,
let data = flagString.data(using: .utf8),
let decodedData = Data(base64Encoded: data),
let image = UIImage(data: decodedData) {
return image
} else {
let img = UIImage(systemName: "plus.circle")
return img == nil ? UIImage() : img!
}
}
static func == (lhs: Country, rhs: Country) -> Bool {
lhs.name == rhs.name
}
static func < (lhs: Country, rhs: Country) -> Bool {
lhs.name < rhs.name
}
struct HeadingData: Codable, Identifiable, Hashable {
let id: Int
let name: String
let isoAlpha3: String
let flag: String
}
struct CurrencyData: Codable, Equatable, Identifiable, Hashable {
let id: UUID
let code: String
let name: String
let symbol: String
}
}
类别国家型号:可观测天体{@已发布变量国家:[国家]=[]
init() {
self.countries = Bundle.main.decode("Countries.json")
}
}
- 选取器扩展**
var hostCountry: some View {
VStack(alignment: .leading) {
Picker(selection: $clientVM.clientHostCountry,
label: Text("")) {
ForEach(countryVM.countries) { country in
VStack {
Text(country.name)
Image(uiImage: country.flagImage!)
}.tag(country as Country)
}
.padding(.horizontal, 10)
.padding()
.pickerStyle(MenuPickerStyle())
}.padding(.horizontal)
}
2条答案
按热度按时间8yparm6h1#
您可以尝试这种简单的方法,显示标志的
Image
,对我来说很有效:从json数据中可以看出,
flag
是一个String
,所以确保在struct Country
中声明let flag: String?
,这样就可以在CountryModel
中解码json。编辑-1
在您的模型结构
Country
中,您可能需要使用以下代码:一旦你有了
Data
的图像,你就可以用它来存储在你的clientFlag
中,你的ClientEntity
和你的ClientViewModel
中。编辑-2:
在您的
Picker
中,与其使用if let data = country.flag!.data(using: .utf8),...etc
尝试再次解码标志,为什么不使用country.flagImage
呢?这正是您使用它的目的。在
Picker
中使用:p1iqtdky2#
您的标志图像字符串
iVBORw0KGgoAAAANSUhEUgAAAB4AAAAUCAIAAAAVyRqTAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw
几乎是base64,但不完全是-它缺少Data(base64encoded:)
所需的末尾填充字符。您可以像这样轻松地添加它们: