แป้นพิมพ์ซ้อนทับ Action Sheet ใน iOS 13.1 บน CNContactViewController


12

สิ่งนี้ดูเหมือนจะเฉพาะเจาะจงกับ iOS 13.1 เนื่องจากทำงานได้ตามที่คาดหวังใน iOS 13.0 และเวอร์ชันก่อนหน้าเพื่อเพิ่มผู้ติดต่อใน ไม่มีการดำเนินการใด ๆ และแป้นพิมพ์ไม่ได้ทำการยกเลิก

คำตอบ:


5

ความรุ่งโรจน์ถึง @GxocT สำหรับวิธีแก้ปัญหาที่ยอดเยี่ยม! ช่วยผู้ใช้ของฉันอย่างมาก
แต่ฉันต้องการแบ่งปันรหัสของฉันตามโซลูชัน @GxocT หวังว่าจะช่วยผู้อื่นในสถานการณ์นี้

ฉันต้องการCNContactViewControllerDelegate contactViewController(_:didCompleteWith:)ให้ฉันยกเลิกการโทร (และเสร็จสิ้น)

รหัสของฉันก็ไม่ได้อยู่ในUIViewControllerนั้นไม่มีself.navigationController

ฉันไม่ต้องการใช้กำลังบังคับเมื่อฉันสามารถช่วยได้ ฉันถูกกัดในอดีตดังนั้นฉันจึงถูกล่ามโซ่if letในการตั้งค่า

นี่คือสิ่งที่ฉันทำ:

  1. ขยายCNContactViewControllerและวางฟังก์ชัน swizzle ไว้ใน
    นั้น

  2. ในกรณีของฉันในการทำงาน swizzle เพียงแค่เรียก
    CNContactViewControllerDelegateผู้ร่วมประชุม
    contactViewController(_:didCompleteWith:)ด้วยselfและ
    self.contactวัตถุจากตัวควบคุมการติดต่อ

  3. ในรหัสการตั้งค่าตรวจสอบให้แน่ใจว่าการเรียก 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)
    }
}

แป้นพิมพ์ยังคงแสดงในไม่ช้า แต่จะลดลงหลังจากที่ตัวควบคุมรายชื่อถูกยกเลิก
หวังว่าแอปเปิ้ลจะแก้ไขสิ่งนี้


การบังคับให้คลายการบีบอัดใช้เพื่อทำให้รหัสมีขนาดกะทัดรัดแน่นอนคุณควรหลีกเลี่ยงหากเป็นไปได้และหากอาจทำให้เกิดความผิดพลาด btw ฉันไม่แน่ใจว่ามันถูกต้องหรือไม่ที่จะส่งผ่านตัวเองติดต่อผู้แทนเพราะมันอาจไม่ได้ถูกสร้างขึ้นหากคุณยกเลิก flow ps: เปลี่ยนการดำเนินงานของฉันเพื่อหลีกเลี่ยงการบังคับใช้งานไม่ได้: D
GxocT

@GxocT - เห็นด้วยกับการบังคับให้ urwraps และพวกเขาก็ไม่ได้แย่เสมอไป แต่คนอื่นไม่ชอบคุณและอาจใช้มันโดยไม่ตระหนักถึงความเสี่ยง;) ฉันชอบถ้าปล่อยแทนที่จะเป็น! เมื่อฉันไม่ 100% แน่ใจว่ามันจะไม่เป็นศูนย์ เกี่ยวกับ self.contact - เป็นเรื่องจริงฉันไม่รู้ว่าปกติแล้วรหัส lib ของ Apple จะส่งไปยังผู้มอบหมายภายใน แต่ self.contact มีข้อมูลติดต่อและเอกสาร CNContactViewController doc บอกว่ามันคือ รหัสของฉันไม่ได้ใช้ผู้ติดต่อที่ส่งผ่านในตัวแทนผู้ดำเนินการจนเสร็จสมบูรณ์ดังนั้นฉันสามารถผ่านศูนย์ในส่วนขยายได้
บาร์เร็ตต์

เนื้อหา (รวมถึงมุมมองข้อความและคีย์บอร์ด) ใน CNContactViewController ควรอยู่ในกระบวนการแยกต่างหาก หากคุณสามารถใช้ 'ลำดับชั้นการดู' ใน Xcode สำหรับตัวควบคุมมุมมองนี้คุณอาจพบว่าเนื้อหาไม่สามารถมองเห็นได้ ด้วยเหตุนี้เราจึงไม่สามารถควบคุมแป้นพิมพ์หรือมุมมองข้อความ
แมว

5

ฉันหาวิธีเลิกใช้คีย์บอร์ดไม่ได้ แต่อย่างน้อยคุณก็สามารถเปิด ViewController โดยใช้วิธีการของฉัน

  1. ไม่ทราบสาเหตุ แต่เป็นไปไม่ได้ที่จะปิดคีย์บอร์ดใน CNContactViewController ฉันลอง endEditing: สร้าง UITextField ใหม่ก่อนการตอบกลับและอื่น ๆ ไม่มีอะไรทำงาน
  2. ฉันพยายามเปลี่ยนการกระทำสำหรับปุ่ม "ยกเลิก" คุณสามารถค้นหาปุ่มนี้ได้ใน NavigationController stack แต่การกระทำของมันจะเปลี่ยนไปทุกครั้งที่คุณพิมพ์บางสิ่ง
  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/


2

ในความเป็นจริงผู้ใช้สามารถปัดลงเพื่อปิดแป้นพิมพ์แล้วแตะยกเลิกและดูแผ่นงาน ดังนั้นปัญหานี้เป็นเรื่องที่น่าเสียใจและเป็นข้อผิดพลาดอย่างแน่นอน (และฉันได้ยื่นรายงานข้อผิดพลาด) แต่ไม่ถึงขั้นเสียชีวิต (ถึงแม้ว่าจะต้องแน่ใจว่า

ป้อนคำอธิบายรูปภาพที่นี่


คุณสามารถลิงค์ไปยังรายงานข้อผิดพลาดที่คุณยื่นมาได้หรือไม่?
Paaske


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 คุณอาจลองโพสต์นี้โดยด้าน


0

ขอบคุณ @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)
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.