我想为
Swift中所有可突出显示的视图创建一个共同的祖先.我希望现有的UIKit类实现突出显示的属性是开箱即用的,所以在阅读
this answer并检查
the Objective-C getter is defined as isHighlighted
之后,我将协议定义更改为:
@objc protocol Highlightable {
var highlighted: Bool { @objc(isHighlighted) get set }
}
所以UILabel和UIControl的协议实现就像这样简单:
extension UILabel: Highlightable {}
extension UIControl: Highlightable {}
这很好用,我可以从Swift访问并设置突出显示的属性作为Highlightable实例.但是,当我尝试在我的Swift类上实现协议时,即使是最简单的实现,如下所示:
class HighlightableView: UIView, Highlightable {
var highlighted: Bool = false
}
我得到这个编译错误:
Objective-C method ‘highlighted’ provided by getter for ‘highlighted’ does not match the requirement’s selector (‘isHighlighted’)
我能让它工作的唯一方法是使用计算属性,但这不是我想要的.
class HighlightableView: UIView, Highlightable {
var highlighted: Bool { @objc(isHighlighted) get { return true } set {} }
}
我的环境是Xcode 8.0和Swift 3.更新到XCode 8.2并且错误仍然存在.
我目前的解决方法是完全避免Objective-C和Swift之间的任何命名冲突.但这远非理想:
@objc protocol Highlightable {
var _highlighted: Bool { get set }
}
extension UILabel: Highlightable {
var _highlighted: Bool {
get { return isHighlighted }
set { isHighlighted = newValue }
}
}
extension UIControl: Highlightable {
var _highlighted: Bool {
get { return isHighlighted }
set { isHighlighted = newValue }
}
}
class HighlightableView: UIView, Highlightable {
var _highlighted: Bool = false
}
最佳答案 您的UILabel和UIControl扩展符合您创建协议的方式,因为它们已经有一个名为highlight的属性,其getter访问器方法是突出显示的.
您的HighlightableView不满足您的Highlightable协议的采用,因为您的getter上有@objc(isHighlighted)要求.
您必须使用计算属性来满足此要求.但是,这意味着您还需要突出显示的属性的后备存储.像private var _highlighted = false之类的东西.
在您的情况下,由于这是不合需要的,您可以删除协议上的@objc属性.
protocol Highlightable: class {
var highlighted: Bool { get set }
}
extension UILabel: Highlightable { }
extension UIControl: Highlightable { }
class HighlightableView: UIView, Highlightable {
var highlighted = false
}
let label = UILabel()
label.isHighlighted // Prior to iOS 10, this property is called "highlighted"
let view = HighlightableView()
view.highlighted
let highlightables: [Highlightable] = [ label, view ]
for highlightable in highlightables {
print(highlightable.highlighted)
}
// Prints:
// false
// false
但是,属性名称在具体类型中不一致.
这是另一种方法:
@objc protocol Highlightable: class {
var isHighlighted: Bool { @objc(isHighlighted)get @objc(setHighlighted:)set }
}
extension UILabel: Highlightable { }
extension UIControl: Highlightable { }
class HighlightableView: UIView, Highlightable {
private var _isHighlighted = false
var isHighlighted: Bool {
@objc(isHighlighted) get {
return _isHighlighted
}
@objc(setHighlighted:) set {
_isHighlighted = newValue
}
}
}
let label = UILabel()
label.isHighlighted = true
let view = HighlightableView()
view.isHighlighted
let highlightables: [Highlightable] = [ label, view ]
for highlightable in highlightables {
print(highlightable.isHighlighted)
}
// Prints:
// false
// false
这会在所有具体类型中公开一致的isHighlighted属性,同时仍符合Highlightable.这里的缺点是@objc属性在不需要的上下文中更为普遍.也就是说,@ objc属性不用于将Swift协议暴露给Objective-C代码.
编辑:
查看Swift的iOS 10 API差异(并在Xcode 7.2中进行一些测试),UILabel和UIControl的isHighlighted属性以前被命名为突出显示.在链接iOS SDK 9.3或更低版本时使用上面的代码将导致编译时错误.
在第一个示例中,可以通过将label.isHighlighted行重命名为label.highlighted来修复这些错误.
在第二个示例中,可以通过将isHighlighted的所有实例重命名为突出显示来修复这些错误(除了@objc属性括号内的那些实例).
9.3到iOS 10.0 API差异:https://developer.apple.com/library/content/releasenotes/General/iOS10APIDiffs/index.html