Swift UIAlertController - > ActionSheet iPad iOS8崩溃

时间:2014-09-25 12:56:17

标签: iphone ipad swift uiactionsheet

目前我的ActionSheet遇到了大麻烦。在iPhone上它运行良好,但在iPad上它只会崩溃

我只用一个按钮创建一个新项目

import UIKit

extension ViewController : UIActionSheetDelegate {

    func actionSheet(actionSheet: UIActionSheet, didDismissWithButtonIndex buttonIndex: Int) {

        if actionSheet.tag == 0 {
            if buttonIndex == 1 {
                // doing something for "product page"
            } else if (buttonIndex == 2) {
                // doing something for "video"
            }
        }
    }

}

class ViewController: UIViewController, UIActionSheetDelegate {
    @IBAction func test(sender: AnyObject) {

        let systemVersion: NSInteger = (UIDevice.currentDevice().systemVersion as NSString).integerValue
        if systemVersion < 8 {
            // iOS7:
            let action:UIActionSheet = UIActionSheet(title: "Change Map Type", delegate: self, cancelButtonTitle: "Back", destructiveButtonTitle: nil, otherButtonTitles: "Product Page", "Video")
            action.tag = 0
            action.showInView(self.view)
        } else {
            // iOS8:
            let alertController: UIAlertController = UIAlertController(title: "Change Map Type", message: nil, preferredStyle: UIAlertControllerStyle.ActionSheet)
            let cancelAction: UIAlertAction = UIAlertAction(title: "Back", style: UIAlertActionStyle.Cancel, handler: nil)
            let button1action: UIAlertAction = UIAlertAction(title: "Product Page", style: UIAlertActionStyle.Default, handler: { (action: UIAlertAction!) -> () in
                // doing something for "product page"
            })
            let button2action: UIAlertAction = UIAlertAction(title: "Video", style: UIAlertActionStyle.Default, handler: { (action: UIAlertAction!) -> () in
                // doing something for "video"
            })
            alertController.addAction(cancelAction)
            alertController.addAction(button1action)
            alertController.addAction(button2action)

            self.presentViewController(alertController, animated: true, completion: nil)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

}

正如我在iphone上说的那样,但如果我点击iPad上的按钮应用程序崩溃了

  

2014-09-25 14:54:52.784 test [9541:1970048] *终止应用程序   未捕获的异常'NSGenericException',原因:'您的应用程序有   提出了一个UIAlertController()   style UIAlertControllerStyleActionSheet。的modalPresentationStyle   具有此样式的UIAlertController是UIModalPresentationPopover。您   必须通过警报提供此弹出窗口的位置信息   controller的popoverPresentationController。你必须提供一个   sourceView和sourceRect或barButtonItem。如果这个信息是   当您出示警报控制器时不知道,您可以提供它   UIPopoverPresentationControllerDelegate方法   -prepareForPopoverPresentation“。   * 第一次抛出调用堆栈:(0 CoreFoundation 0x00613df6 exceptionPreprocess + 182 1 libobjc.A.dylib
  0x01fdaa97 objc_exception_throw + 44 2 UIKit
  0x0164da37 - [UIPopoverPresentationController   presentationTransitionWillBegin] + 3086 3 UIKit
  0x00f54f75 __71- [UIPresentationController   _initViewHierarchyForPresentationSuperview:] _ block_invoke + 1666 4 UIKit 0x00f53554   __56- [UIPresentationController runTransitionForCurrentState] _block_invoke + 226 5 UIKit
  0x00f8721b __40 + [UIViewController _scheduleTransition:] _ block_invoke +   18 6 UIKit 0x00e4d62e   ___afterCACommitHandler_block_invoke + 15 7 UIKit 0x00e4d5d9 _applyBlockToCFArrayCopiedToStack + 415 8 UIKit
  0x00e4d3ee _afterCACommitHandler + 545 9 CoreFoundation
  0x00536fbe   __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION
+ 30 10 CoreFoundation 0x00536f00 __CFRunLoopDoObservers   + 400 11 CoreFoundation 0x0052c93a __CFRunLoopRun + 1226 12 CoreFoundation 0x0052c1ab CFRunLoopRunSpecific + 443 13 CoreFoundation
  0x0052bfdb CFRunLoopRunInMode + 123 14 GraphicsServices
  0x0438424f GSEventRunModal + 192 15 GraphicsServices
  0x0438408c GSEventRun + 104 16 UIKit
  0x00e23e16 UIApplicationMain + 1526 17测试
  0x00085e9e top_level_code + 78 18测试
  0x00085edb main + 43 19 libdyld.dylib
  0x0273eac9开始+ 1 20 ???   0x00000001 0x0 + 1)libc ++ abi.dylib:以未捕获终止   NSException类型的异常

可以在https://www.dropbox.com/s/54jqd8nsc67ll5g/test.zip?dl=0找到项目进行下载并尝试。

8 个答案:

答案 0 :(得分:145)

错误消息告诉您需要向警报控制器的popoverPresentationController提供一个位置,以便它可以正确定位。这很容易做 - 只需检查是否有弹出控制器并将发件人添加为源。

如果您的按钮是UIBarButtonItem

if let popoverController = alertController.popoverPresentationController {
    popoverController.barButtonItem = sender
}
self.presentViewController(alertController, animated: true, completion: nil)

否则:

if let popoverController = alertController.popoverPresentationController {
    popoverController.sourceView = sender
    popoverController.sourceRect = sender.bounds
}
self.presentViewController(alertController, animated: true, completion: nil)

答案 1 :(得分:7)

试试这个

alertController.popoverPresentationController?.sourceView = self.view

答案 2 :(得分:2)

Nate Cook是完全正确但我会这样做,所以我发现它是iPad还是iPhone。

这适用于// decimal truncation is free when dealing with int/long long value = new Date().getTime() / 1000 / 30; byte[] data = new byte[8]; for (int i = 8; i-- > 0; value >>>= 8) { data[i] = (byte) value; } byte[] hash = hmacSha1(data, key);

barButtonItem

答案 3 :(得分:1)

var actionSheet = UIAlertController(title: "Please Select Camera or Photo Library", message: "", preferredStyle: .actionSheet)

if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad ){
    actionSheet = UIAlertController(title: "Please Select Camera or Photo Library", message: "", preferredStyle: .alert)
}

actionSheet.addAction(UIAlertAction(title: "Upload a Photo", style: .default, handler: { (UIAlertAction) in
    self.openPhotoLibrary()
}))
actionSheet.addAction(UIAlertAction(title: "Take a Photo", style: .default, handler: { (UIAlertAction) in
    self.openCamera()
}))
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(actionSheet, animated: true, completion: nil)

答案 4 :(得分:1)

如果您想在iPad上无箭头地将其展示在屏幕上[ Swift 3 + ]:

struct EventA {};

struct EventB {};

struct EventC {};

using Event = std::variant<EventA, EventB, EventC>;

struct Visitor {
  enum class LastEvent { None, A, B, C };

  struct State {
    LastEvent last_event = LastEvent::None;
  };

  static State apply(State s, EventA e) { return State{LastEvent::A}; }

  static State apply(State s, EventB e) { return State{LastEvent::B}; }
};

template <typename Visitor> struct Applicator {

  static State apply(State s, Event e) {

    /*** Start of pseudo code ***/
    if (Visitor can apply) {
      return Visitor::apply(s, e);
    }
    /*** End of pseudo code ***/

    // Else, don't update state state
    return s;
  }
};

int main() {
  // Handled by visitor
  State s1 = Applicator<Visitor>::apply(State{}, EventA{});
  assert(s1.last_event == Visitor::LastEvent::A);

  // Handled by visitor
  State s2 = Applicator<Visitor>::apply(State{}, EventB{});
  assert(s2.last_event == Visitor::LastEvent::B);

  // NOT handled by visitor
  State s3 = Applicator<Visitor>::apply(State{}, EventC{});
  assert(s3.last_event == Visitor::LastEvent::None);
}

答案 5 :(得分:0)

如果有人使用 sender:UITapGestureRecognizer ,这可能会有所帮助。

@objc func popupSettings(sender : UITapGestureRecognizer) {
    .....
    if let popoverPresentationController = alert.popoverPresentationController {
        popoverPresentationController.sourceView = self.view
        popoverPresentationController.sourceRect = CGRect(origin: sender.location(in: self.view), size: CGSize(width: 1.0, height: 1.0))
    }
    self.present(alert, animated: true, completion: nil)
}

答案 6 :(得分:0)

如果您想在中心显示警报而没有箭头,我尝试了一下,它可以在iOS 11.2上运行

swift 4.2版本:

let actionSheet = UIAlertController ......
if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad ){

        if let currentPopoverpresentioncontroller = actionSheet.popoverPresentationController{
            currentPopoverpresentioncontroller.permittedArrowDirections = []
            currentPopoverpresentioncontroller.sourceRect = CGRect(x: (self.view.bounds.midX), y: (self.view.bounds.midY), width: 0, height: 0)
            currentPopoverpresentioncontroller.sourceView = self.view
            self.present(actionSheet, animated: true, completion: nil)
        }
    }else{
        self.present(actionSheet, animated: true, completion: nil)
    }

目标C版本:

UIAlertController* actionSheet 
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    NSArray *empty;
    UIPopoverPresentationController *currentPopOverPresentationController = [actionSheet popoverPresentationController];
    currentPopOverPresentationController.permittedArrowDirections = empty;
    currentPopOverPresentationController.sourceRect = CGRectMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds), 0, 0);
    currentPopOverPresentationController.sourceView = self.view;

    [self presentViewController:actionSheet animated:YES completion:nil];
}else{
    [self presentViewController:actionSheet animated:YES completion:nil];
}

答案 7 :(得分:0)

跟进Nate Cook的回答。如果您的按钮是UIBarButtonItem,则可能有必要在sender上进行强制转换。

if let popoverController = alertController.popoverPresentationController {
    popoverController.barButtonItem = sender as! UIBarButtonItem
}
self.presentViewController(alertController, animated: true, completion: nil)