为什么在分段控件上使用 UIControlState.normal 导致此崩溃?

Why is using UIControlState.normal on a segmented control causing this crash?

我有一个简单的 UISegmentedControl,有两个部分,我正在尝试自定义它的外观。

我收到这个运行时错误:

*** Terminating app due to uncaught exception >'NSInvalidArgumentException', reason: '-[NSNull renderingMode]: unrecognized selector sent to instance 0x112156f08'

@IBOutlet weak var sortController: UISegmentedControl!

override func viewDidLoad() {
    super.viewDidLoad()

    styleSortController()

    // other setup code

}

func styleSortController() {
    let titleAttributes: [String: Any] = [NSForegroundColorAttributeName: UIColor.white, NSFontAttributeName: UIFont(name: "AvenirNext-Demi", size: CGFloat(14.0)) as Any]
    let selectedTitleAttributes: [String: Any] = [NSForegroundColorAttributeName: UIColor.white,
                                                  NSFontAttributeName: UIFont(name: "AvenirNext-DemiBold", size: CGFloat(14.0)) as Any]

    // this line causes it to crash
    sortController.setTitleTextAttributes(titleAttributes, for: UIControlState.normal)

    // but this line works, no problem
    sortController.setTitleTextAttributes(selectedTitleAttributes, for: UIControlState.selected)
}

由上面看到的行引起,我首先尝试设置标题文本属性(请注意,设置属性的第二行工作正常)。

根据 Apple 的文档,我应该能够使用任何有效的 UIControlState 并且 UIControlState.normal 确实看起来有效,所以我真的很困惑为什么会这样。

这条线给我带来了什么麻烦?

我看到的第一个问题是你写的很多代码在 Swift 中被重命名了 4. 不再支持属性格式 [String: Any]。你必须使用 [NSAttributedString.Key: Any].

例如:NSForegroundColorAttributeName --> NSAttributedString.Key.foregroundColor

其次,字体 AvenirNext 没有任何样式 "Demi",它只有 "DemiBold".

let titleAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont(name: "AvenirNext-DemiBold", size: CGFloat(14.0)) as Any]
let selectedTitleAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont(name: "AvenirNext-DemiBold", size: CGFloat(14.0)) as Any]
let titleAttributes: [String: Any] = [NSForegroundColorAttributeName: UIColor.white, 
                                      NSFontAttributeName: UIFont(name: "AvenirNext-Demi", size: CGFloat(14.0)) as Any]
let selectedTitleAttributes: [String: Any] = [NSForegroundColorAttributeName: UIColor.white,
                                              NSFontAttributeName: UIFont(name: "AvenirNext-DemiBold", size: CGFloat(14.0)) as Any]

在说这是 UIControlState 问题之前,您需要做:

sortController.setTitleTextAttributes(selectedTitleAttributes, for: UIControlState.normal)

换句话说,使用相同的工作样本(.selected 的样本)

它应该会造成同样的错误崩溃。

然后你会发现罪魁祸首是UIFont(name: "AvenirNext-Demi", size: CGFloat(14.0)),它returns nil。

所以字体名称无效。

您可以遍历您的字体以列出它 (see this related question) 并找到正确的字体。 是一个"usual one",所以你可以打开字体Book.app,找到它,查看它的Post脚本名称。并非 macOS 中的所有字体都在 iOS 中,但那个字体就是这种情况。

您将获得:AvenirNext-RegularAvenirNext-MediumAvenirNext-UltraLight, AvenirNext-Italic, AvenirNext-MediumItalic, AvenirNext-UltraLightItalic, AvenirNext -DemiBold, AvenirNext-Bold, AvenirNext-Heavy, AvenirNext-DemiBoldItalic, AvenirNext-BoldItalic, AvenirNext-HeavyItalic.

没有AvenirNext-Demi

所以请使用您认为更适合您的需求。

如果您使用自定义字体,我建议您在 Mac 中安装它们。这样就可以很容易地查看字体的后记名称。