13

这似乎特定于 iOS 13.1,因为它在 iOS 13.0 和更早版本上按预期工作,以在 CNContactViewController 中添加联系人,如果我“取消”,则操作表与键盘重叠。没有执行任何操作,并且键盘没有关闭。

4

7 回答 7

5

感谢@GxocT 的出色解决方法!极大地帮助了我的用户。
但我想基于@GxocT 解决方案分享我的代码,希望它能在这种情况下帮助其他人。

我需要我CNContactViewControllerDelegate contactViewController(_:didCompleteWith:)被取消(以及完成)。

另外我的代码不在 aUIViewController所以没有self.navigationController

我也不喜欢在可以提供帮助时使用强制解包。我过去被咬过所以我if let在设置中链接了s

这是我所做的:

  1. 扩展CNContactViewController并将调酒功能放在
    那里。

  2. 在我的情况下,在 swizzle 函数中,只需从联系人控制器调用
    CNContactViewControllerDelegate委托
    contactViewController(_:didCompleteWith:)和对象self
    self.contact

  3. 在设置代码中,确保 swizzleMethod 调用 class_getInstanceMethod指定CNContactViewController 类而不是self

和斯威夫特代码:

class MyClass: CNContactViewControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.changeImplementation()
    }

    func changeCancelImplementation() {

        let originalSelector = Selector(("editCancel:"))
        let swizzledSelector = #selector(CNContactViewController.cancelHack)

        if let originalMethod = class_getInstanceMethod(object_getClass(CNContactViewController()), originalSelector),
           let swizzledMethod = class_getInstanceMethod(object_getClass(CNContactViewController()), swizzledSelector) {

            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }

   func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
       // dismiss the contacts controller as usual
       viewController.dismiss(animated: true, completion: nil)
       // do other stuff when your contact is canceled or saved
       ...
    }
}

extension CNContactViewController {
    @objc func cancelHack()  {
        self.delegate?.contactViewController?(self, didCompleteWith: self.contact)
    }
}

键盘仍会暂时显示,但会在联系人控制器关闭后立即下降。
让我们希望苹果能解决这个问题

于 2019-10-03T23:34:25.723 回答
5

我找不到关闭键盘的方法。但至少你可以使用我的方法弹出 ViewController。

  1. 不知道为什么,但在 CNContactViewController 中关闭键盘是不可能的。我尝试了 endEditing:,创建新的 UITextField firstResponder 等等。没有任何效果。
  2. 我试图改变“取消”按钮的动作。您可以在 NavigationController 堆栈中找到此按钮,但每次键入内容时它的操作都会更改。
  3. 最后我使用了方法调配。如前所述,我找不到关闭键盘的方法,但至少您可以在按下“取消”按钮时关闭 CNContactViewController。
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        changeImplementation()
    }

    @IBAction func userPressedButton(_ sender: Any) {
        let controller = CNContactViewController(forNewContact: nil)
        controller.delegate = self
        navigationController?.pushViewController(controller, animated: true)
    }

    @objc func popController() {
        self.navigationController?.popViewController(animated: true)
    }

    func changeImplementation() {
        let originalSelector = Selector("editCancel:")
        let swizzledSelector = #selector(self.popController)

        if let originalMethod = class_getInstanceMethod(object_getClass(CNContactViewController()), originalSelector),
            let swizzledMethod = class_getInstanceMethod(object_getClass(CNContactViewController()), swizzledSelector) {

            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }
}

PS:您可以找到有关 reddit 主题的更多信息:https ://www.reddit.com/r/swift/comments/dc9n3a/bug_with_cnviewcontroller_ios_131/

于 2019-10-03T15:36:15.900 回答
4

在 Xcode 模拟器中测试的 iOS 13.4 中已修复

于 2020-03-25T11:39:55.433 回答
2

注意:此错误现已修复。此问题和答案仅适用于某些特定版本的 iOS(有限范围的 iOS 13 版本)。


用户实际上可以向下滑动以关闭键盘,然后点击取消并查看操作表。所以这个问题是令人遗憾的,绝对是一个错误(我已经提交了一个错误报告)但不是致命的(虽然,可以肯定的是,解决方法对于用户来说并不是微不足道的发现)。

在此处输入图像描述

于 2019-10-13T18:05:14.647 回答
1

感谢@Gxoct的出色工作。我认为这对于那些正在使用的人来说是非常有用的问题和帖子CNContactViewController。我也有这个问题(直到现在),但在目标 c 中。我将上面的 Swift 代码解释为目标 c。

- (void)viewDidLoad {
    [super viewDidLoad];
    Class class = [CNContactViewController class];

    SEL originalSelector = @selector(editCancel:);
    SEL swizzledSelector = @selector(dismiss); // we will gonna access this method & redirect the delegate via this method

    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

    BOOL didAddMethod =
        class_addMethod(class,
            originalSelector,
            method_getImplementation(swizzledMethod),
            method_getTypeEncoding(swizzledMethod));

    if (didAddMethod) {
        class_replaceMethod(class,
            swizzledSelector,
            method_getImplementation(originalMethod),
            method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}

创建CNContactViewController用于访问驳回的类别;

@implementation CNContactViewController (Test)

- (void) dismiss{
    [self.delegate contactViewController:self didCompleteWithContact:self.contact];
}

@end

对 Swizzling 不太熟悉的人可以试试matt 的这篇文章

于 2020-05-03T16:07:07.247 回答
1

谢谢@GxocT 的解决方法,但是,此处发布的解决方案与您在 Reddit 上发布的解决方案不同。

Reddit 上的那个对我有用,这个不行,所以我想在这里重新发布。不同之处在于 swizzledMethod 应该是:

   let swizzledMethod = class_getInstanceMethod(object_getClass(self), swizzledSelector) {

整个更新的代码是:

class MyClass: CNContactViewControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.changeImplementation()
    }

    func changeCancelImplementation() {

        let originalSelector = Selector(("editCancel:"))
        let swizzledSelector = #selector(CNContactViewController.cancelHack)

        if let originalMethod = class_getInstanceMethod(object_getClass(CNContactViewController()), originalSelector),
           let swizzledMethod = class_getInstanceMethod(object_getClass(self), swizzledSelector) {

            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }

   func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
       // dismiss the contacts controller as usual
       viewController.dismiss(animated: true, completion: nil)
       // do other stuff when your contact is canceled or saved
       ...
    }
}

extension CNContactViewController {
    @objc func cancelHack()  {
        self.delegate?.contactViewController?(self, didCompleteWith: self.contact)
    }
}
于 2020-04-30T15:14:36.603 回答
0

要始终考虑的一件事是 swizzler 方法只执行一次。确保您在 dispatch_once 队列中实现 changeCancelImplementation() 以便它只执行一次。

检查此链接以获取说明

此错误仅在 iOS 13.1、13.2 和 13.3 中发现

于 2020-06-18T03:35:27.067 回答