如何修复 "UIPopoverController is deprecated" 警告?

How can I fix the "UIPopoverController is deprecated" warning?

我正在使用此代码:

mediaLibraryPopover = [[UIPopoverController alloc] 
                        initWithContentViewController:avc];
[self.mediaLibraryPopover presentPopoverFromRect:[theButton bounds] 
                          inView:theButton 
                          permittedArrowDirections:UIPopoverArrowDirectionAny 
                          animated:YES];

我在 Xcode 7:

中收到此警告

UIPopoverController is deprecated, first deprecated in iOS 9.0 - UIPopoverController is deprecated. Popovers are now implemented as UIViewController presentations. Use a modal presentation style of UIModalPresentationPopover and UIPopoverPresentationController.

您不再需要 UIPopoverController 来呈现视图控制器。 相反,您可以将视图控制器的 modalPresentationStyle 设置为 UIModalPresentationPopover.

您可以为此使用以下代码:

avc.modalPresentationStyle = UIModalPresentationPopover;
avc.popoverPresentationController.sourceView = theButton;
[self presentViewController:avc animated:YES completion:nil];

UIModalPresentationPopover

In a horizontally regular environment, a presentation style where the content is displayed in a popover view. The background content is dimmed and taps outside the popover cause the popover to be dismissed. If you do not want taps to dismiss the popover, you can assign one or more views to the passthroughViews property of the associated UIPopoverPresentationController object, which you can get from the popoverPresentationController property.

In a horizontally compact environment, this option behaves the same as UIModalPresentationFullScreen.

Available in iOS 8.0 and later.

引用UIModalPresentationStyle Reference


您需要设置 sourceViewbarButtonItem 属性,否则它会崩溃并显示以下消息:

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'UIPopoverPresentationController (***) should have a non-nil sourceView or barButtonItem set before the presentation occurs.'

为了正确定位弹出框箭头,您还需要指定 sourceRect 属性。

avc.modalPresentationStyle                   = UIModalPresentationPopover;
avc.popoverPresentationController.sourceView = self.view;
avc.popoverPresentationController.sourceRect = theButton.frame;
[self presentViewController:avc animated:YES completion:nil];

参考sourceView and sourceRect了解更多详情。

编辑:关于反对票。首先是一个有趣且相关的故事:

http://www.folklore.org/StoryView.py?story=Negative_2000_Lines_Of_Code.txt

我 post 编辑了下面的答案,以帮助编码人员可能一直认为 iPad/iPhone 在呈现媒体选择器时仍然需要单独的执行路径 UI. 在我原来的时候 post 这在其他答案中并不清楚。此解决方案路径简化了我的代码和我的应用程序的未来维护。我认为其他人可能会发现这种观点很有用,因为有时删除正确的代码行可能是一个很好的解决方案。

编辑结束。

如果您已经有一个有效的程序并且只是想摆脱折旧警告,这可能适合您。

在我的代码中,根据我的理解,弹出框是为 iPad 引入的,并且是 iPad 特定的。苹果似乎已经改变了这一点。所以,如果你已经有一个使用类似这样的东西的工作程序:

if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
    // use popovers 
else
    //  don't use popovers

你能做的就是摆脱 iPad 特定代码(这可能是使用 Popover 的代码)并让你的程序 运行 对两个 iPhone 使用相同的指令和 iPad。这对我有用。

如果想直接从 Button Action 中获取,则可以使用此代码

SecondViewController *destinationViewController = (SecondViewController *)[self.storyboard instantiateViewControllerWithIdentifier:@"second"];
destinationViewController.modalPresentationStyle = UIModalPresentationPopover;
destinationViewController.popoverPresentationController.sourceView = self.customButton;

// Set the correct sourceRect given the sender's bounds
destinationViewController.popoverPresentationController.sourceRect = ((UIView *)sender).bounds;
[self presentViewController:destinationViewController animated:YES completion:nil];

Apple 在此处为 iOS8 提供了显示和配置弹出窗口的官方方法:https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIPopoverPresentationController_class/index.html

虽然与@MidhunMP 的回答相似,但值得注意的是段落:

Configuring the popover presentation controller after calling presentViewController:animated:completion: might seem counter-intuitive but UIKit does not create a presentation controller until after you initiate a presentation. In addition, UIKit must wait until the next update cycle to display new content onscreen anyway. That delay gives you time to configure the presentation controller for your popover.

如果需要,也可以通过委托完成配置和响应事件 (https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIPopoverPresentationControllerDelegate_protocol/index.html)。

举个例子,抛开delegate的使用:

// Present the controller using the popover style.
controller.modalPresentationStyle = UIModalPresentationPopover;
[self presentViewController:controller animated:YES completion:nil];

// Popover presentation controller was created when presenting; now  configure it.
UIPopoverPresentationController *presentationController =
        [controller popoverPresentationController];
presentationController.permittedArrowDirections = UIPopoverArrowDirectionLeft;
presentationController.sourceView = containerFrameOfReferenceView;
// arrow points out of the rect specified here
presentationController.sourceRect = childOfContainerView.frame;

但是你也想忽略它。要在不使用委托的情况下这样做,您的呈现控制器只需调用:

[self dismissViewControllerAnimated:YES completion:nil];

但是如果我旋转我的设备,弹出窗口没有指向正确的区域怎么办?您的呈现控制器可以处理它:

// Respond to rotations or split screen changes
- (void)viewWillTransitionToSize:(CGSize)size
       withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    [coordinator animateAlongsideTransition:nil 
                                 completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
        // Fix up popover placement if necessary, after the transition.
        if (self.presentedViewController) {
            UIPopoverPresentationController *presentationController =
                    [self.presentedViewController popoverPresentationController];
            presentationController.sourceView = containerFrameOfReferenceView;
            presentationController.sourceRect = childOfContainerView.frame;
        }
    }];
}