我是iOS和OSX编程的新手,并决定从
Swift开始,将iOS8 API用于测试应用程序,并尝试在其他环境中使用的一些编程技术.但是,我遇到了一个奇怪的情况,我希望有人可以识别和帮助我.这涉及对UIAlertController进行子类化的困难.
这是我的第一次尝试:
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))
}
}
但是,我在Xcode中收到了以下警告,我不明白 – 在我看来,错误在我看来是自相矛盾的(原谅坏双关语)
use of self in delegating initializer before self.init is called
Self.init is't called on all paths in delegating initialiser
所以我试过了
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))
}
}
并没有遇到任何编译时错误.但是,当我从一个简单的ViewController中使用它时,就像这样
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);
}
}
我得到以下运行时错误,我不太明白
*** 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.'
但是,如果我只是简单地实现没有方法或属性的FubarAlertController,我可以像调用接口构建器动作中的UIAlertController一样调用它.
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);
}
}
…一切都按预期工作 – 没有编译时间或运行时错误,但我不明白为什么!
所以我的问题是:
(i)为什么我不能以第一次尝试的方式实现便捷初始化方法?我在这里错过了什么神奇的知识?为什么我不能在便捷初始化器中在self的上下文中调用超类init方法?
(ii)当我第二次实现UIAlertController的子类时,为什么我得到运行时而不是编译时错误?
非常感谢你做到这一点,并期待一些反馈 – 我很难过!
最佳答案 我知道这是一个老问题,但认为它至少可以使用部分答案.
(I)我必须像你一样做UIAlertController的子类.我认为简单的答案是“不要这样做”. Apple技术上不允许根据他们的文档对UIAlertController进行子类化:
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)
我在iPad上运行我的iPhone应用程序时遇到同样的错误.
*** 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.'
由于iPad上的弹出窗口不是全屏,因此iPad需要设置sourceView或sourceRect属性来确定弹出窗口应在何处显示.
每当您将样式设置为.ActionSheet时,将这样的代码添加到您的UIAlertController:
//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
}
根据您的具体情况,您可能需要调整此项.我上面的例子来自IBAction函数,其中sender是UIButton.