我有以下代码:
func registerNotification(name:String, selector:Selector)
{
NSNotificationCenter.defaultCenter().addObserver(self, selector: selector, name: name, object: nil)
}
func registerKeyboardNotifications()
{
let isInPopover = navigationController?.popoverPresentationController != nil
let ignore = isInPopover && DEVICE_IS_IPAD
if !ignore {
registerNotification(UIKeyboardWillShowNotification, selector: Selector("keyboardWillShow:"))
registerNotification(UIKeyboardWillHideNotification, selector: Selector("keyboardWillHide:"))
}
}
Run Code Online (Sandbox Code Playgroud)
在延伸UIViewController.许多viewcontroller重用此代码来注册键盘通知.但是使用Swift 2.2会产生警告.我喜欢新的#selector语法,但不知道在这种情况下如何实现它.
我认为正确的解决方案是制定协议并UIViewController仅针对符合该协议的实例进行扩展.我的代码到目前为止:
@objc protocol KeyboardNotificationDelegate
{
func keyboardWillShow(notification: NSNotification)
func keyboardWillHide(notification: NSNotification)
}
extension UIViewController where Self: KeyboardNotificationDelegate
{
func registerKeyboardNotifications()
{
let isInPopover = navigationController?.popoverPresentationController != nil
let ignore = isInPopover && DEVICE_IS_IPAD …Run Code Online (Sandbox Code Playgroud) 我们考虑以下代码:
protocol A {
func doA()
}
extension A {
func registerForNotification() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardDidShow:"), name: UIKeyboardDidShowNotification, object: nil)
}
func keyboardDidShow(notification: NSNotification) {
}
}
Run Code Online (Sandbox Code Playgroud)
现在看一下实现A的UIViewController子类:
class AController: UIViewController, A {
override func viewDidLoad() {
super.viewDidLoad()
self.registerForNotification()
triggerKeyboard()
}
func triggerKeyboard() {
// Some code that make key board appear
}
func doA() {
}
}
Run Code Online (Sandbox Code Playgroud)
但令人惊讶的是,这会因错误而崩溃:
keyboardDidShow:]:无法识别的选择器发送到实例0x7fc97adc3c60
那么我应该在视图控制器本身中实现观察者吗?不能留在延期?
以下事情已经尝试过.
制作A类协议.将keyboardDidShow添加到协议本身作为签名.
protocol A:class {
func doA()
func keyboardDidShow(notification: NSNotification)
}
Run Code Online (Sandbox Code Playgroud) 是否可以通过扩展将协议合规性添加到不同的协议?
例如,我们希望A符合B:
protocol A {
var a : UIView {get}
}
protocol B {
var b : UIView {get}
}
Run Code Online (Sandbox Code Playgroud)
我想给B类的对象提供B的默认实现(合规性)
// This isn't possible
extension A : B {
var b : UIView {
return self.a
}
}
Run Code Online (Sandbox Code Playgroud)
动机是在需要B的情况下重用A的对象而不创建我自己的"桥"
class MyClass {
func myFunc(object : A) {
...
...
let view = object.a
... do something with view ...
myFunc(object) // would like to use an 'A' without creating a 'B'
}
func myFunc2(object : B) {
...
... …Run Code Online (Sandbox Code Playgroud) 考虑以下:
protocol ViewControllable: class {
typealias VM: ViewModellable
var vm: VM! { get }
func bind()
}
extension ViewControllable {
var vm: VM! {
didSet {
bind()
}
}
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试观察vm属性并bind在注入时调用它.但这不会编译错误说:
扩展名可能不包含存储的属性
这是有道理的,因为协议不能强制执行属性stored或computed.
这可能在没有介绍的情况下完成class inheritance吗?
换句话说,我可以观察协议扩展内属性的变化吗?
是否可以从Objective-C调用Swift中协议扩展中定义的方法?
例如:
protocol Product {
var price:Int { get }
var priceString:String { get }
}
extension Product {
var priceString:String {
get {
return "$\(price)"
}
}
}
class IceCream : Product {
var price:Int {
get {
return 2
}
}
}
Run Code Online (Sandbox Code Playgroud)
实例的价格字符串IceCream是'$ 2'并且可以在Swift中访问,但是该方法在Objective-C中不可见.编译器抛出错误'No visible @interface for'FlowCream'声明选择器......'.
在我的配置中,如果方法是直接在Swift对象的实现中定义的,那么一切都按预期工作.即:
protocol Product {
var price:Int { get }
var priceString:String { get }
}
class IceCream : Product {
var price:Int {
get {
return 2
}
} …Run Code Online (Sandbox Code Playgroud) 当实现Self在协议扩展中返回的静态协议函数时,在扩展中的函数的实现中出现错误(在没有上下文的情况下显示的最小简化方案):
import Foundation
protocol P {
static func f() -> Self
static func g() -> Self
}
extension P {
static func f() -> Self { // Method 'f()' in non-final class 'NSData' must return `Self` to conform to protocol 'P'
return g()
}
}
extension NSData: P {
static func g() -> Self {
return self.init()
}
}
Run Code Online (Sandbox Code Playgroud)
更换Self与P上发生错误的行使编译器段错误(SIG 11)(这似乎输送类型不匹配错误的有效的方式).
改变的申报f()返回P,以及更换Self用P的错误行,结果在编译成功,但失去式精密(并且需要力向下转换在每次调用点,再加上记录了Self详细要求).
是否有任何其他解决方法可以解决此问题,并且不会丢失通用返回类型?
编辑 …
我有一个Objective-C协议,主要用于Objective-C对象和一个或两个Swift对象.
我想在Swift中扩展协议并添加2个函数.一个用于注册通知,另一个用于处理通知.
如果我添加这些
func registerForPresetLoadedNotification() {
NSNotificationCenter.defaultCenter().addObserver(self as AnyObject,
selector: #selector(presetLoaded(_:)),
name: kPresetLoadedNotificationName,
object: nil)
}
func presetLoaded(notification: NSNotification) {
}
Run Code Online (Sandbox Code Playgroud)
我在#selector上收到错误 Argument of '#selector' refers to a method that is not exposed to Objective-C
如果我然后标记presetLoaded,因为@objc我得到一个错误@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes
我也无法将协议扩展标记为@objc
当我将Objective-C协议创建为Swift协议时,我得到了同样的错误.
有没有办法实现这个适用于使用该协议的Objective-C和Swift类?
我有一组视图控制器,它们有一个菜单栏按钮.我为那些viewControllers创建了一个协议来采用.此外,我已经扩展了协议以添加默认功能.
我的协议看起来像,
protocol CenterViewControllerProtocol: class {
var containerDelegate: ContainerViewControllerProtocol? { get set }
func setupMenuBarButton()
}
Run Code Online (Sandbox Code Playgroud)
并且,扩展看起来像这样,
extension CenterViewControllerProtocol where Self: UIViewController {
func setupMenuBarButton() {
let barButton = UIBarButtonItem(title: "Menu", style: .Done, target: self, action: "menuTapped")
navigationItem.leftBarButtonItem = barButton
}
func menuTapped() {
containerDelegate?.toggleSideMenu()
}
}
Run Code Online (Sandbox Code Playgroud)
我的viewController采用协议 -
class MapViewController: UIViewController, CenterViewControllerProtocol {
weak var containerDelegate: ContainerViewControllerProtocol?
override func viewDidLoad() {
super.viewDidLoad()
setupMenuBarButton()
}
}
Run Code Online (Sandbox Code Playgroud)
我得到了很好的显示按钮,但是当我点击它时,应用程序崩溃了
[AppName.MapViewController menuTapped]: unrecognized selector sent to instance 0x7fb8fb6ae650
Run Code Online (Sandbox Code Playgroud)
如果我在ViewController中实现该方法,它可以正常工作.但我要复制符合协议的所有viewControllers中的代码.
我在这里做错了什么?提前致谢.
所以我试图用一些方便的函数来扩展Swift的整数类型,但是我还不清楚我应该扩展哪些协议.
作为一个例子,假设我想实现一个用于钳位值的函数(如果它小于最小值,则将其设置为该值,否则如果它大于最大值则将其设置为该值).我的第一个想法是做这样的事情:
extension Int {
func clamp(minimum:Int, maximum:Int) {
if self < minimum { return minimum }
if self > maximum { return maximum }
return self
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个简单的例子,但它说明了问题; 如果我现在想要调用它,UInt那么我自然也不能,所以我必须添加一个等价物UInt,但这对于UInt16等等不适用.
我认为我可以在链上向上扩展一些东西,然后使用泛型,但是IntegerType似乎无法扩展协议.
那么,是否有更合适的地方可以放置我的扩展程序?
protocol Car {
static func foo()
}
struct Truck : Car {
}
extension Car {
static func foo() {
print("bar")
}
}
Car.foo() // Does not work
// Error: Car does not have a member named foo
Truck.foo() // Works
Run Code Online (Sandbox Code Playgroud)
Xcode Car.foo()正确地自动填充,所以我要问的是它是否是一个不能编译的错误(说它没有一个名为foo()的成员).如果在协议扩展中定义静态方法,可以直接在协议上调用静态方法吗?