如何解决我可以打印数据,但不能在Swift中将其分配给标签 1 fetchPokemons实施 2更新viewDidLoad() 3重构var pokemon: Pokemon? didSet观察者
我将数据从API调用发送到了InfoController viewDidLoad。在那里,我能够安全地将其存储在skillName常量中,并打印出来,并通过控制台接收所有信息。
当我尝试将此变量分配给SkillLabel时出现问题。
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时,控制台将显示我需要的所有数据。数据如下所示:Data Example
我想使用此数据的外观的计算属性为:
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类级别具有的String变量。
这是我的应用在运行时的外观: PokeApp
我的目标是获取详细信息参数以显示skillName数据,但它返回nil,idk为什么。有什么建议吗?
EDIT1 :从我的服务类中获取Pokemon数据的函数是这个函数:
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设置都是非常重要的。
编辑:
获取功能可能会导致问题!您多次调用处理程序:
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)
}
}
}
Edit2:
查看代码库后,您需要更改以下几项内容:
1。 fetchPokemons
实施
controller.service.fetchPokes
的处理程序被每个宠物小精灵调用,因此我们需要检查所获取的是当前(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,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)
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。