2017-02-21 6 views
1

В следующем коде, основанном на сравнении строк, я принимаю решение о том, какой VC будет показан.Избегание повторяющегося кода в swift

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) 
} 

Теперь весь код повторяется, кроме имени класса, и я хочу этого избежать. Но, быстрые не имеют NSClassFromString

Как это сделать? Должен ли я использовать Generics/Templates? Какие-либо предложения!

Извините, если мне не хватает чего-то глупого здесь.

+1

Да, вы можете создать простую функцию для выполнения этой строки (с описанием: SomeViewController.self) –

ответ

3

удаления дублирование очевидна:

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 контроллерам. Либо использовать общий суперкласс или протокол.

+0

Благодарю Вас за Ваше время. Это мне очень помогло. :) –

0

Вы можете просто создать функцию, которая получает идентификатор и возвращает viewcontroller. Так как ваш XVC, YVC, ZVC действительно есть сходство, вы можете также сделать их подклассы других ВК, которые имеют их свойство, как data, isFull,...

Кроме того, вы можете использовать похожие на NSClassFromString с String(describing: SomeViewController.self) вернется SomeViewController

2

Редактировать

Я предпочитаю ответ Sulthan, так как она чище, что мое (Должен признать ...)

Для завершения моей, getControllerFor:type необходимость вернуть родительский класс. Забыл упомянуть его

я редактировал первый ответ, чтобы исправить несколько промахов и сделать его более кратким

Первый ответ

Вы могли бы сделать что-то вроде этого:

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

+0

Спасибо за ваше время :) –

2

Вы можете сделать это с помощью перечисления. Вам просто нужно, чтобы каждый из ваших ViewControllers соответствовал 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 
} 
Смежные вопросы