สิ่งนี้ดูเหมือนจะเฉพาะเจาะจงกับ iOS 13.1 เนื่องจากทำงานได้ตามที่คาดหวังใน iOS 13.0 และเวอร์ชันก่อนหน้าเพื่อเพิ่มผู้ติดต่อใน ไม่มีการดำเนินการใด ๆ และแป้นพิมพ์ไม่ได้ทำการยกเลิก
สิ่งนี้ดูเหมือนจะเฉพาะเจาะจงกับ iOS 13.1 เนื่องจากทำงานได้ตามที่คาดหวังใน iOS 13.0 และเวอร์ชันก่อนหน้าเพื่อเพิ่มผู้ติดต่อใน ไม่มีการดำเนินการใด ๆ และแป้นพิมพ์ไม่ได้ทำการยกเลิก
คำตอบ:
ความรุ่งโรจน์ถึง @GxocT สำหรับวิธีแก้ปัญหาที่ยอดเยี่ยม! ช่วยผู้ใช้ของฉันอย่างมาก
แต่ฉันต้องการแบ่งปันรหัสของฉันตามโซลูชัน @GxocT หวังว่าจะช่วยผู้อื่นในสถานการณ์นี้
ฉันต้องการCNContactViewControllerDelegate
contactViewController(_:didCompleteWith:)
ให้ฉันยกเลิกการโทร (และเสร็จสิ้น)
รหัสของฉันก็ไม่ได้อยู่ในUIViewController
นั้นไม่มีself.navigationController
ฉันไม่ต้องการใช้กำลังบังคับเมื่อฉันสามารถช่วยได้ ฉันถูกกัดในอดีตดังนั้นฉันจึงถูกล่ามโซ่if let
ในการตั้งค่า
นี่คือสิ่งที่ฉันทำ:
ขยายCNContactViewController
และวางฟังก์ชัน swizzle ไว้ใน
นั้น
ในกรณีของฉันในการทำงาน swizzle เพียงแค่เรียก
CNContactViewControllerDelegate
ผู้ร่วมประชุม
contactViewController(_:didCompleteWith:)
ด้วยself
และ
self.contact
วัตถุจากตัวควบคุมการติดต่อ
ในรหัสการตั้งค่าตรวจสอบให้แน่ใจว่าการเรียก swizzleMethod เพื่อ
class_getInstanceMethod
ระบุ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/
ในความเป็นจริงผู้ใช้สามารถปัดลงเพื่อปิดแป้นพิมพ์แล้วแตะยกเลิกและดูแผ่นงาน ดังนั้นปัญหานี้เป็นเรื่องที่น่าเสียใจและเป็นข้อผิดพลาดอย่างแน่นอน (และฉันได้ยื่นรายงานข้อผิดพลาด) แต่ไม่ถึงขั้นเสียชีวิต (ถึงแม้ว่าจะต้องแน่ใจว่า
แก้ไขใน iOS 13.4 ที่ทดสอบใน Xcode Simulator
ขอบคุณ@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 คุณอาจลองโพสต์นี้โดยด้าน
ขอบคุณ @GxocT สำหรับวิธีแก้ปัญหาของคุณอย่างไรก็ตามวิธีการโพสต์ที่นี่แตกต่างจากที่คุณโพสต์ใน Reddit
หนึ่งใน Reddit ใช้งานได้สำหรับฉันอันนี้ไม่ได้ดังนั้นฉันต้องการ repost ที่นี่ ความแตกต่างอยู่บนบรรทัดกับ 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)
}
}