如何创建可在多个ViewController中复用的Alert View?
Great question! Your current implementation is a solid start, but there are a few tweaks we can make to make it more reusable, idiomatic, and less error-prone for iOS development. Let's break this down step by step:
First: Fix the Issue in Your Current Code
Your AlertView struct works in theory, but there's a critical mistake in how you're presenting the alert in your ViewController:
alert.present(alert, animated: true) { ... }
You can't call present(_:) on the alert itself—this method belongs to UIViewController. You need to call it on your ViewController instance instead. Also, using [weak self] in the completion closure helps avoid retain cycles. Here's the corrected call:
@IBAction func submitPressed(_ sender: Any) { let alertView = AlertView() let alert = alertView.showAlertBox(title: "Hours Added", message: "Hours have been updated") // Fix: Call present on self, not the alert self.present(alert, animated: true) { [weak self] in self?.dismiss(animated: true, completion: nil) self?.timeSubmitted = true self?.performSegue(withIdentifier: "unwindToMyHours", sender: nil) } }
Better Reusable Approaches
While your struct works after fixing the present call, we can optimize this for better reusability:
1. Use a UIViewController Extension (Most Idiomatic)
Extending UIViewController lets any ViewController show alerts with a single method call, eliminating the need to create extra objects or handle presentation logic in every VC. This is the standard approach in iOS development:
import UIKit extension UIViewController { // Basic alert with OK button and optional completion func showAlert(title: String, message: String, completion: (() -> Void)? = nil) { let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .cancel) { _ in completion?() }) present(alert, animated: true) } // Overload for alerts with custom actions (e.g., OK + Cancel) func showAlert(title: String, message: String, actions: [UIAlertAction]) { let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) actions.forEach { alert.addAction($0) } present(alert, animated: true) } }
Usage in your ViewController:
@IBAction func submitPressed(_ sender: Any) { showAlert(title: "Hours Added", message: "Hours have been updated") { [weak self] in self?.dismiss(animated: true) self?.timeSubmitted = true self?.performSegue(withIdentifier: "unwindToMyHours", sender: nil) } }
2. Static Method in Your AlertView Struct
If you prefer keeping alert logic in a dedicated struct, make the method static so you don't need to instantiate AlertView every time:
import UIKit struct AlertView { static func showAlertBox(title: String, message: String) -> UIAlertController { let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: { _ in })) return alert } }
Usage:
@IBAction func submitPressed(_ sender: Any) { let alert = AlertView.showAlertBox(title: "Hours Added", message: "Hours have been updated") self.present(alert, animated: true) { [weak self] in self?.dismiss(animated: true) self?.timeSubmitted = true self?.performSegue(withIdentifier: "unwindToMyHours", sender: nil) } }
Key Takeaways
- The
UIViewControllerextension is the most convenient approach because it integrates directly with the ViewController lifecycle and reduces boilerplate. - Always use
[weak self]in completion closures to prevent memory leaks. - Your original implementation was almost correct—fixing the presentation call and making the method static (or using an extension) makes it fully reusable across all ViewControllers.
内容的提问来源于stack exchange,提问作者user15554941

