将@available 与存储属性一起使用
Using @available with stored properties
我有一个使用本地通知并支持 iOS10 的应用程序。我正在尝试添加 iOS9 支持,这需要我使用旧的位置通知 API。我正在尝试在我的 iOS 10 代码上使用 @available
和 #available
,但我不知道如何让我的中心变量仅适用于设备 运行 iOS10.
当我将目标从 iOS 10 设置为 9 时,我收到此变量的错误消息:
UNUserNotificationCenter is only available on iOS 10.0 or newer.
它建议我将 @available(iOS 10.0, *)
添加到我的整个 class 中,但我不想这样做,因为此 class 中的代码将用于 iOS 9. 我感谢任何关于如何将我的中心 属性 限制为 iOS 10.
的建议
class ViewController: UIViewController, UITextFieldDelegate {
let center = UNUserNotificationCenter.current()
...
}
@available
可用于整个 class 或一个或多个函数,但不能用于属性。
关于您的 UNUserNotificationCenter 用法,current
returns 一个永远不会改变的单例,所以为什么不直接删除 center
常量,而只使用 UNUserNotificationCenter.current()
其中 center
被使用了?
let validClass = NSClassFromString("UNUserNotificationCenter") != nil
使用 validClass
来确定特定于 iOS 10 的代码,例如:
if validClass
// iOS 10 code
else
// Earlier than iOS 10 code
这是一个可能的解决方案(感谢 blog post)。这个想法是使用类型为 Any
的存储 属性,然后创建一个计算的 属性,它将转换存储的 属性(并在必要时实例化它)。
private var _selectionFeedbackGenerator: Any? = nil
@available(iOS 10.0, *)
fileprivate var selectionFeedbackGenerator: UISelectionFeedbackGenerator {
if _selectionFeedbackGenerator == nil {
_selectionFeedbackGenerator = UISelectionFeedbackGenerator()
}
return _selectionFeedbackGenerator as! UISelectionFeedbackGenerator
}
另一个是使用lazy
(但是,这使得变量可读写):
@available(iOS 10.0, *)
private(set) lazy var center = UNUserNotificationCenter.current()
与 kgaidis 类似的想法,通过使用任何版本都接受的类型的单独存储 属性。但是 Any
可能太通用了,因为它不能被声明为 weak
例如,所以在某些情况下你可能想用一个符合协议的协议来替换它:
private weak var _notificationCenterDelegate: NSObjectProtocol?
@available(iOS 10.0, *)
var notificationCenterDelegate: UNUserNotificationCenterDelegate? {
return _notificationCenterDelegate as? UNUserNotificationCenterDelegate
}
我知道这是一个较旧的问题,但我想为像我一样通过 Google 来到这里的人添加一个答案。
正如 kgaidis 和 Coeur 提到的,您可以在计算属性上使用 @available
。但是,lazy
变量被视为计算属性,因此您也可以对它们使用 @available
。这有一个很好的好处,那就是删除额外存储的 属性 和强制转换的样板 - 事实上,它不会在你的 pre-iOS 10 代码中留下 属性 的证据。
您可以像这样简单地声明它:
@available(iOS 10.0, *)
private(set) lazy var center = UNUserNotificationCenter.current()
不幸的是,没有办法让它完全只读,但 private(set)
至少让它在 class.
之外只读
我在我的应用程序中用于反馈生成器的代码支持 iOS 9. 如您所见,它很简单并且没有强制转换。主要思想是将值存储在 Any?
属性 中并通过计算值使用它。
private var storedFeedbackGenerator: Any? = nil
@available(iOS 10.0, *)
private var feedbackGenerator: UISelectionFeedbackGenerator {
if let generator = storedFeedbackGenerator as? UISelectionFeedbackGenerator {
return generator
}
let generator = UISelectionFeedbackGenerator()
generator.prepare()
storedFeedbackGenerator = generator
return generator
}
对于objective-c
@property (nonatomic, strong) CustomClass *object API_AVAILABLE(ios(10.0));
我有一个使用本地通知并支持 iOS10 的应用程序。我正在尝试添加 iOS9 支持,这需要我使用旧的位置通知 API。我正在尝试在我的 iOS 10 代码上使用 @available
和 #available
,但我不知道如何让我的中心变量仅适用于设备 运行 iOS10.
当我将目标从 iOS 10 设置为 9 时,我收到此变量的错误消息:
UNUserNotificationCenter is only available on iOS 10.0 or newer.
它建议我将 @available(iOS 10.0, *)
添加到我的整个 class 中,但我不想这样做,因为此 class 中的代码将用于 iOS 9. 我感谢任何关于如何将我的中心 属性 限制为 iOS 10.
class ViewController: UIViewController, UITextFieldDelegate {
let center = UNUserNotificationCenter.current()
...
}
@available
可用于整个 class 或一个或多个函数,但不能用于属性。
关于您的 UNUserNotificationCenter 用法,current
returns 一个永远不会改变的单例,所以为什么不直接删除 center
常量,而只使用 UNUserNotificationCenter.current()
其中 center
被使用了?
let validClass = NSClassFromString("UNUserNotificationCenter") != nil
使用 validClass
来确定特定于 iOS 10 的代码,例如:
if validClass
// iOS 10 code
else
// Earlier than iOS 10 code
这是一个可能的解决方案(感谢 blog post)。这个想法是使用类型为 Any
的存储 属性,然后创建一个计算的 属性,它将转换存储的 属性(并在必要时实例化它)。
private var _selectionFeedbackGenerator: Any? = nil
@available(iOS 10.0, *)
fileprivate var selectionFeedbackGenerator: UISelectionFeedbackGenerator {
if _selectionFeedbackGenerator == nil {
_selectionFeedbackGenerator = UISelectionFeedbackGenerator()
}
return _selectionFeedbackGenerator as! UISelectionFeedbackGenerator
}
另一个lazy
(但是,这使得变量可读写):
@available(iOS 10.0, *)
private(set) lazy var center = UNUserNotificationCenter.current()
与 kgaidis 类似的想法,通过使用任何版本都接受的类型的单独存储 属性。但是 Any
可能太通用了,因为它不能被声明为 weak
例如,所以在某些情况下你可能想用一个符合协议的协议来替换它:
private weak var _notificationCenterDelegate: NSObjectProtocol?
@available(iOS 10.0, *)
var notificationCenterDelegate: UNUserNotificationCenterDelegate? {
return _notificationCenterDelegate as? UNUserNotificationCenterDelegate
}
我知道这是一个较旧的问题,但我想为像我一样通过 Google 来到这里的人添加一个答案。
正如 kgaidis 和 Coeur 提到的,您可以在计算属性上使用 @available
。但是,lazy
变量被视为计算属性,因此您也可以对它们使用 @available
。这有一个很好的好处,那就是删除额外存储的 属性 和强制转换的样板 - 事实上,它不会在你的 pre-iOS 10 代码中留下 属性 的证据。
您可以像这样简单地声明它:
@available(iOS 10.0, *)
private(set) lazy var center = UNUserNotificationCenter.current()
不幸的是,没有办法让它完全只读,但 private(set)
至少让它在 class.
我在我的应用程序中用于反馈生成器的代码支持 iOS 9. 如您所见,它很简单并且没有强制转换。主要思想是将值存储在 Any?
属性 中并通过计算值使用它。
private var storedFeedbackGenerator: Any? = nil
@available(iOS 10.0, *)
private var feedbackGenerator: UISelectionFeedbackGenerator {
if let generator = storedFeedbackGenerator as? UISelectionFeedbackGenerator {
return generator
}
let generator = UISelectionFeedbackGenerator()
generator.prepare()
storedFeedbackGenerator = generator
return generator
}
对于objective-c
@property (nonatomic, strong) CustomClass *object API_AVAILABLE(ios(10.0));