swift - 我可以打印数据但不能将其分配给 Swift 中的标签
问题描述
我将我的 API 调用中的数据发送到我的 InfoController viewDidLoad。在那里,我能够将它安全地存储在一个技能名称常量中,并打印它,通过控制台接收所有信息。
当我尝试将此变量分配给我的技能标签时,问题就来了。
override func viewDidLoad() {
super.viewDidLoad()
configureViewComponents()
fetchPokemons { (names) in
guard var skillName = names as? String else { return }
self.pokemon?.skillName = skillName
self.allNames = skillName
print(self.allNames)
}
}
在那里,当我打印 allNames 时,控制台会显示我需要的所有数据。这是数据的样子:数据示例
我想使用这些数据的计算属性是:
var pokemon: Pokemon? {
didSet {
guard let id = pokemon?.id else { return }
guard let data = pokemon?.image else { return }
navigationItem.title = pokemon?.name?.capitalized
infoLabel.text = pokemon?.description
infoView.pokemon = pokemon
if id == pokemon?.id {
imageView.image = UIImage(data: data)
infoView.configureLabel(label: infoView.skillLabel, title: "Skills", details: "\(allNames)")
}
}
}
PD: allNames 是我在 InfoController 类级别拥有的字符串变量。
这是我的应用程序在运行时的样子: PokeApp
我的目标是获取详细信息参数以显示 SkillName 数据,但它返回 nil,不知道为什么。有什么建议吗?
EDIT1:我从我的服务类中获取口袋妖怪数据的函数是这个:
func fetchPokemons(handler: @escaping (String) -> Void) {
controller.service.fetchPokes { (poke) in
DispatchQueue.main.async {
self.pokemon? = poke
guard let skills = poke.abilities else { return }
for skill in skills {
guard let ability = skill.ability else { return }
guard var names = ability.name!.capitalized as? String else { return }
self.pokemon?.skillName = names
handler(names)
}
}
}
}
EDIT2: InfoView 类看起来像:
class InfoView: UIView {
// MARK: - Properties
var delegate: InfoViewDelegate?
// This whole block assigns the attributes that will be shown at the InfoView pop-up
// It makes the positioning of every element possible
var pokemon: Pokemon? {
didSet {
guard let pokemon = self.pokemon else { return }
guard let type = pokemon.type else { return }
guard let defense = pokemon.defense else { return }
guard let attack = pokemon.attack else { return }
guard let id = pokemon.id else { return }
guard let height = pokemon.height else { return }
guard let weight = pokemon.weight else { return }
guard let data = pokemon.image else { return }
if id == pokemon.id {
imageView.image = UIImage(data: data)
}
nameLabel.text = pokemon.name?.capitalized
configureLabel(label: typeLabel, title: "Type", details: type)
configureLabel(label: pokedexIdLabel, title: "Pokedex Id", details: "\(id)")
configureLabel(label: heightLabel, title: "Height", details: "\(height)")
configureLabel(label: defenseLabel, title: "Defense", details: "\(defense)")
configureLabel(label: weightLabel, title: "Weight", details: "\(weight)")
configureLabel(label: attackLabel, title: "Base Attack", details: "\(attack)")
}
}
let skillLabel: UILabel = {
let label = UILabel()
return label
}()
let imageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFill
return iv
}()
. . .
}
infoView.configureLabel 是这样的:
func configureLabel(label: UILabel, title: String, details: String) {
let attributedText = NSMutableAttributedString(attributedString: NSAttributedString(string: "\(title): ", attributes: [NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 16), NSAttributedString.Key.foregroundColor: Colors.softRed!]))
attributedText.append(NSAttributedString(string: "\(details)", attributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16), NSAttributedString.Key.foregroundColor: UIColor.gray]))
label.attributedText = attributedText
}
编辑 3:结构设计
struct Pokemon: Codable {
var results: [Species]?
var abilities: [Ability]?
var id, attack, defense: Int?
var name, type: String?
...
}
struct Ability: Codable {
let ability: Species?
}
struct Species: Codable {
let name: String?
let url: String?
}
解决方案
跳转到 Edit2 段落以获得最终答案!
初步答案:
我看起来你的 UI 在控制器获取所有数据后没有更新。
由于所有的 UI 配置代码都在var pokemon / didSet
.
private func updateView(with pokemon: Pokemon?, details: String?) {
guard let id = pokemon?.id, let data = pokemon?.image else { return }
navigationItem.title = pokemon?.name?.capitalized
infoLabel.text = pokemon?.description
infoView.pokemon = pokemon
if id == pokemon?.id {
imageView.image = UIImage(data: data)
infoView.configureLabel(label: infoView.skillLabel, title: "Skills", details: details ?? "")
}
}
现在您可以轻松调用didSet
var pokemon: Pokemon? {
didSet { updateView(with: pokemon, details: allNames) }
}
并fetchPokemons
完成
override func viewDidLoad() {
super.viewDidLoad()
configureViewComponents()
fetchPokemons { (names) in
guard var skillName = names as? String else { return }
self.pokemon?.skillName = skillName
self.allNames = skillName
print(self.allNames)
DispatchQueue.main.async {
self.updateView(with: self.pokemon, details: self.allNames)
}
}
}
在主队列上进行任何 UI 设置都非常重要。
编辑:
fetch 函数可能会导致问题!您正在多次调用处理程序:
func fetchPokemons(handler: @escaping (String) -> Void) {
controller.service.fetchPokes { (poke) in
DispatchQueue.main.async {
self.pokemon? = poke
guard let skills = poke.abilities else { return }
let names = skills.compactMap { $0.ability?.name?.capitalized }.joined(separator: ", ")
handler(names)
}
}
}
编辑2:
查看您的代码库后,您需要更改几件事:
1.fetchPokemons
实施
每个controller.service.fetchPokes
pokemon都会调用处理程序,因此我们需要检查获取的是否是当前的(self.pokemon),然后使用格式正确的技能调用。handler
func fetchPokemons(handler: @escaping (String) -> Void) {
controller.service.fetchPokes { (poke) in
guard poke.id == self.pokemon?.id else { return }
self.pokemon? = poke
let names = poke.abilities?.compactMap { $0.ability?.name?.capitalized }.joined(separator: ", ")
handler(names ?? "-")
}
}
2.更新viewDidLoad()
现在只需将names
值传递给标签。
override func viewDidLoad() {
super.viewDidLoad()
configureViewComponents()
fetchPokemons { (names) in
self.pokemon?.skillName = names
self.infoView.configureLabel(label: self.infoView.skillLabel, title: "Skills", details: names)
}
}
3.重构var pokemon: Pokemon?
didSet 观察者
var pokemon: Pokemon? {
didSet {
guard let pokemon = pokemon, let data = pokemon.image else { return }
navigationItem.title = pokemon.name?.capitalized
infoLabel.text = pokemon.description!
infoView.pokemon = pokemon
imageView.image = UIImage(data: data)
}
}
推荐阅读
- dynamics-crm - 查找字段中的文档模板实体
- python - 如何从文件中删除一行?
- vb.net - Microsoft.ACE.OLEDB 未在本地计算机上注册
- postgresql - 如何在多列上创建唯一约束,一列可以有单个空值
- java - Android 蓝牙程序在大约一分钟后停止接收字符。java.io.exception:BT 套接字关闭读取返回:-1
- android - 在后端将 MVVM 和 n 层架构与 Firestore 相结合
- android - Google Pay 电子钱包中的访问卡
- python - 如何从采用“bool”类型的矩阵中调用方法?
- bash - 父退出时如何使Bash后台命令退出?
- pca - 主成分分析阈值