避免在 swift 中重复代码

Avoiding repeating code in swift

在下面的代码中,根据字符串比较,我决定显示哪个 VC。

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    dataObj = frc.object(at: indexPath) as! Data_Object
    var pvc: UIViewController?

    if dataObj.type == "X" {

        let obj = MainStoryboard().instantiateViewController(withIdentifier: "XVC") as! XVC
        obj.data = dataObj
        obj.isFull = true
        obj.delegate = self
        pvc = obj as UIViewController

    } else if dataObj.type == "Y" {

        let obj = MainStoryboard().instantiateViewController(withIdentifier: "YVC") as! YVC
        obj.data = dataObj
        obj.isFull = true
        obj.delegate = self
        pvc = obj as UIViewController

    } else {

        let obj = MainStoryboard().instantiateViewController(withIdentifier: "ZVC") as! ZVC
        obj.data = dataObj
        obj.isFull = true
        obj.delegate = self
        pvc = obj as UIViewController
    }

    obj.modalPresentationStyle = .popover
    let popPVC = pvc?.popoverPresentationController
    popPVC?.sourceView = self.view
    self.present(pvc!, animated: true, completion: nil)
}

现在,除了 class 名称之外,所有代码都是重复的,我想避免这种情况。但是,swift没有NSClassFromString

我该如何做到这一点?我应该使用 Generics/Templates 吗?有什么建议!

如果我遗漏了一些愚蠢的东西,请提前道歉。

您可以只创建一个获取标识符和 return viewcontroller 的函数。由于您的 XVC、YVC、ZVC 确实具有相似性,您还可以使它们成为其他具有 属性 的 VC 的子类 data, isFull,...

此外,您可以使用类似于 NSClassFromStringString(describing: SomeViewController.self) 将 return SomeViewController

重复删除很明显:

let identifier: String

switch dataObj.type {
    case "X":
       identifier = "XVC"
    case "Y":
       identifier = "YVC"
    default:
       identifier = "ZVC"
}

let pvc = MainStoryboard().instantiateViewController(withIdentifier: identifier) as! PVC
pvc.data = dataObj
pvc.isFull = true
pvc.delegate = self

其中 PVC 是您的 3 个控制器的通用超类,例如:

class PVC : UIViewController {}
class XVC : PVC {}
class YVC : PVC {}
class ZVC : PVC {}

如果您的 3 类 没有通用的超类,您可以使用协议代替:

protocol PVC : class {
   var data: ...
   var isFul: ...
   weak var delegate: ...
}

并由您的 3 类:

实施

简而言之,要消除重复,您需要为 3 个控制器添加一个通用接口。使用通用的超类或协议。

编辑

我更喜欢 Sulthan 的回答,因为它比我的更干净(不得不承认...)

要完成我的,getControllerFor:type 需要 return 一个 parent class。忘记说了

我编辑了第一个答案以纠正一些遗漏并使其更简洁

第一个回答

你可以这样做:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

  dataObj = frc.object(at: indexPath) as! Data_Object
  var pvc: UIViewController?

  let obj = getControllerFor(type: dateObj.type)
  obj.data = dataObj
  obj.isFull = true
  obj.delegate = self
  pvc = obj as UIViewController
  obj.modalPresentationStyle = .popover
  let popPVC = pvc?.popoverPresentationController
  popPVC?.sourceView = self.view
  self.present(pvc!, animated: true, completion: nil)
}



func getControllerFor(type : String) -> SuperType? {
  switch type {
  case "X": return XVC()
  case "Y": return YVC()
  case "Z": return ZVC()
  default: return nil
  }
}

class SuperType {}
class XVC: SuperType {}
class YVC: SuperType {}
class ZVC: SuperType {}

理想情况下,type 不是 String,而是 Enum

您可以使用枚举很好地做到这一点。您只需要让每个 ViewController 都符合 CustomViewController。

enum ViewControllers: String {
    case x = "X"
    case y = "Y"
    case z = "Z"

    func getViewController<T>(dataObj: Data_Object, delegate: YourDelegate?) -> T where T: UIViewController, T: CustomViewController {
        let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: self.rawValue) as! T
        viewController.data = dataObj
        viewController.isFull = true
        viewController.delegate = delegate

        return viewController
    }
}

protocol CustomViewController: class {
    var data: Data_Object! { get set }
    var isFull: Bool! { get set }
    weak var delegate: YourDelegate? { get set }
}

然后你会像这样使用它:

if dataObj.type == "X" {
     let vc: XVC = ViewControllers.x.getViewController(dataObj: dataObj, delegate: self)
    pvc = vc
}