iOS17-18中UILabel设置NSAttributedString时NSFont为nil崩溃求助
解决方案:iOS17+设置NSAttributedString到UILabel时的NSFont nil崩溃问题
问题分析
从Crash日志和代码来看,崩溃仅出现在iOS17及以上版本(17.6.1、18),是系统处理UILabel的attributedText时,尝试给字典设置nil的NSFont值导致的。虽然代码里显式创建了字体对象,但存在两种潜在触发场景:
- 极端情况下
UIFont.systemFont(ofSize:weight:)可能返回nil(比如系统字体库异常、动态字体缩放的极端值) - iOS17+的UIKit内部在合成富文本属性时,可能出现属性丢失或nil注入的bug(尤其在cell复用场景下)
具体修复方案
1. 确保字体创建非空,添加兜底逻辑
修改prepareRating()里的字体创建代码,强制保证字体不为nil,兜底到系统默认字体:
private func prepareRating() { // Rating Status if let commentCount = hotel.commentCount, let ratingtext = hotel.averageScoreText { let commentText = (commentCount >= 3 ? " (\(commentCount) \(TextKey.hotelComment.localized))" : "") // 字体创建添加兜底,避免返回nil let boldFont = UIFont.systemFont(ofSize: 15, weight: .bold) ?? UIFont.systemFont(ofSize: 15) let regularFont = UIFont.systemFont(ofSize: 12) ?? UIFont.systemFont(ofSize: 12) let titleColor = UIColor.blue let mutableAttributedString = NSMutableAttributedString() mutableAttributedString.append(NSAttributedString(string: ratingtext, attributes: [.font: boldFont, .foregroundColor: titleColor])) mutableAttributedString.append(NSAttributedString(string: commentText, attributes: [.font: regularFont, .foregroundColor: titleColor])) self.ratingStatusAttributed = mutableAttributedString } else { // 兜底:条件不满足时设置空富文本,避免传递nil self.ratingStatusAttributed = NSAttributedString(string: "") } }
2. 给UILabel设置默认字体,避免系统合成时无 fallback
在HotelListTableViewCell的configure方法里提前给label设置默认字体,或者在xib/storyboard中配置明确的默认字体:
func configure(with data: HotelListPresentation) { let rating = data.averageScore ?? 0 ratingLabel.text = rating.ratingDescription ratingBackgroundView.tintColor = data.averageScoreColor ratingStackView.isHidden = rating == 0 ? true : false // 提前设置label默认字体,防止系统合成富文本时找不到字体 if ratingStatusLabel.font == nil { ratingStatusLabel.font = UIFont.systemFont(ofSize: 12) } // 处理nil情况,避免给attributedText设置nil ratingStatusLabel.attributedText = data.ratingStatusAttributed ?? NSAttributedString(string: "") }
3. 预检查NSAttributedString的所有属性(可选,彻底排查用)
如果崩溃仍间歇性出现,可以添加工具方法遍历富文本属性,确保NSFont不为nil:
extension NSAttributedString { func sanitizedForLabel() -> NSAttributedString { let mutable = NSMutableAttributedString(attributedString: self) mutable.enumerateAttributes(in: NSRange(location: 0, length: mutable.length), options: []) { attrs, range, stop in var safeAttrs = attrs if safeAttrs[.font] == nil { // 替换为默认字体 safeAttrs[.font] = UIFont.systemFont(ofSize: 12) mutable.setAttributes(safeAttrs, range: range) } } return mutable } }
设置时使用:
ratingStatusLabel.attributedText = data.ratingStatusAttributed?.sanitizedForLabel() ?? NSAttributedString(string: "")
4. 优化cell复用逻辑(可选)
如果是cell复用导致的极端场景,在prepareForReuse()中重置状态:
override func prepareForReuse() { super.prepareForReuse() ratingStatusLabel.attributedText = nil ratingStatusLabel.font = UIFont.systemFont(ofSize: 12) // 重置默认字体 }
总结
核心思路是确保字体属性绝对非空,同时给UILabel提供明确的默认字体兜底,避免iOS17+系统在合成富文本时出现nil字典操作。以上方案可覆盖绝大多数间歇性触发的场景。
内容的提问来源于stack exchange,提问作者Yılmaz edis
相关产品推荐
相关产品推荐

