问题描述
我有一个用于帮助管理用户使用MFMailComposeViewControllerDelegate发送电子邮件的过程的类。
代码很长,我几乎在所有ViewController中使用它。而且我认为我应该能够将其添加为UIVIewController的扩展。因此,我目前正在尝试执行此操作,但是却无法正确执行操作。
工作代码:
结构:
struct Feedback {
let recipients = [R.App.Contact.email] // [String]
let subject: String
let body: String
let footer: String
}
班级:
final class FeedbackManager: NSObject,MFMailComposeViewControllerDelegate {
private var Feedback: Feedback
private var completion: ((Result<MFMailComposeResult,Error>)->Void)?
override init() {
fatalError("Use FeedbackManager(Feedback:)")
}
init?(Feedback: Feedback) {
print("init()")
guard MFMailComposeViewController.canSendMail() else {
return nil
}
self.Feedback = Feedback
}
func send(on viewController: UIViewController,completion:(@escaping(Result<MFMailComposeResult,Error>)->Void)) {
print("send()")
var appVersion = ""
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
appVersion = version
}
let mailVC = MFMailComposeViewController()
self.completion = completion
mailVC.mailComposeDelegate = self
mailVC.setToRecipients(Feedback.recipients)
mailVC.setSubject(Feedback.subject)
mailVC.setMessageBody("<p>\(Feedback.body)<br><br><br><br><br>\(Feedback.footer)<br>Potfolio: (\(appVersion))<br>\(UIDevice.modelName) (\(UIDevice.current.systemVersion))</p>",isHTML: true)
dispatchQueue.main.async {
viewController.present(mailVC,animated:true)
}
}
func mailComposeController(_ controller: MFMailComposeViewController,didFinishWith result: MFMailComposeResult,error: Error?) {
print("mailComposeController()")
if let error = error {
completion?(.failure(error))
controller.dismiss(animated: true)
} else {
completion?(.success(result))
controller.dismiss(animated: true)
}
}
}
实施:
var FeedbackManager: FeedbackManager?
func sendEmail() {
let Feedback = Feedback(subject: "subject",body: "body",footer: "footer")
if let manager = FeedbackManager(Feedback: Feedback) {
self.FeedbackManager = manager
self.FeedbackManager?.send(on: self) { [weak self] result in
switch result {
case .failure(let error):
print("error: ",error.localizedDescription)
case .success(_):
print("Success")
}
self?.FeedbackManager = nil
}
} else { // Cant Send Email:
let FailedMenu = UIAlertController(title: "Please email " + R.App.Contact.email,message: nil,preferredStyle: .alert)
let okAlert = UIAlertAction(title: "Ok!",style: .default)
FailedMenu.addAction(okAlert)
dispatchQueue.main.async {
self.present(FailedMenu,animated: true)
}
}
}
我尝试屈光:
import UIKit
extension UIViewController {
func refactoredEmail(on viewController: UIViewController,with Feedback: Feedback,manager: inout FeedbackManager?) -> FeedbackManager? {
guard let letManager = FeedbackManager(Feedback: Feedback) else {
let FailedMenu = UIAlertController(title: "Please email " + R.App.Contact.email,style: .default)
FailedMenu.addAction(okAlert)
dispatchQueue.main.async {
viewController.present(FailedMenu,animated: true)
}
return nil
}
manager = letManager
manager?.send(on: self) { [weak manager] result in
switch result {
case .failure(let error):
print("error: ",error.localizedDescription)
case .success(_):
print("Success")
}
manager = nil
}
return letManager
}
}
实施:
var FeedbackManager: FeedbackManager?
func sendEmail() {
let Feedback = Feedback(subject: "subject",footer: "footer")
refactoredEmail(on: self,with: Feedback,manager: &FeedbackManager)
}
FeedbackManager类与上述相同。 -
按原样,此是功能,但是refactoredEmail
使用FeedbackManager
作为inout
参数。完成后,FeedbackManager
不会返回到nil
。
我不确定使用inout
有多糟(或没有)。而且我不完全了解闭包。但是,我的理解是FeedbackManager类必须是一个类,因为它是MFMailComposeViewControllerDelegate
的子类。因此,每个ViewController需要它自己的对该类的引用。 var FeedbackManager: FeedbackManager?
进入的位置。
FeedbackManager
然后可以在FeedbackManager
类中运行代码。哪一个MFMailComposeViewController
出现在FeedbackManager
所在的ViewController上。但是由于现在refactoredEmail()
是UIViewController的扩展,我猜想闭包捕获错误吗?
结论:我的目标是重新编写代码,以便希望与第一个实现代码块相比,减少在每个视图控制器中实现该代码。
另外,使用inout
有多糟?
解决方法
我不确定为什么经理在完成后不为零,但是我可以向您展示其他实现方式。
您可以使用关联的对象:
protocol FeedbackShowable: class {
func giveFeedback(with feedback: Feedback)
}
extension UIViewController: FeedbackShowable {
private enum AssociatedObjectKeys {
static var feedbackManager: String = "feedbackManager"
}
private var feedbackManager: FeedbackManager? {
get {
return objc_getAssociatedObject(self,&AssociatedObjectKeys.feedbackManager) as? FeedbackManager
}
set {
objc_setAssociatedObject(self,&AssociatedObjectKeys.feedbackManager,newValue as FeedbackManager?,.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
func giveFeedback(with feedback: Feedback) {
let feedbackManager = FeedbackManager(feedback: feedback)
self.feedbackManager = feedbackManager
feedbackManager.send(on: self) { [weak self] result in
self?.feedbackManager = nil
}
}
}