CNContactViewController의 iOS 13.1에서 키보드 오버레이 작업 시트


답변:


5

위대한 해결 방법을 위해 @GxocT에 대한 찬사! 내 사용자들을 엄청나게 도와주었습니다.
그러나 @GxocT 솔루션을 기반으로 코드를 공유하고 싶었습니다.이 시나리오에서 다른 사람들에게 도움이되기를 바랍니다.

나는 CNContactViewControllerDelegate contactViewController(_:didCompleteWith:)취소 할 때뿐만 아니라 전화해야했습니다.

또한 내 코드가 아니 었 UIViewController으므로self.navigationController

나는 또한 그것을 도울 수있을 때 강제로 풀기를 사용하는 것을 좋아하지 않습니다. 나는 과거에 물렸으므로 if let셋업에서 체인을 연결 했습니다.

내가 한 일은 다음과 같습니다.

  1. CNContactViewControllerswizzle 기능을 확장 하고 배치하십시오
    .

  2. 내 경우에는 swizzle 함수 에서 연락처 컨트롤러 와 함께
    CNContactViewControllerDelegate대리자
    contactViewController(_:didCompleteWith:)를 호출 self하고
    self.contact객체를 객체에서

  3. 설정 코드에서 swizzleMethod 호출이 대신 클래스 를 class_getInstanceMethod지정 하는지 확인하십시오. CNContactViewControllerself

그리고 스위프트 코드 :

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)
    }
}

키보드는 여전히 잠깐 동안 표시되지만 연락처 컨트롤러가 해제 된 직후에 삭제됩니다.
사과가 이것을 고치기를 바랍니다.


강제 랩 해제는 코드를 컴팩트하게 만드는 데 사용되며 가능한 경우 충돌을 일으킬 수있는 경우 피해야합니다. 당신이 PS 흐름 취소 할 경우는 아마 만들어 아니에요 원인, 대리인에게 self.contact을 통과 맞습니다 경우 BTW 난 잘 모르겠어요 : 피하기 힘 펼쳤다 내 구현을 변경 : D
GxocT

@GxocT-포스 랩에 합의했습니다. 그리고 그들은 항상 끔찍한 것은 아니지만 다른 사람들은 당신과 같지 않으며 항상 위험을 깨닫지 않고 그것들을 사용할 수 있습니다;). 대신에 보자! 내가 100 % 확실하지 않을 때 그것은 0이되지 않을 것입니다. self.contact에 대해-사실 Apple의 lib 코드가 일반적으로 대리자에게 내부적으로 전달되는 것을 알지 못하지만 self.contact는 연락처 데이터를 가지고 있으며 CNContactViewController 문서에 "표시되는 연락처"라고 표시되어 사용하기에 좋았습니다. 내 코드는 실제로 완성 대리자에 전달 된 연락처를 사용하지 않으므로 확장 프로그램에서 nil을 전달할 수 있습니다.
Barrett

CNContactViewController의 내용 (텍스트보기 및 키보드 포함)은 별도의 프로세스에 있어야합니다. 이 뷰 컨트롤러에 대해 Xcode에서 'View Hierarchy'를 사용할 수 있으면 내용을 볼 수 없습니다. 결과적으로 키보드 나 텍스트보기를 제어 할 수 없습니다.
WildCat

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)
        }
    }
}

추신 : reddit 주제에 대한 추가 정보를 찾을 수 있습니다 : https://www.reddit.com/r/swift/comments/dc9n3a/bug_with_cnviewcontroller_ios_131/


2

사용자는 실제로 아래로 스 와이프하여 키보드를 닫은 다음 취소를 탭하고 작업 시트를 볼 수 있습니다. 따라서이 문제는 유감스럽고 분명히 버그 (및 버그 보고서를 제출했지만) 치명적이지는 않습니다 (확실히 말하면 해결 방법은 사용자가 쉽게 알 수 없습니다).

여기에 이미지 설명을 입력하십시오


제출 한 버그 보고서에 링크 할 수 있습니까?
Paaske

1

Xcode Simulator에서 테스트 한 iOS 13.4에서 수정되었습니다.


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에 의해이 게시물 을 시도 할 수 있습니다


0

해결 방법으로 @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)
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.