[iOS 10で修正されたようです!]したがって、以下はiOS 9のみに適用されます...
私はAppleの新しい連絡先フレームワークを実験しており、CNContactViewControllerの3つの形式の1つに大きなバグを発見しました。周囲のインターフェースを破壊して、アプリが役に立たなくなるようにします。ユーザーが行き詰まっている。
このバグをわかりやすくするために、サンプルプロジェクトを https://github.com/mattneub/CNContactViewControllerBug に投稿しました。
実験するには、プロジェクトを実行し、次の手順を実行します。
ボタン(不明な人)をタップします。
必要に応じてアクセスを許可します。
ナビゲーションインターフェースに部分的な連絡先が表示されます(上部の[戻る]ボタンに注意してください)。
[既存の連絡先に追加]をタップします。連絡先ピッカーが表示されます。
[キャンセル]をタップします。実際にここから何をするかは問題ではありませんが、[キャンセル]をタップするのが最も簡単で、バグに到達する最も早い方法です。
これで部分的な接触に戻りましたが、ナビゲーションインターフェースはなくなりました。ユーザーはこのインターフェースから脱出する方法がありません。 アプリはホースです。
わかりやすくするために、実行する必要がある手順のスクリーンショットを次に示します。
これを表示するには、[既存の連絡先に追加]をタップします。
これを表示するには、[キャンセル]をタップします。最初のスクリーンショットと同じであることに注意してください。ただし、ナビゲーションバーはなくなっています。
私はこのバグを回避するために多くの方法を試しましたが、方法がないようです。私の知る限り、このウィンドウはフレームワークの「アウトプロセス」によって提示されており、アプリの一部ではありません。それを取り除くことはできません。
それで質問は何ですか?私はこれだと思います:このビューコントローラ(この形式)を使用可能にする方法を誰かに見せてもらえますか?見つからない回避策はありますか?
[〜#〜] edit [〜#〜]このバグはiOS 9.0で発生し、iOS 9.1でも引き続き存在します。コメントの中で、@ SergeySkopusは非推奨のアドレス帳フレームワークに切り替えても役に立たないと報告しています。バグはどこかにある根本的な構造にあります。
Appleがついに私のバグレポートに重複と宣言することで対応したので、明らかにこれはバグです。
カテゴリを使用してナビゲーションバーを表示または非表示にするために、UINavigationControllerメソッドを非表示にしました。
@interface UINavigationController (contacts)
@end
@implementation UINavigationController (contacts)
- (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated {
NSLog(@"Hide: %d", hidden);
}
@end
このようにして、CNContactViewControllerはナビゲーションバーを非表示にすることができません。 NSLogにブレークポイントを設定するこのメソッドがプライベート[CNContactViewController isPresentingFullscreen:]
から呼び出されていることを発見しました。
ナビゲーションコントローラーのself.topViewController
がクラスCNContactViewController
の一種であるかどうかを確認することで、ナビゲーションバーを非表示にするかどうかを決定できます。
「CNContactViewController forUnknownContact」を使用可能にする唯一の方法は、ナビゲーションバーを放棄し、ツールバーを使用して次のようなモーダルビューを終了することです(Objective C)。
CNContactViewController *picker = [CNContactViewController viewControllerForUnknownContact: newContact];
picker.delegate = self;
UINavigationController *newNavigationController = [[UINavigationController alloc] initWithRootViewController:picker];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStyleDone target:self action:@selector(YourDismissFunction)];
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[picker setToolbarItems:[[NSArray alloc] initWithObjects:flexibleSpace, doneButton, flexibleSpace, nil] animated:NO];
newNavigationController.toolbarHidden = NO;
picker.edgesForExtendedLayout = UIRectEdgeNone;
[self presentViewController:newNavigationController animated:YES completion:nil];
それが役立つことを願って
非常にプライベートなAPI修正に興味がありますか?
@implementation CNContactViewController (Debug)
+ (void)load
{
Method m1 = class_getInstanceMethod([CNContactViewController class], NSSelectorFromString(@"".underscore.s.h.o.u.l.d.B.e.O.u.t.O.f.P.r.o.c.e.s.s));
Method m2 = class_getInstanceMethod([CNContactViewController class], @selector(checkStatus));
method_exchangeImplementations(m1, m2);
}
- (BOOL)checkStatus
{
//Leo: Fix bug where in-process contact view controller crashes if there is no access to local contacts.
BOOL result;
if([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] == CNAuthorizationStatusAuthorized)
{
result = NO;
}
else {
result = YES;
}
return result;
}
@end
これは、アップルによるバグの多いXPCコントローラの使用を元に戻す「魔法の」ソリューションです。最新のCN
コントローラーと、内部でAB
を使用するレガシーCN
コントローラーの両方で、非常に多くの問題を解決します。
まあ、私は問題を一時的に解決する3つの方法を見つけました。
Swift 2.2バージョン:
オプション1:デバイスをシェイクしてナビゲーションバーを表示するか、直接閉じる
class CustomContactViewController: CNContactViewController {
override func viewDidLoad() {
super.viewDidLoad()
UIApplication.sharedApplication().applicationSupportsShakeToEdit = true
}
override func canBecomeFirstResponder() -> Bool {
return true
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
becomeFirstResponder()
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
resignFirstResponder()
UIApplication.sharedApplication().applicationSupportsShakeToEdit = false
}
override func motionEnded(motion: UIEventSubtype, withEvent event: UIEvent?) {
navigationController?.setNavigationBarHidden(false, animated: true)
// or just dismiss
// dismissViewControllerAnimated(true, completion: nil)
// or pop
// navigationController?.popViewControllerAnimated(true)
}
}
オプション2:タイマーを設定して、ナビゲーションバーを強制的に表示します。しかし...それはまた新しい問題を引き起こし、あなたは連絡先のアバターを編集したり共有したりすることはできません。
class CustomContactViewController: CNContactViewController {
var timer: NSTimer?
override func viewDidLoad() {
super.viewDidLoad()
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(showNavigationBar), userInfo: nil, repeats: true)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
timer?.fire()
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
timer?.invalidate()
}
@objc private func showNavigationBar() {
navigationController?.setNavigationBarHidden(false, animated: true)
}
}
オプション3:一番上のビューに閉じるボタンを作成します。
class CustomContactViewController: CNContactViewController {
override func viewDidLoad() {
super.viewDidLoad()
configureDismissButton()
}
private func configureDismissButton() {
guard let topView = UIApplication.topMostViewController?.view else { return }
let button = UIButton()
button.setImage(UIImage(named: "close"), forState: .Normal)
button.addTarget(self, action: #selector(dismissViewController), forControlEvents: .TouchUpInside)
topView.addSubview(button)
// just use SnapKit to set AutoLayout
button.snp_makeConstraints { (make) in
make.width.height.equalTo(36)
make.bottom.equalTo(8)
make.left.equalTo(-8)
}
}
@objc private func dismissViewController() {
dismissViewControllerAnimated(true, completion: nil)
}
var topMostViewController: UIViewController? {
var topController = UIApplication.sharedApplication().keyWindow?.rootViewController
while topController?.presentedViewController != nil {
topController = topController?.presentedViewController
}
return topController
}
}
これは、私が一人ではなかったことを見てうれしかった問題の1つです。
CNContactViewController(contact :)を使用して連絡先を表示すると、同じ問題が発生します。
画像または「連絡先の共有」をタップすると、ルートのCNContactViewControllerのナビゲーションバーが消えて、ユーザーが行き詰まっていました。これはiOS 9.3.3では修正されていません。
この時点での解決策は、uitoolbarを使用することです。問題は、連絡先の画像データがフルスクリーンであっても、これが常に下部に表示されることです。
// initialise new contact view controller to display with contact
let contactVC = CNContactViewController(forContact: contact!)
// set view controller delegate
contactVC.delegate = self
// set view controller contact store
contactVC.contactStore = self.store
// enable actions
contactVC.allowsActions = true
// disable editing
contactVC.allowsEditing = false
// add cancel button
let cancelButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Cancel, target: self, action: #selector(dismissContactVC(_:)))
// add flexible space
let flexibleSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
// add to toolbar
contactVC.setToolbarItems([flexibleSpace, cancelButton, flexibleSpace], animated: false)
// contact view controller must be embedded in navigation controller
// initialise navigation controller with contact view controller as root
let navigationVC = SubClassNavigationController(rootViewController: contactVC)
// show toolbar
navigationVC.setToolbarHidden(false, animated: false)
// set navigation presentation style
navigationVC.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
// present view controller
self.presentViewController(navigationVC, animated: true, completion: nil)
この後、最初にcncontactviewcontrollerを表示したときに空白のナビゲーションバーが表示されるため、これを削除し、uinavigationcontrollerをサブクラス化し、viewWillAppear(animated :)で関数setnavigationbar(hidden:animated :)を呼び出してナビゲーションバーを非表示にします。
Appleこれが理想的な解決策ではないので、すぐに修正してください。