2016-12-16 37 views
4

我想为Swift中的所有highlightable视图创建一个共同的祖先。我想是实现highlighted财产已有UIKit类工作开箱即用,所以阅读this answer和检查the Objective-C getter is defined as isHighlighted后,我改变了协议定义的:使用Objective-C属性获取器实现Swift协议

@objc protocol Highlightable { 
    var highlighted: Bool { @objc(isHighlighted) get set } 
} 

所以对于UILabelUIControl协议实现是这样简单:

extension UILabel: Highlightable {} 
extension UIControl: Highlightable {} 

这个伟大的工程,我可以访问和设置雨燕highlighted财产Highlightable实例。然而,当我试图实现协议上我的雨燕班,也不像这个最简单的实现:

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 
} 

回答

1

UILabelUIControl扩展满足您创建协议的方式,因为他们已经有一个名为highlighted其吸气访问方法是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代码。

编辑:

看着斯威夫特对于iOS的10 API的diff(和在Xcode 7.2做一些测试),UILabelUIControlisHighlighted财产原名highlighted。使用上面的代码与iOS SDK 9.3或更低版本进行链接时会导致编译时错误。

在第一个示例中,可以通过将label.isHighlighted行重命名为label.highlighted来修复这些错误。

在第二个示例中,可以通过将isHighlighted的所有实例重命名为highlighted@objc属性的括号内的那些除外)来解决这些错误。

9.3到iOS 10.0 API差异:https://developer.apple.com/library/content/releasenotes/General/iOS10APIDiffs/index.html

+0

你有测试了第一个样本?我无法得到它编译 – redent84

+0

@ redent84是的。它编译罚款(Xcode 8.2)。你能分享这个错误吗? –

+0

它不适用于XCode 8.0,但它在XCode 8.2上工作。 – redent84

0

我有一个解决方案,但它有点不是你想要更大,但我认为这将帮助你。

你应该做快速的协议,并确定类默认实现需要

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 
} 

我希望它可以帮助你什么。