Xcode 在扩展方法中向Objective-C公开实例方法

Xcode 在扩展方法中向Objective-C公开实例方法,xcode,selector,extension-methods,swift3,Xcode,Selector,Extension Methods,Swift3,我有一个应用程序,它使用UIKeyboard在几个不同的控制器中显示和隐藏通知。我决定尝试整合将带有键盘的视图移动到基于协议的扩展中所需的逻辑 这是我的协议 public protocol KeyboardType : class { func keyboardWillShow(_ sender: Notification) func keyboardWillHide(_ sender: Notification) } 接下来,我为我的新协议添加了一个扩展,这样我所需要做的就是

我有一个应用程序,它使用UIKeyboard在几个不同的控制器中显示和隐藏通知。我决定尝试整合将带有键盘的视图移动到基于协议的扩展中所需的逻辑

这是我的协议

public protocol KeyboardType : class {
    func keyboardWillShow(_ sender: Notification)
    func keyboardWillHide(_ sender: Notification)
}
接下来,我为我的新协议添加了一个扩展,这样我所需要做的就是实现我的“键盘式协议”,我将获得使用键盘移动视图所需的功能:

这是我的分机

public extension KeyboardType where Self: UIViewController {

    func addObservers() { 
        NotificationCenter.default.addObserver(self, selector: #selector(Self.keyboardWillShow(_:)), name:NSNotification.Name.UIKeyboardWillShow, object: self.view.window)
        NotificationCenter.default.addObserver(self, selector: #selector(Self.keyboardWillHide(_:)), name:NSNotification.Name.UIKeyboardWillHide, object: self.view.window)
    }

    func removeObservers() {
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: self.view.window)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: self.view.window)

    }

    func keyboardWillHide(_ sender: Notification) {
        let userInfo: [AnyHashable : Any] = (sender as NSNotification).userInfo!
        let keyboardSize: CGSize = (userInfo[UIKeyboardFrameBeginUserInfoKey]! as AnyObject).cgRectValue.size
        self.view.frame.origin.y += keyboardSize.height
    }

    func keyboardWillShow(_ sender: Notification) {
        let userInfo: [AnyHashable : Any] = sender.userInfo!

        let keyboardSize: CGSize = (userInfo[UIKeyboardFrameBeginUserInfoKey]! as AnyObject).cgRectValue.size
        let offset: CGSize = (userInfo[UIKeyboardFrameEndUserInfoKey]! as AnyObject).cgRectValue.size

        if keyboardSize.height == offset.height {
            if self.view.frame.origin.y == 0 {
                UIView.animate(withDuration: 0.1, animations: { () -> Void in
                    self.view.frame.origin.y -= keyboardSize.height
                })
            }
        } else {
            UIView.animate(withDuration: 0.1, animations: { () -> Void in
                self.view.frame.origin.y += keyboardSize.height - offset.height
            })
        }
    }

}
问题

问题是编译器要求我将@objc添加到keyboardWillShow和keyboardWillHide方法中。当我允许Xcode添加关键字时,编译器立即要求我删除@objc关键字

“#选择器”的参数引用了实例方法“keyboardWillShow” 不接触Objective-C的

我的问题 在这种情况下,如何向Objective-C公开keyboardWillShow

有没有更好的方法来完成同样的任务?

您尝试过这个吗?:

@objc public protocol KeyboardType {
    func keyboardWillShow(_ sender: Notification)
    func keyboardWillHide(_ sender: Notification)
}
您还需要导入UIKit

您尝试过这个吗?:

@objc public protocol KeyboardType {
    func keyboardWillShow(_ sender: Notification)
    func keyboardWillHide(_ sender: Notification)
}

您还需要导入UIKit

我将采用不同的方法扩展UIViewController,如下所示:

protocol KeyboardController {
    func keyboardWillShow(_ sender: Notification)
    func keyboardWillHide(_ sender: Notification)
}



我最喜欢的另一个选项是将UIViewController子类化:

class KeyboardViewController: UIViewController {

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        addObservers()
    }
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        removeObservers()
    }

    func addObservers() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: .UIKeyboardWillShow, object: view.window)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: .UIKeyboardWillHide, object: view.window)
    }

    func removeObservers() {
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: view.window)
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: view.window)
    }

    func keyboardWillHide(_ notification: Notification) {
        print("---> keyboardWillHide")
        if let keyboardHeight = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size.height {
            print("keyboardHeight", keyboardHeight)
            view.frame.origin.y += keyboardHeight
        }
    }

    func keyboardWillShow(_ notification: Notification) {
        print("---> keyboardWillShow")
        if let userInfo = notification.userInfo,
            let keyboardHeight = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size.height,
            let offsetHeight = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size.height {
            print("userInfo", userInfo)
            print("keyboardHeight", keyboardHeight)
            print("offsetHeight", offsetHeight)
            if keyboardHeight == offsetHeight {
                if self.view.frame.origin.y == 0 {
                    UIView.animate(withDuration: 0.1, animations: { () -> Void in
                        self.view.frame.origin.y -= keyboardHeight
                    })
                }
            } else {
                UIView.animate(withDuration: 0.1, animations: { () -> Void in
                    self.view.frame.origin.y += keyboardHeight - offsetHeight
                })
            }
        }
    }
}


我将采用不同的方法扩展UIViewController,如下所示:

protocol KeyboardController {
    func keyboardWillShow(_ sender: Notification)
    func keyboardWillHide(_ sender: Notification)
}



我最喜欢的另一个选项是将UIViewController子类化:

class KeyboardViewController: UIViewController {

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        addObservers()
    }
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        removeObservers()
    }

    func addObservers() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: .UIKeyboardWillShow, object: view.window)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: .UIKeyboardWillHide, object: view.window)
    }

    func removeObservers() {
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: view.window)
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: view.window)
    }

    func keyboardWillHide(_ notification: Notification) {
        print("---> keyboardWillHide")
        if let keyboardHeight = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size.height {
            print("keyboardHeight", keyboardHeight)
            view.frame.origin.y += keyboardHeight
        }
    }

    func keyboardWillShow(_ notification: Notification) {
        print("---> keyboardWillShow")
        if let userInfo = notification.userInfo,
            let keyboardHeight = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size.height,
            let offsetHeight = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size.height {
            print("userInfo", userInfo)
            print("keyboardHeight", keyboardHeight)
            print("offsetHeight", offsetHeight)
            if keyboardHeight == offsetHeight {
                if self.view.frame.origin.y == 0 {
                    UIView.animate(withDuration: 0.1, animations: { () -> Void in
                        self.view.frame.origin.y -= keyboardHeight
                    })
                }
            } else {
                UIView.animate(withDuration: 0.1, animations: { () -> Void in
                    self.view.frame.origin.y += keyboardHeight - offsetHeight
                })
            }
        }
    }
}



注意:与选择器无关,但您当前的方法将在beta 6中崩溃。您需要将其强制转换为NSValue
(notification.userInfo?[UIKeyboardFrameBeginUserInfo]as?NSValue)?.cgRectValue.size
@LeoDabus此确切代码在beta 6中的视图控制器中运行良好。这很奇怪,我将仔细检查。当我更新到beta 6时,我有一个在对任何对象进行强制转换时崩溃的微笑代码,我发现了它。您的方法正在工作,因为您首先对NSNotifica进行强制转换。如果您不强制转换到NSNotifica你需要按照我的建议去做,否则它会崩溃,你的AppSype屏幕显示你只导入了基础,但是你知道你需要导入UIKIT来使用你的代码中的<代码> UIViewController <代码>。一些错误(包括这样的缺省导入)可能会阻止Xcode进行代码分析,因此会显示旧的错误消息。注意:与选择器无关,但您当前的方法将在beta 6中崩溃。您需要将其强制转换为NSValue
(notification.userInfo?[UIKeyboardFrameBeginUserInfo]作为?NSValue)?.cgRectValue.size
@LeoDabus此确切代码在beta 6中的视图控制器中运行良好。这很奇怪,我将仔细检查。当我更新到beta 6时,我有一个在对任何对象进行强制转换时崩溃的微笑代码,我发现了它。您的方法正在工作,因为您首先对NSNotifica进行强制转换。如果您不强制转换到NSNotifica你需要按照我的建议去做,否则它会崩溃,你的AppSype屏幕显示你只导入了基础,但是你知道你需要导入UIKIT来使用你的代码中的<代码> UIViewController <代码>。一些错误(包括这样的缺省导入)可能正在阻止Xcode进行代码分析,因此显示旧的错误消息。是的。当我添加此项时,编译器尝试在我的两个函数之前添加@objc,当我添加它们时,它会告诉我删除它们。@Danbeauliue您是否尝试将其添加到协议而不是方法?@Danbeauliue,这是一种奇怪的行为。在我的beta 6中,Xcode没有对于上面显示的协议,您不能抱怨任何关于
@objc
(尽管您可能需要修复代码的其他部分)重新输入上面的代码,然后尝试clean build。@LeoDabus我已经添加了一个图像和发生的事情的简要说明。上面的解决方案是我在发布之前尝试过的。是的。当我添加该解决方案时,编译器尝试在我的两个函数之前添加@objc,当我添加它们时,它会告诉我删除它们。@DanBeaulieu您尝试过将其添加到协议而不是方法?@DanBeaulieu,这是一种奇怪的行为。在我的beta 6中,Xcode对上面显示的协议没有任何抱怨(尽管您可能需要修复代码的其他部分)重新输入上面的代码,然后尝试“干净构建”。@LeoDabus我已经添加了一个图像和发生的事情的简要说明。上面的解决方案是我在发布之前尝试过的。我最初考虑过扩展UIViewController,但我试图避免向UIViewController类型添加一揽子功能。我认为这是一个可以接受的解决方案但是如果我接受这个作为我的答案,我需要重新措辞我的问题。(我可能会这么做)我接受这是解决我问题的最佳方案。我将查看您明天发送的Dropbox文件,并在课后修改我的问题。再次感谢Leotook快速查看您的文件,子类化路线也是一个很好的解决方案。我最初曾考虑扩展UIViewController,但我试图避免向UIViewController类型。我认为这是一个可以接受的解决方案,但如果我接受这个作为我的答案,我需要重新回答我的问题。(我可能会这么做)我接受这是我问题的最佳解决方案。我将查看您明天发送的Dropbox文件,并在课后修改我的问题。再次感谢Leotook快速查看您的文件,子类化路线也是一个很好的解决方案