2015-07-30 3 views
4

В моем проекте, использующем Swift 2, я имею дело с 2 протоколами, MyViewControllerProtocol и MyViewModelProtocol. Я хочу, чтобы все контроллеры View соответствовали MyViewControllerProtocol. Для этого протокола требуется свойство. Собственность должна соответствовать протоколу MyViewModel.Протокол Swift 2 - свойство с общим типом?

То, что я думал, будет работать здесь будет что-то вроде этого:

protocol MyViewControllerProtocol { 
    var viewModel: <T:MyViewModelProtocol> { get set } 
} 

class MyCustomViewModel: MyViewModelProtocol { 
    // Implementation here 
} 

Тогда для View Controller:

class ViewController: UIViewController, MyViewControllerProtocol { 
    var viewModel: MyCustomViewModel { 
     // Getter and Setter implementations here 
    } 
} 

Я, скорее всего, думать об этом так. Это не будет компилироваться, и я еще не видел этот тип реализации в сочетании с свойством. Есть ли какая-то другая модель, которая могла бы выполнить то, что я пытаюсь сделать здесь?

ответ

4

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

protocol MyViewModel { 
    var title: String { get set } 
} 

protocol MyViewController { 
    typealias MyViewModelType 

    var viewModel: MyViewModelType { get set } 
} 

class BaseViewController<T: MyViewModel>: MyViewController { 
    typealias MyViewModelType = T 
    var viewModel: T 

    init(_ viewModel: T) { 
    self.viewModel = viewModel 
    } 
} 

struct CarViewModel: MyViewModel { 
    var title: String = "Car" 
} 

struct BikeViewModel: MyViewModel { 
    var title: String = "Bike" 
} 

let car = BaseViewController(CarViewModel()) 
let bike = BaseViewController(BikeViewModel()) 

Если вы пытаетесь использовать его с моделью, не соответствующей вашему протоколу MyViewModel, он не будет работать:

struct AnotherModel { 
    var title: String = "Another" 
} 

let another = BaseViewController(AnotherModel()) 

Это имеет несколько подводных камней, как вы не можете передать контроллер представления с помощью аргумента MyViewController type, по причине typealias. Это не будет работать:

func something(vc: MyViewController) { 
} 

Почему не проще подход без typealias. Если я правильно вас понял, вам они не нужны. Что-то вроде:

protocol MyViewModel { 
    var title: String { get set } 
} 

protocol MyViewController { 
    var viewModel: MyViewModel { get set } 
} 

class BaseViewController: MyViewController { 
    var viewModel: MyViewModel 

    init(_ viewModel: MyViewModel) { 
    self.viewModel = viewModel 
    } 
} 

struct CarViewModel: MyViewModel { 
    var title: String = "Car" 
} 

struct BikeViewModel: MyViewModel { 
    var title: String = "Bike" 
} 

И теперь вы можете использовать MyViewController протокол как тип переменной:

let bike: MyViewController = BaseViewController(BikeViewModel()) 
let car: MyViewController = BaseViewController(CarViewModel()) 

Вы можете передать его в какой-то функции, как MyViewController:

func something(vc: MyViewController) { 
} 

И вы можете» t сделать это также:

struct AnotherViewModel { 
    var title: String = "Another" 
} 

let another: MyViewController = BaseViewController(AnotherViewModel()) 

Я что-то пропустил? Я имею в виду, о ваших дженериках и ограничениях типа? У вас есть какой-то прецедент, который заставляет вас использовать их?

0

Протоколы в Swift не имеют общих угловых скобок. Для того, чтобы использовать родовое поведение, которое вы должны использовать typealias:

protocol MyViewControllerProtocol { 
    typealias T: MyViewModelProtocol 
    var viewModel: T { get set } 
} 
2

typealias для протоколов устарел и заменен associatedtype. Вышеуказанные ответы теперь будут написаны так:

protocol MyViewController { 
    associatedtype MyViewModelType 
    var viewModel: MyViewModelType { get set } 
} 
Смежные вопросы