我想为Swift中所有可突出显示的视图创建一个共同的祖先。我希望现有的实现highlighted
属性的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中的highlighted
属性设置为Highlightable
个实例。但是,当我尝试在我的Swift类上实现协议时,即使是最简单的实现,如下所示:
class HighlightableView: UIView, Highlightable {
var highlighted: Bool = false
}
我收到此编译错误:
Objective-C方法'突出显示'由getter提供以突出显示'与要求的选择器不匹配(' 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
}
答案 0 :(得分:1)
您的UILabel
和UIControl
扩展程序符合您创建协议的方式,因为它们已经有一个名为highlighted
的属性,其getter访问器方法为isHighlighted
。
您的HighlightableView
无法满足您Highlightable
协议的要求,因为您对获取者有@objc(isHighlighted)
要求。
您必须使用计算属性来满足此要求。但是,这意味着您还需要highlighted
属性的后备存储。类似于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
的{{1}}属性以前被命名为isHighlighted
。在链接iOS SDK 9.3或更低版本时使用上面的代码将导致编译时错误。
在第一个示例中,可以通过将highlighted
行重命名为label.isHighlighted
来修复这些错误。
在第二个示例中,可以通过将label.highlighted
的所有实例重命名为isHighlighted
来修复这些错误(highlighted
属性括号内除外)。
9.3到iOS 10.0 API差异:https://developer.apple.com/library/content/releasenotes/General/iOS10APIDiffs/index.html
答案 1 :(得分:0)
我有一个解决方案,但它比你想要的要大,但我认为它会对你有帮助。
您应该执行swift协议并确定所需类的默认实现
protocol Highlightable: class {
var highlighted: Bool { get set }
}
extension Highlightable where Self: UILabel {
var highlighted: Bool {
get {
return isHighlighted
}
set {
isHighlighted = newValue
}
}
}
extension Highlightable where Self: UIControl {
var highlighted: Bool {
get {
return isHighlighted
}
set {
isHighlighted = newValue
}
}
}
所以你可以实现它
extension UILabel: Highlightable {}
extension UIControl: Highlightable {}
class CustomView: UIView, Highlightable {
var highlighted: Bool = false
}
我希望它可以帮到你。