我可以打印数据,但可以';t在Swift中将其分配给标签
我将API调用中的数据发送到InfoController viewDidLoad。在那里,我能够安全地将它存储在skillName常量中,并打印它,通过控制台接收所有信息 当我尝试将此变量分配给skillLabel时,问题就出现了我可以打印数据,但可以';t在Swift中将其分配给标签,swift,string,viewdidload,computed-properties,Swift,String,Viewdidload,Computed Properties,我将API调用中的数据发送到InfoController viewDidLoad。在那里,我能够安全地将它存储在skillName常量中,并打印它,通过控制台接收所有信息 当我尝试将此变量分配给skillLabel时,问题就出现了 override func viewDidLoad() { super.viewDidLoad() configureViewComponents() fetchPokemons { (names) in guard var s
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)
}
}
在那里,当我打印所有名称时,控制台显示我需要的所有数据。以下是数据的外观:
我想使用这些数据的计算属性是:
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类级别拥有的字符串变量
这是我的应用在运行时的外观:
我的目标是让details参数显示skillName数据,但它返回nil,idk why。有什么建议吗
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(带pokemon:pokemon?,详细信息:String?){
guard let id=pokemon?.id,let data=pokemon?.image else{return}
navigationItem.title=pokemon?.name?.capitalized
infoLabel.text=pokemon?.description
infoView.pokemon=pokemon
如果id==口袋妖怪?.id{
imageView.image=UIImage(数据:数据)
infoView.configureLabel(标签:infoView.skillLabel,标题:“技能”,详细信息:详细信息??)
}
}
现在您可以轻松地调用didSet
var口袋妖怪:口袋妖怪?{
didSet{updateView(with:pokemon,details:allNames)}
}
还有fetchPokemons
completion
override func viewDidLoad(){
super.viewDidLoad()
configureViewComponents()
获取口袋妖怪{(名称)在
guard var skillName=名称为?字符串else{return}
self.pokemon?.skillName=skillName
self.allNames=skillName
打印(self.allNames)
DispatchQueue.main.async{
self.updateView(使用:self.pokemon,详细信息:self.allNames)
}
}
}
在主队列上进行任何UI设置都非常重要
编辑:
fetch函数可能是导致问题的原因!您多次调用处理程序:
func-fetchPokemons(处理程序:@escaping(String)->Void){
controller.service.fetchPokes{(戳)入
DispatchQueue.main.async{
self.pokemon?=戳
守卫技能=poke.abilities else{return}
让names=skills.compactMap{$0.ability?.name?.capitalized}.joined(分隔符:“,”)
处理程序(名称)
}
}
}
编辑2:
查看代码库后,您需要更改以下几项:
1. <代码>抓取口袋妖怪实现
每个口袋妖怪都会调用controller.service.fetchPokes
的处理程序,因此我们需要检查获取的处理程序是否为当前处理程序(self.pokemon),然后使用正确格式的技能调用处理程序
func-fetchPokemons(处理程序:@escaping(String)->Void){
controller.service.fetchPokes{(戳)入
guard poke.id==self.pokemon?.id else{return}
self.pokemon?=戳
让names=poke.abilities?.compactMap{$0.ability?.name?.capitalized}.joined(分隔符:“,”)
处理程序(名称为“-”)
}
}
2.更新viewDidLoad()
现在只需将名称
值传递给标签即可
override func viewDidLoad(){
super.viewDidLoad()
configureViewComponents()
获取口袋妖怪{(名称)在
self.pokemon?.skillName=名称
self.infoView.configureLabel(标签:self.infoView.skillLabel,标题:“技能”,详细信息:名称)
}
}
3.重构var pokemon:pokemon?
didSet-observer
var口袋妖怪:口袋妖怪?{
迪塞特{
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(数据:数据)
}
}
如果你通过了self.pokemon?.skillName
而不是self.allNames
?同样的结果,而且我的CollectionView加载速度比重构前慢。你能在问题中包含更多的代码吗?更多的背景会更好。需要检查的一件事是infoView.skillLabel
是否与当前显示的相同。如果您提到collectionView,可能会尝试在抓取完成后调用reloadData()
?好吧,我的应用程序是这样工作的:CollectionViewController显示每个项目的图像和名称。如果你点击一个项目,它会推送到我的InfoViewController,在那里我真的想展示技能。我认为infoView.skillLabel
与当前显示的绝对相同,否则它不会显示空的“”,而不是我想要的值,因此infoView.skillLabel
本身不在某种UICollectionViewCell中,而是一个静态标签,对吗?我很想看到infoView.configureLabel的实现,也许还有infoView