Swift-重构代码封闭和内向?

问题描述

我有一个用于帮助管理用户使用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
        }
    }
}