2017-03-07 7 views
2

신속 프로토콜 및 관련 유형 구현하는 경우 :확인 두 개체 내가 같은 관련 유형과 프로토콜을 선언 있어요 스위프트 3 프로젝트가

protocol ViewModelContainer { 
    associatedtype ViewModelType 
    var viewModel: ViewModelType! { get set } 
} 

을 그리고 나는 두 물체 있는지 확인하려면 ViewModelContainer을 구현하고 할당 유형을 ViewModelType으로 지정하면 '일반적인'방식으로 할당됩니다.

이상적으로 나는 같은 것을 할 싶습니다

if let container = container as? ViewModelContainer, let model = model as? container.ViewModelType { 
    container.viewModel = model 
} 

을하지만 캐스트 할 수 containerViewModelContainer에 :

프로토콜 'ViewModelContainer'은 단지 일반적인 제약 조건으로 사용할 수 있습니다

자체 또는 관련 유형 요구 사항이 있기 때문에


나의 현재 해결 방법은 직접 특정 클래스와 관련 타입으로 후퇴하는 것입니다,하지만 경향이 매우 자세한 오류 내 코드를 잎 :

override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 
    if let vc = segue.destination as? MediaPlaySelectionViewController, let vm = sender as? MediaPlaySelectionViewModel { 
     vc.viewModel = vm 
    } 
    if let vc = segue.destination as? SearchResultsViewController, let vm = sender as? SearchResultsViewModel { 
     vc.viewModel = vm 
    } 
    if let vc = segue.destination as? ReviewDetailsViewController, let vm = sender as? ReviewDetailsViewModel { 
     vc.viewModel = vm 
    } 
    if let vc = segue.destination as? ReviewComposerViewController, let vm = sender as? ReviewComposerViewModel { 
     vc.viewModel = vm 
    } 
} 

I 일반적인 UIViewController의를 사용했지만, 그러므로 Objective-C doesn't recognize generic Swift classes 때문 붙어있어 스토리 보드에서는 사용할 수 없습니다.

+0

이 정말 바보입니다 ...하지만 당신이 빈 프로토콜을 확인한 다음 할 경우 ViewModelContainer''에 부합하는 모든 종류의 당신에게 다음, 해당 프로토콜을 준수 이 문제에 대해 부딪히지 않고 해당 프로토콜에 대한 적합성을 확인하십시오. – BallpointBen

+0

진짜 질문은 왜'container'가'ViewModelContainer'를 따르는 타입으로 정적으로 타입 화되지 않았을까요? 당신은 잘 유형 지우개를 찾고 있을지도 모른다. – Hamish

+0

왜'ViewModelType'을 프로토콜로 만들지 않겠습니까? – dichen

답변

0

그것은 내가 (내가 혼동을 피하기 위해 내 이전 게시물을 삭제) 예상보다 난이도했지만, 난이 당신을 위해 일한다고 생각 :

protocol ViewModelContainerVC 
{ 
    mutating func setModel(_ :Any) 
} 

protocol ViewModelContainer:class,ViewModelContainerVC 
{ 
    associatedtype ViewModelType 
    var viewModel: ViewModelType! { get set } 
} 

extension ViewModelContainer 
{ 
    mutating func setModel(_ model:Any) 
    { if model is ViewModelType { viewModel = model as! ViewModelType } } 
} 

그런 다음 타입 캐스팅에 대한 ViewModelContainerVC을 사용할 수 있으며 할당 :

if let container = container as? ViewModelContainerVC 
{ 
    container.setModel(model) 
} 

나중에 참조 [편집] 여기 형의 호환성을 위해 BOOL 반환과 같은 일이 :

protocol ViewModelContainerVC 
{ 
    @discardableResult mutating func setModel(_ :Any) -> Bool 
} 

extension ViewModelContainer 
{ 
    @discardableResult mutating func setModel(_ model:Any) -> Bool 
    { 
     if let validModel = model as? ViewModelType 
     { viewModel = validModel; return true } 
     return false 
    } 
} 
결합 된 상태를 수

:

if var container = container as? ViewModelContainerVC, 
    container.setModel(model) 
{ ... } 
+0

좋은 해결 방법입니다. 그러나'if let '이나'as as'대신에'is '와'as!'를 왜 사용합니까? – redent84

+0

특별한 이유가 없기 때문에 나는 그 의도를 더 잘 전달했다고 느꼈다. –

+0

이것은 매우 유쾌한 것처럼 보입니다 : 잘못된 타입으로 호출했을 때'setModel' 메소드가 자동으로 실패하지만 컴파일러는 도움이되지 않습니다. 어떤 타입의 인수로든'ViewModelContainer'에서 호출 할 수 있습니다. –

0

여기 associatedtype ViewModelType을 프로토콜로 변경하는 아이디어입니다.

protocol ViewModelProtocol { 
} 

protocol ViewModelContainer { 

    var viewModel: ViewModelProtocol? { get set } 
} 

class MediaPlaySelectionViewModel: ViewModelProtocol { 

    var title: String? 
    func play() { 
     print("playing") 
    } 
} 

class SearchResultsViewModel: ViewModelProtocol { 

    var results: [String]? 
} 

class MediaPlaySelectionViewController: UIViewController, ViewModelContainer { 

    var viewModel: ViewModelProtocol? 

    // So the view itself know which kind of vm it wants. 
    var myViewModel: MediaPlaySelectionViewModel? { 
     return viewModel as? MediaPlaySelectionViewModel 
    } 

    override func viewWillAppear(_ animated: Bool) { 
     print(myViewModel?.title ?? "Undefined") 
    } 
} 

class SearchResultsViewController: UIViewController, ViewModelContainer { 

    var viewModel: ViewModelProtocol? 

    // So the view itself know which kind of vm it wants. 
    var myViewModel: SearchResultsViewModel? { 
     return viewModel as? SearchResultsViewModel 
    } 

    override func viewWillAppear(_ animated: Bool) { 
     print(myViewModel?.results?.joined(separator: ", ") ?? "No Result") 
    } 
} 

class MenuViewController: UITableViewController { 

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 

     // NOTE: Swift doesn't allow me to use 'let' here 
     if var container = segue.destination as? ViewModelContainer, let cell = sender as? UITableViewCell, let vm = viewModel(for: cell) { 
      container.viewModel = vm 
     } 
    } 

    // NOTE: One difficulty here, how could you decide which ViewModel to prepare? I guess you need a Factory. 
    func viewModel(for cell: UITableViewCell) -> ViewModelProtocol! { 

     if let index = tableView.indexPath(for: cell) { 

      if index.item == 0 { 

       let vm = MediaPlaySelectionViewModel() 
       vm.title = "My Video" 

       return vm 
      } 
      else if index.item == 1 { 

       let vm = SearchResultsViewModel() 
       vm.results = ["Apple", "Banana"] 

       return vm 
      } 
     } 

     return nil 
    } 
} 
+1

로 업데이트 글쎄,보기 모델 **과 ** 형태 안전성을 잃어 버리는 것보다 훨씬 더 자세한 표시가 아닌'준비 '를 좀 더 자세하게 선호합니다. – redent84