在iPad中显示类型为UIAlertControllerUIActionSheet时出现问题。我知道iPad需要更多信息才能显示弹出窗口,但我遇到了一些奇怪的问题。

我正在检查与我的应用程序相关的iOS 13兼容性问题,并且似乎出现了旧技巧,例如使用performSelectorUIBarButtonItem上获取视图不再起作用。

方式1

所以我这样做。

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    UIView* internalView = (UIView*) [weakSelf.navigationItem.rightBarButtonItem performSelector:@selector(view)];

    menuController.popoverPresentationController.sourceView = weakSelf.navigationController.navigationBar;
    menuController.popoverPresentationController.sourceRect = internalView.frame;
    menuController.popoverPresentationController.canOverlapSourceViewRect = YES;
}


internalView似乎为零,而不是在旧版iOS中获得UIView。弹出窗口显示在屏幕的左上角,而不是导航栏按钮项附近。

方式二

因此,我想尝试另一种方式来做到这一点,实际上是“正确的方式”:

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    menuController.popoverPresentationController.barButtonItem = weakSelf.navigationItem.rightBarButtonItem;
}


当我尝试使用此代码时,应用程序崩溃,并显示一条消息,提示我必须设置sourceView / sourceRect / barButtonItem。但是我告诉它去做。


  由于未捕获的异常“ NSGenericException”而终止应用程序,原因:“您的应用程序呈现了UISmartNavigationController()的UIAlertControllerStyleActionSheet样式的UIAlertController()。具有此样式的UIAlertController的modalPresentationStyle为UIModalPresentationPopover。您必须通过警报控制器的popoverPresentationController提供此弹出窗口的位置信息。您必须提供sourceView和sourceRect或barButtonItem。如果在显示警报控制器时不知道此信息,则可以在UIPopoverPresentationControllerDelegate方法-prepareForPopoverPresentation中提供它。


我也尝试使用UIPopoverPresentationControllerDelegate,但得到相同的结果。

我检查并重新检查,weakSelf.navigationItem.rightBarButtonItem不是零,并设置为右栏按钮项。我想我想念一些巨大的东西,但是呢?

最佳答案

Apple文档参考此页面。
https://developer.apple.com/documentation/uikit/windows_and_screens/displaying_transient_content_in_a_popover
但是,示例代码引用了一个从未定义的对象optionsControl。我可以得到一些构建,部署和运行的变体,但是所有崩溃都会出现类似的错误,例如:
由于出现未捕获的异常'NSGenericException'而终止应用程序,原因:'UIPopoverPresentationController()在演示之前应设置非null的sourceView或barButtonItem。
最后,经过三天的阅读,我发现了此页面UIActivityViewController crashing on iOS 8 iPads,该页面帮助我在下面创建了一个工作版本。这比我尝试过的其他方法简单得多。关键是将控制器的sourceView设置为对我来说是object.view的父视图,因为object是对作为发送方传入的父视图控制器的引用。

static func transmitAirDrop(object: ProjectOrganizerMasterViewController) {
    NSLog("UTVCU.transmitAirDrop")
    if (StatusReportSettings.supportsAirdrop() == false) {
        self.sendMultipleXMLEmail(object: object)
        return;
    }
    let myDelegate : StatusReportAppDelegate = UITableViewController.sharedDelegate()
    let documentsDirectory : String = UITableViewController.persistProjectFiles(managedObjectContext: object.managedObjectContext, delegate: myDelegate as! ProjectOrganizerAppDelegate)

    let backupZipFileName : String = UITableViewController.backupExportZipFileName(StatusReportSettings.appSpecificFileName())!

    let password1 : String = object.passwordPromptController?.textFields?.first?.text ?? ""
    let backupZipFilePath : String = StatusReportMasterViewController.createPasswordProtectedExportZipFile(password1: password1, documentsDirectory: documentsDirectory)

    let url : URL = URL.init(fileURLWithPath: backupZipFilePath)
    NSLog("transmitAirDrop() url ->%@", url.path);



    let objectsToShare : NSArray = [url]

    NSLog("UTVCU.transmitAirDrop presentViewController calling");

    let controller = UIActivityViewController(activityItems: [url], applicationActivities: nil)
    controller.excludedActivityTypes = [.postToFacebook,
        .postToTwitter,
        .print,
        .copyToPasteboard,
        .assignToContact,
        .saveToCameraRoll]

    controller.popoverPresentationController?.sourceView = object.view


    object.present(controller, animated: true, completion: nil)


    NSLog("UTVCU.transmitAirDrop presentViewController returned");

}

10-07 17:06