Subclassing UIAlertController and encountering runtime errors

大憨熊 提交于 2020-01-01 12:07:07

问题


I'm new to programming for iOS and OSX, and decided to start with Swift and use the iOS8 API's for a test app and attempt some programming techniques I use in other environments. However, I'm encountering a strange situation which I hope someone could identify and help me with. This involves difficulties subclassing UIAlertController.

This was my first attempt:

import UIKit

class FubarAlertController: UIAlertController {

    convenience init (message:String) {
        self.init(title: "Alert", message: message, preferredStyle: UIAlertControllerStyle.Alert);
        self.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
    }
}

However, I got the following warnings in Xcode, which I don't understand- to my eyes, the errors appear to me to be self contradictory (pardon the bad pun)

use of self in delegating initializer before self.init is called
Self.init is't called on all paths in delegating initialiser

So then I tried

class FubarAlertController: UIAlertController {

    convenience init (message:String) {
        self.init();
        self.title = "Alert";
        self.message = message;
        self.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
    }
}

and did not encounter any compile time errors. However, when I use this from a simple ViewController like so

class FubarController: UIViewController {

    // method invoked when a UIBarButtonItem action takes place 

    @IBAction
    func enterTextButtonAction(sender: UIBarButtonItem) {

        let controller = FubarAlertController(message: "Fubar!");
        presentViewController(controller, animated: true, completion: nil);
    }   
}

I get the following runtime error which again, I don't quite understand

*** Terminating app due to uncaught exception 'NSGenericException', 
reason: 'Your application has presented a UIAlertController
(<UiToolKit.TextChangedAlertController: 0x7adf2340>) of style 
UIAlertControllerStyleActionSheet. The modalPresentationStyle of a 
UIAlertController with this style is UIModalPresentationPopover. You 
must provide location information for this popover through the alert 
controller's popoverPresentationController. You must provide either a 
sourceView and sourceRect or a barButtonItem.  If this information is
not known when you present the alert controller, you may provide it in the 
UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation.'

But, if I simply implement FubarAlertController with no methods or properties at all, I can call it exactly as if it were a UIAlertController in the interface builder action like so

class FubarController: UIViewController {

    // method invoked when a UIBarButtonItem action takes place 

    @IBAction
    func enterTextButtonAction(sender: UIBarButtonItem) {
        let controller = FubarAlertController(title: "Alert", message: "Fubar!", preferredStyle: UIAlertControllerStyle.Alert);
        controller.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
        presentViewController(controller, animated: true, completion: nil);
    }   
}   

... and everything works as expected - no compile time or run time errors but I don't understand why!

So my questions are:

(i) Why couldn't I implement the convenience init method in the manner of my first attempt? What magic knowledge am I missing here? Why couldn't I call a super class init method in the context of self within a convenience initialiser?

(ii) How come I get run time as opposed to compile time errors when I subclass UIAlertController as I implemented it the second time?

Many thanks for making it this far and looking forward to some feedback - I'm stumped!


回答1:


I know this is an old question, but thought it could use at least a partial answer.

(I) I've had to do the same as you to get a subclass of UIAlertController working. I think the simple answer is "Don't do it". Apple technically doesn't allow subclassing of UIAlertController, as per their documentation:

The UIAlertController class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified.

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIAlertController_class/

(II) I got this same error when running my working iPhone app on iPad.

*** Terminating app due to uncaught exception 'NSGenericException', 
reason: 'Your application has presented a UIAlertController of style 
UIAlertControllerStyleActionSheet. The modalPresentationStyle of a 
UIAlertController with this style is UIModalPresentationPopover. You 
must provide location information for this popover through the alert 
controller's popoverPresentationController. You must provide either a 
sourceView and sourceRect or a barButtonItem.  If this information is
not known when you present the alert controller, you may provide it in the 
UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation.'

Since a popover on iPad is not full screen, iPad needs the sourceView or sourceRect property set to determine where on screen the popover should show from.

Add some code like this to your UIAlertController whenever you set the style to .ActionSheet:

//For iPad, check that there is a popover and set action button as the sender
if let popoverController = controller.popoverPresentationController {
        //Sender will be a UIButton, cast down to UIView
        popoverController.sourceView = sender as? UIView
        popoverController.sourceRect = sender.bounds
}

You may have to tweak this, depending your situation. My example above came from a IBAction function where sender is a UIButton.



来源:https://stackoverflow.com/questions/26935703/subclassing-uialertcontroller-and-encountering-runtime-errors

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!