답변:
위대한 해결 방법을 위해 @GxocT에 대한 찬사! 내 사용자들을 엄청나게 도와주었습니다.
그러나 @GxocT 솔루션을 기반으로 코드를 공유하고 싶었습니다.이 시나리오에서 다른 사람들에게 도움이되기를 바랍니다.
나는 CNContactViewControllerDelegate
contactViewController(_:didCompleteWith:)
취소 할 때뿐만 아니라 전화해야했습니다.
또한 내 코드가 아니 었 UIViewController
으므로self.navigationController
나는 또한 그것을 도울 수있을 때 강제로 풀기를 사용하는 것을 좋아하지 않습니다. 나는 과거에 물렸으므로 if let
셋업에서 체인을 연결 했습니다.
내가 한 일은 다음과 같습니다.
CNContactViewController
swizzle 기능을 확장 하고 배치하십시오
.
내 경우에는 swizzle 함수 에서 연락처 컨트롤러 와 함께
CNContactViewControllerDelegate
대리자
contactViewController(_:didCompleteWith:)
를 호출 self
하고
self.contact
객체를 객체에서
설정 코드에서 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)
}
}
키보드는 여전히 잠깐 동안 표시되지만 연락처 컨트롤러가 해제 된 직후에 삭제됩니다.
사과가 이것을 고치기를 바랍니다.
키보드를 해제하는 방법을 찾을 수 없습니다. 그러나 적어도 내 방법을 사용하여 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)
}
}
}
추신 : 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
Swizzling에 익숙하지 않은 사람들은 matt에 의해이 게시물 을 시도 할 수 있습니다
해결 방법으로 @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)
}
}