Swift: словарь со значением нескольких типов - PullRequest
0 голосов
/ 10 марта 2020

Мне трудно разобраться с приведенным ниже кодом, значение в dict sectionMoviesBundle = [HomeSection: [T]] может быть MovieViewModel или ActorViewModel, два из которых являются типом структуры.

Так, в общем, как мне справиться с этим dict [String: [typeA or typeB...]], используя generi c или AnyObject, как nowPlaying.results.map(MovieViewModel.init) as AnyObject? И как это реализовать в коде?

import SwiftUI
import Combine


class MovieListViewModel: ObservableObject {
    private var webService = WebService()
    private var cancellableSet: Set<AnyCancellable> = []

    @Published var sectionMoviesBundle = [HomeSection: [T]]() // Don't know how to deal with it now=.=!

    func getSectionMoviesBundle() {
        webService.getSectionsPublisher()
            .receive(on: DispatchQueue.main)
            .sink(receiveCompletion: { status in
                switch status {
                case .finished:
                    break
                case .failure(let error):
                    print("ERROR: \(error)")
                    break
                }
            }) { (nowPlaying, popular, upComing, topActor) in
                self.sectionMoviesBundle[.NowPlaying] = nowPlaying.results.map(MovieViewModel.init)
                self.sectionMoviesBundle[.Popular] = popular.results.map(MovieViewModel.init)
                self.sectionMoviesBundle[.Upcoming] = upComing.results.map(MovieViewModel.init) 
                self.sectionMoviesBundle[.TopActor] = topActor.results.map(ActorViewModel.init) 
        }.store(in: &self.cancellableSet)
    }
}

Ответы [ 3 ]

0 голосов
/ 10 марта 2020

Один из многих подходов, которые вы можете использовать:

enum MovieSectionType {
    case actor, movie
}
protocol MovieSectionViewModelProtocol {
    var sectionType: MovieSectionType { get }
    var name: String { get set }
}
struct MovieViewModel: MovieSectionViewModelProtocol{

    var sectionType: MovieSectionType = .movie
    var name: String
    var title: String

}
struct ActorViewModel: MovieSectionViewModelProtocol {
    var sectionType: MovieSectionType = .actor
    var name: String
    var birthday: Date

}

class MovieListViewModel: ObservableObject {
    private var webService = WebService()
    private var cancellableSet: Set<AnyCancellable> = []

    @Published var sectionMoviesBundle = [HomeSection: [MovieSectionViewModelProtocol]]() // Don't know how to deal with it now=.=!

    func getSectionMoviesBundle() {
        self.sectionMoviesBundle[.Upcoming] = [MovieViewModel(name: "Movie", title: "Movie Title")]
        self.sectionMoviesBundle[.TopActor] = [ActorViewModel(name: "Actor", birthday: Date())]

        let item = self.sectionMoviesBundle[.Upcoming]!.first!
        switch item.sectionType {
        case .actor:
            guard let actor = item as? ActorViewModel else {
                return
            }
            print(actor.birthday)
            break
        case .movie:
            guard let movie = item as? MovieViewModel else {
                return
            }
            print(movie.title)
            break
        }

    }
}
0 голосов
/ 11 марта 2020

Вы можете использовать «тип суммы», который в Swift представляет собой enum:

enum SectionContent {
    case actors([ActorViewModel])
    case movies([MovieViewModel])
}

@Published var sectionMoviesBundle = [HomeSection: SectionContent]()

func getSectionMoviesBundle() {
    webService.getSectionsPublisher()
        .receive(on: DispatchQueue.main)
        .sink(receiveCompletion: { status in
            switch status {
            case .finished:
                break
            case .failure(let error):
                print("ERROR: \(error)")
                break
            }
        }) { (nowPlaying, popular, upComing, topActor) in
            self.sectionMoviesBundle[.NowPlaying] = .movies(nowPlaying.results.map(MovieViewModel.init))
            self.sectionMoviesBundle[.Popular] = .movies(popular.results.map(MovieViewModel.init))
            self.sectionMoviesBundle[.Upcoming] = .movies(upComing.results.map(MovieViewModel.init))
            self.sectionMoviesBundle[.TopActor] = .actors(topActor.results.map(ActorViewModel.init))
    }.store(in: &self.cancellableSet)
}
0 голосов
/ 10 марта 2020

Альтернатива, которую, я думаю, вы можете попробовать

  1. [String: [Any]]

  2. Создать протокол и внедрить его для всех Структура, которую вы хотите использовать в словаре, и использовать [String: [someProtocol]]

, чтобы вставить его в словарь, вы можете использовать свой текущий код

...