これはiOS 13.1に固有のようです。iOS13.0以前のバージョンではCNContactViewControllerに連絡先を追加すると期待どおりに機能するため、「キャンセル」すると、アクションシートがキーボードで重なります。アクションは実行されず、キーボードは終了しません。
これはiOS 13.1に固有のようです。iOS13.0以前のバージョンではCNContactViewControllerに連絡先を追加すると期待どおりに機能するため、「キャンセル」すると、アクションシートがキーボードで重なります。アクションは実行されず、キーボードは終了しません。
回答:
素晴らしい回避策を@GxocTに感謝します!ユーザーを大いに助けました。
しかし、@ GxocTソリューションに基づいて自分のコードを共有したかったのですが、このシナリオで他の人に役立つことを期待しています。
CNContactViewControllerDelegate
contactViewController(_:didCompleteWith:)
キャンセル時に(そして完了時に)呼び出される必要がありました。
また、私のコードはないUIViewController
のでself.navigationController
私はそれを助けることができるときに強制アンラップを使うのも好きではありません。私は過去に噛まれたのでif let
、セットアップでs をチェーンしました
これが私がしたことです:
そこにCNContactViewController
スウィズル機能を拡張して配置し
ます。
私の場合、スウィズル関数では、連絡先コントローラのオブジェクトとオブジェクトを使用して
CNContactViewControllerDelegate
デリゲート
contactViewController(_:didCompleteWith:)
を呼び出すだけです。self
self.contact
セットアップコードで、
代わりにクラスをclass_getInstanceMethod
指定するswizzleMethod呼び出しを確認し
ますCNContactViewController
self
そしてSwiftコード:
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)
}
}
キーボードは一瞬表示されますが、連絡先コントローラーが終了した直後にドロップします。
アップルがこれを修正することを望みます
キーボードを閉じる方法が見つかりませんでした。しかし、少なくとも、私のメソッドを使用してViewControllerをポップできます。
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/
@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
スウィズリングに慣れていない人はマットでこの投稿を試してみてください
@GxocTの回避策に感謝しますが、ここに投稿されたソリューションは、Redditに投稿したものとは異なります。
Redditの1つは私には有効ですが、これは機能しないため、ここに再投稿します。違いは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)
}
}