如何显示来自不同班级的警报
Posted
技术标签:
【中文标题】如何显示来自不同班级的警报【英文标题】:How to display an Alert from a different class 【发布时间】:2017-09-13 02:14:55 【问题描述】:我创建了一个 Utilities 类来保存一些常用函数,其中之一是 alertUser 函数,如果调用该函数,将向用户显示一个带有提供的标题和消息文本的警报框。在另一个类文件中,我正在验证一些文本字段条目,如果验证没有通过,那么我想使用 Utilities 类中的 alertUser 函数。但是,当我这样做时,我在 Xcode 日志中收到以下错误消息:
Warning: Attempt to present <UIAlertController: 0x7f9c4be0b140> on <MyAppName.Utilities: 0x7f9c4be1cb60> whose view is not in the window hierarchy!
调用代码在 UIViewController 类文件中。这是在 类 ItemSettingsVC: UIViewController:
private func validateNameField() -> Bool
var passed = false
if (nameField.hasText)
passed = true
else
Utilities().alertUser(strTitle: "Alert", strMessage: strInvalidNameFieldErrorMsg)
passed = false
return passed
这是 alertUser 函数,它位于 类实用程序:UIViewController:
public func alertUser(strTitle: String, strMessage: String)
let myAlert = UIAlertController(title: strTitle, message: strMessage, preferredStyle: UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil)
myAlert.addAction(okAction)
self.present(myAlert, animated: true, completion: nil)
这是在 ios 上运行的。我正在使用 Xcode 8 和 swift 3。非常感谢任何帮助。谢谢。
【问题讨论】:
我已经给出了答案,但我也只想在这里发表评论以避免混淆你应该做什么。要回答您有关崩溃的问题,这是因为您的 Utilities(它是 UIViewController 的子类)不是您前台的当前视图,它试图通过调用 self 来呈现警报控制器这就是为什么我推荐下面的答案。也请注意那里的最后一条消息:) 【参考方案1】:应该这样做:
public func alertUser(strTitle: String, strMessage: String)
let myAlert = UIAlertController(title: strTitle, message: strMessage, preferredStyle: UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil)
myAlert.addAction(okAction)
UIApplication.shared.delegate?.window??.rootViewController?.present(myAlert, animated: true, completion: nil)
【讨论】:
【参考方案2】:您必须在 alertUser 函数中添加一个附加参数,该参数将是显示警报控制器的 VC。
例如:
public func alertUser(strTitle: String, strMessage: String, viewController: UIViewController)
let myAlert = UIAlertController(title: strTitle, message: strMessage, preferredStyle: UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil)
myAlert.addAction(okAction)
viewController.present(myAlert, animated: true, completion: nil)
但我建议您只制作 UIViewController 的 extension 并在其中添加您的 func alertUser()*,因为您肯定会使用在我看来,不同 VC 和复杂性方面的这个 alertUser 会更加优化。
像这样:
extension UIViewController
func showAlert(title: String, message: String, callback: @escaping () -> ())
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler:
alertAction in
callback()
))
self.present(alert, animated: true, completion: nil)
//add additional functions here if necessary
//like a function showing alert with cancel
注意:请不要将 Utilities 类设为 UIViewController 的子类,最好将其设为 struct 处理静态函数和/或变量
【讨论】:
【参考方案3】:使用这个类可以轻松显示 Alert 或 ActionSheet
UIAlertController 扩展
public extension UIAlertController
public func showAlert(animated: Bool = true, completionHandler: (() -> Void)? = nil)
guard let rootVC = UIApplication.shared.keyWindow?.rootViewController else
return
var forefrontVC = rootVC
while let presentedVC = forefrontVC.presentedViewController
forefrontVC = presentedVC
forefrontVC.present(self, animated: animated, completion: completionHandler)
为 UIAlertController Show 创建 AppAlert 类
public class AppAlert
private var alertController: UIAlertController
public init(title: String? = nil, message: String? = nil, preferredStyle: UIAlertControllerStyle)
self.alertController = UIAlertController(title: title, message: message, preferredStyle: preferredStyle)
public func setTitle(_ title: String) -> Self
alertController.title = title
return self
public func setMessage(_ message: String) -> Self
alertController.message = message
return self
public func setPopoverPresentationProperties(sourceView: UIView? = nil, sourceRect:CGRect? = nil, barButtonItem: UIBarButtonItem? = nil, permittedArrowDirections: UIPopoverArrowDirection? = nil) -> Self
if let poc = alertController.popoverPresentationController
if let view = sourceView
poc.sourceView = view
if let rect = sourceRect
poc.sourceRect = rect
if let item = barButtonItem
poc.barButtonItem = item
if let directions = permittedArrowDirections
poc.permittedArrowDirections = directions
return self
public func addAction(title: String = "", style: UIAlertActionStyle = .default, handler: @escaping ((UIAlertAction!) -> Void) = _ in ) -> Self
alertController.addAction(UIAlertAction(title: title, style: style, handler: handler))
return self
public func addTextFieldHandler(_ handler: @escaping ((UITextField!) -> Void) = _ in ) -> Self
alertController.addTextField(configurationHandler: handler)
return self
public func build() -> UIAlertController
return alertController
用于打开警报框
AppAlert(title: "Question", message: "Are you sure?", preferredStyle: .alert)
.addAction(title: "NO", style: .cancel) _ in
// action
.addAction(title: "Okay", style: .default) _ in
// action
.build()
.showAlert(animated: true)
用于 ActionSheet 打开
if UIDevice.current.userInterfaceIdiom != .pad
// Sample to show on iPhone
AppAlert(title: "Question", message: "Are you sure?", preferredStyle: .actionSheet)
.addAction(title: "NO", style: .cancel) _ in
print("No")
.addAction(title: "YES", style: .default) _ in
print("Yes")
.build()
.showAlert(animated: true)
else
// Sample to show on iPad
AppAlert(title: "Question", message: "Are you sure?", preferredStyle: .actionSheet)
.addAction(title: "Not Sure", style: .default)
_ in
print("No")
.addAction(title: "YES", style: .default) _ in
print("Yes")
.setPopoverPresentationProperties(sourceView: self, sourceRect: CGRect.init(x: 0, y: 0, width: 100, height: 100), barButtonItem: nil, permittedArrowDirections: .any)
.build()
.showAlert(animated: true)
【讨论】:
【参考方案4】:首先找出窗口上最顶层的 viewController。
Get the top ViewController in iOS Swift
然后在该 viewController 上显示您的警报。无需传递任何参数。
public func alertUser(strTitle: String, strMessage: String)
let myAlert = UIAlertController(title: strTitle, message: strMessage, preferredStyle: UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil)
myAlert.addAction(okAction)
topmostVC().present(myAlert, animated: true, completion: nil)
【讨论】:
以上是关于如何显示来自不同班级的警报的主要内容,如果未能解决你的问题,请参考以下文章
何时需要获取PermanentIDsForObjects:error:?来自2个不同的班级?
我如何使用文本字段警报操作来更新单独的UIViewController上的标签?
依次显示两个相同的警报视图。如何区分来自警报 1 和警报 2 的文本?