【问题标题】:Saving UIFont? to UserDefault Swift 3保存 UIFont?到 UserDefault Swift 3
【发布时间】:2017-01-23 19:19:38
【问题描述】:

我创建了一个步进器来增加我的应用程序中的字体大小,现在,我想保存最后一个字体大小,这样当用户重新打开应用程序时,最后一个字体大小将保持不变。我试图将它保存到 UserDefaults 但它不会让我保存我的标签,因为我正在使用 UIFont 来建立我想要的字体类型,并且 CGFloat 能够使用我的步进器切换字体大小。

当我运行应用程序并尝试选择字体大小时,应用程序崩溃,我找不到问题。我知道问题在于尝试将 UIFont 中的数据保存到 UserDefaults 中,因为当我注释掉那行代码时,应用程序运行没有问题。

另外,在我尝试调用 ViewDidAppear 函数中存储的 UserDefault 设置后,我收到一条错误消息,提示我无法分配 Any?输入 UIFont?

任何帮助将不胜感激。同样,我的意图是,当用户使用步进器更改字体大小时,字体大小将保持不变,即使在退出并重新打开应用程序后也是如此。

import UIKit
import Foundation

class ViewController: UIViewController {
@IBOutlet weak var quotesLabel: UITextView!
@IBOutlet weak var welcomeLabel: UILabel!
@IBOutlet weak var topLabel: UILabel!
@IBOutlet weak var generateLabel: UILabel!
@IBOutlet weak var fontStepper: UIStepper!
@IBOutlet weak var minFontSizeLabel: UILabel!
@IBOutlet weak var adjustFontSizeLabel: UILabel!
@IBOutlet weak var maxFontSizeLabel: UILabel!


    let quotesBook = QuotesBook()
    let defaults = UserDefaults.standard



    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically   from a nib



        fontStepper.wraps = true
        fontStepper.autorepeat = true
        generateLabel.font = UIFont(name: "HoeflerText-Italic", size: 15)
        generateLabel.textColor = UIColor(red: 25/255, green: 23/255, blue: 170/255, alpha: 230/255)
        generateLabel.textAlignment = NSTextAlignment.center
        topLabel.font = UIFont(name: "HoeflerText-Italic", size: 20)
        topLabel.textColor = UIColor(red: 25/255, green: 23/255, blue: 170/255, alpha: 230/255)



}

override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

@IBAction func stepperPressed(_ sender: UIStepper) {
    quotesLabel.isEditable = true
    quotesLabel.font = UIFont (name: "Futura-MediumItalic", size: CGFloat(Float(sender.value)))
    defaults.set(quotesLabel.font, forKey: "textSize")




}
@IBAction func showQuoteBttn(_ sender: Any) {
    quotesLabel.textAlignment = NSTextAlignment.center
    maxFontSizeLabel.isHidden = false
    adjustFontSizeLabel.isHidden = false
    minFontSizeLabel.isHidden = false
    fontStepper.isHidden = false
    generateLabel.isHidden = false
    welcomeLabel.isHidden = true
    topLabel.isHidden = true
    quotesLabel.isHidden = false
    quotesLabel.text = quotesBook.randomQuote()

}

override func viewDidAppear(_ animated: Bool) {
    if let b = defaults.object(forKey: "textSize")
    {
    quotesLabel.font = b
    }

}

【问题讨论】:

  • 为什么不直接保存字体大小?
  • 您好!这就是为什么我正在尝试这样做。但是,我不想创建另一个按钮来保存字体大小。我想要做的是,一旦你完成使用步进器选择你想要的任何字体大小,应用程序会记住这个大小,直到你再次更改它。
  • 感谢大家提供的所有解决方案。我真的很感谢你们抽出时间来帮助我。我稍后会尝试一下。上帝保佑你们。

标签: ios swift


【解决方案1】:

您不能将(UI)Font 直接保存到用户默认值中,因为它不符合属性列表。

一个合适的解决方案是分别保存String 名称和Float 字体大小。这可以通过UserDefaults 的扩展来实现:

extension UserDefaults {

    func set(font : UIFont, forKey key : String)
    {
        let fontName = font.fontName
        let fontSize = font.pointSize
        self.set(fontName, forKey: key + "_name")
        self.set(Float(fontSize), forKey: key + "_size")
    }

    func font(forKey key : String) -> UIFont?
    {
        guard let fontName = string(forKey: key + "_name") else { return nil }
        let fontSize = float(forKey: key + "_size")
        if fontSize == 0.0 { return nil }
        return UIFont(name: fontName, size: CGFloat(fontSize))
    }
}

或者——也带有扩展名——将字体归档和取消归档到NSData

extension UserDefaults {

    func set(font: UIFont, forKey key: String)
    {
        let data = NSKeyedArchiver.archivedData(withRootObject: font)
        self.set(data, forKey: key)
    }

    func font(forKey key: String) -> UIFont?
    {
        guard let data = data(forKey: key) else { return nil }
        return NSKeyedUnarchiver.unarchiveObject(with: data) as? UIFont
    }
}

【讨论】:

  • @Lefteris 不,不是,可序列化和符合属性列表是两个独立的东西。
  • 其实不是。只要能转成NSData就可以保存
  • @Lefteris 它是可序列化的,但不符合属性列表。
【解决方案2】:

(这是我在寻找这个问题的解决方案时出现的第一个项目,所以我不妨分享一个可持续的解决方案。这里使用macOS,但NSFontDescriptor在iOS上也存在,只是替换UIFont)。

推荐的保存字体的方法是不要这样做(有点轻率,抱歉) - 但在 2013 年的 WWDC 会话 223 中(使用 TextKit 字体),建议专门针对 a) 不挑选属性(换句话说,不只保存字体名称和大小)和 b) 不保存 NSFont,而是保存 NSFontDescriptor。

NSFontDescriptor 是一个容易被忽视的类,但documentation 很清楚

符号特征取代了 NSFontManager 使用的现有 NSFontTraitMask 类型。

所以我们应该使用它。尤其是在 iOS 上,你可以用它做很多奇怪而美妙的事情,包括你想要使用的字体的层叠首选项、特定语言的设置等等。

保存,假设您有一个名为 'font' 的字体:

  let fontDescriptor = font.fontDescriptor
           let descriptorData = NSKeyedArchiver.archivedData(withRootObject: fontDescriptor)
            userDefaults.set(descriptorData, forKey: "descriptorData")

阅读:

if let descriptorData = userDefaults.data(forKey: "descriptorData"){
        if let fontDescriptor = NSKeyedUnarchiver.unarchiveObject(with: descriptorData) as? NSFontDescriptor {
            let myFont = NSFont(descriptor: fontDescriptor, size: 0)
        }
    }

将大小设置为“0”意味着它从描述符中获取大小,否则您将覆盖它。

这不会保存字体颜色;如果要保存默认文本颜色,您仍然需要单独执行此操作。

编辑添加 UIKit

好的,blink 和 iOS 的变化(我错了 NSFontDescriptor,它是 UIFontDescriptor,当前的 macOS 方法已被弃用:

let font = UIFont.systemFont(ofSize: 14)


let fontDescriptor = font.fontDescriptor
let descriptorData = try NSKeyedArchiver.archivedData(withRootObject: fontDescriptor, requiringSecureCoding: true)
UserDefaults.standard.set(descriptorData, forKey: "descriptorData")

if let descriptorData = UserDefaults.standard.data(forKey: "descriptorData"){
    if let fontDescriptor = try NSKeyedUnarchiver.unarchivedObject(ofClass: UIFontDescriptor.self, from: descriptorData) {
        let myFont = UIFont(descriptor: fontDescriptor, size: 0)
    }
}

(这是在操场上编译的;我没有在 iOS 应用程序中测试过)

【讨论】:

  • 不适用于 iOS,Code=4864 "value for key 'font' was of unexpected class 'UIFontDescriptor'
  • 我已经添加了iOS代码;这适用于游乐场,应该适用于应用程序。
  • 我显然使用了 UIFontDescriptor 而不是 NS,但我的解码失败了。我最终保存了字体系列和大小,然后编写了字体
【解决方案3】:

UIFont 无法保存到 UserDefaults。如果需要,您可以只保存字体大小和字体名称。

将字体保存到UserDefaults:

let font = UIFont.systemFont(ofSize: 15)
let defaults = UserDefaults()
defaults.set(font.pointSize, forKey: "font")
defaults.set(font.fontName, forKey: "fontName")

稍后恢复:

let fontSize = defaults.float(forKey: "font")
let fontName = defaults.string(forKey: "fontName")
if let name = fontName {
    let savedFont = UIFont(name: name, size: CGFloat(fontSize))
    print("Saved font: \(savedFont)")
}
else {
    // Use default font
}

【讨论】:

  • 任何东西都可以保存到NSUserdefaults只要能转换成NSData
猜你喜欢
  • 2018-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多