避免在 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,...
此外,您可以使用类似于 NSClassFromString
和 String(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
}
在下面的代码中,根据字符串比较,我决定显示哪个 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,...
此外,您可以使用类似于 NSClassFromString
和 String(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
}