Ответ на ваш вопрос
Давайте начнем с примечания, что createMyAction: Action<String, Void>
относится к типу (struct
) с именем Action
, как если бы он был универсальным, но вы не объявили его как таковой и, следовательно, не будете работать.
А чтобы ответить на ваш вопрос о вложенном struct Action
, можно сослаться на его внешние class MyViewModel
- да, вы можете ссылаться на static
свойства, например:
struct Foo {
struct Bar {
let biz = Foo.buz
}
static let buz = "buz"
}
let foobar = Foo.Bar()
print(foobar.biz)
Но вам, вероятно, следует избегать таких циркулярных ссылок. И я опущу любой уродливый хак, который мог бы получить такую циклическую ссылку на нестатические свойства (вероятно, включил бы изменяемые необязательные типы). Это кодовый запах.
Предложение для MVVM
Похоже, вы хотели бы объявить Action
как функцию? Я сам использую этот протокол:
protocol ViewModelType {
associatedtype Input
associatedtype Output
func transform(input: Input) -> Output
}
Первоначально вдохновлено Чистой архитектурой SergDort .
Вы можете подготовить экземпляр input
(содержащий Observable
s) из UIViewController
и вызвать функцию transform
, а затем отобразить Output
преобразования (будучи Observables
s), чтобы обновить GUI.
Итак, в этом коде предполагается, что вы обладаете базовыми знаниями по реактиву . Что касается Observable
s, вы можете выбрать между RxSwift или ReactiveSwift - да, их имена похожи.
Если вы знакомы с Rx, это отличный способ создания красивой архитектуры MVVM с простыми асинхронными обновлениями графического интерфейса. В приведенном ниже примере вы найдете тип Driver
, который задокументирован здесь , но краткое объяснение состоит в том, что вы хотите использовать для ввода из представлений и вход в представлений, так как он обновляет представления в потоке графического интерфейса, и это гарантированно не выдает ошибку.
CleanArchitecture содержит, например, PostsViewModel
final class PostsViewModel: ViewModelType {
struct Input {
let trigger: Driver<Void>
let createPostTrigger: Driver<Void>
let selection: Driver<IndexPath>
}
struct Output {
let fetching: Driver<Bool>
let posts: Driver<[PostItemViewModel]>
let createPost: Driver<Void>
let selectedPost: Driver<Post>
let error: Driver<Error>
}
private let useCase: PostsUseCase
private let navigator: PostsNavigator
init(useCase: PostsUseCase, navigator: PostsNavigator) {
self.useCase = useCase
self.navigator = navigator
}
func transform(input: Input) -> Output {
let activityIndicator = ActivityIndicator()
let errorTracker = ErrorTracker()
let posts = input.trigger.flatMapLatest {
return self.useCase.posts()
.trackActivity(activityIndicator)
.trackError(errorTracker)
.asDriverOnErrorJustComplete()
.map { $0.map { PostItemViewModel(with: $0) } }
}
let fetching = activityIndicator.asDriver()
let errors = errorTracker.asDriver()
let selectedPost = input.selection
.withLatestFrom(posts) { (indexPath, posts) -> Post in
return posts[indexPath.row].post
}
.do(onNext: navigator.toPost)
let createPost = input.createPostTrigger
.do(onNext: navigator.toCreatePost)
return Output(fetching: fetching,
posts: posts,
createPost: createPost,
selectedPost: selectedPost,
error: errors)
}
}