问题
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