SwiftUI 5.5를 사용하여 아키텍처 청소
21080 단어 programmingiosswiftuiswift
프로젝트의 폴더/그룹 구조는 다음과 같습니다.
├── Core
├── Data
├── Domain
└── Presentation
역층부터 시작합시다.이 층은 프로젝트/응용 프로그램의 기능을 설명합니다.많은 응용 프로그램의 구축과 구조 방식은 폴더 구조만 보고 응용 프로그램의 기능을 이해할 수 없다는 것을 설명해 드리겠습니다.가옥을 비교하는 건축을 사용하면 건축의 평면도와 입면도를 살펴보면 건축의 외관과 기능을 신속하게 확정할 수 있다
마찬가지로, 우리 프로젝트의 역층은 응용 프로그램의 기능을 지정하고 설명해야 한다.이 폴더에서 모델, 메모리 라이브러리 인터페이스, 용례를 보존할 것입니다.
├── Core
├── Data
├── Presentation
└── Domain
├── Model
│ ├── Todo.swift
│ └── User.swift
├── Repository
│ ├── TodoRepository.swift
│ └── UserRepository.swift
└── UseCase
├── Todo
│ ├── GetTodos.swift
│ ├── GetTodo.swift
│ ├── DeleteTodo.swift
│ ├── UpdateTodo.swift
│ └── CreateTodo.swift
└── User
├── GetUsers.swift
├── GetUser.swift
├── DeleteUser.swift
├── UpdateUser.swift
└── CreateUser.swift
모델: 모델은 일반적으로 문제와 관련된 진실한 대상을 나타낸다.이 폴더에서, 우리는 보통 클래스를 보류해서 대상을 표시합니다.e, g. 대기사항, 사용자 등
Repository: 모든 저장소 인터페이스의 컨테이너입니다.라이브러리는 모델과 관련된 모든 작업을 저장하는 중심 위치입니다.이 예에서는 Todo 저장소 인터페이스에서 저장소 방법에 대해 설명합니다.실제 저장소는 데이터 층에 저장됩니다.
용례: 프로그램의 모든 기능을 보여 주는 용기입니다.e, g 수령, 삭제, 생성, 업데이트
├── Core
├── Data
├── Domain
└── Presentation
└── Todo
└── TodoList
├── TodoListViewModel.swift
└── TodoListView.swift
데이터 계층은 외부 종속과 관련된 모든 코드를 유지하여 이러한 코드가 어떻게 구현되는지 확인합니다.├── Core
├── Domain
├── Presentation
├── Data
├── Repository
│ ├── TodoRepositoryImpl.swift
│ ├── TodoAPIDataSourceImpl.swift
│ └── TodoDBDataSourceImpl.swift
└── DataSource
├── API
│ ├── TodoAPIDataSource.swift
│ └── Entity
│ ├── TodoAPIEntity.swift
│ └── UserAPIEntity.swift
└── DB
├── TodoDBDataSource.swift
└── Entity
├── TodoDBEntity.swift
└── UserDBEntity.swift
저장소: 저장소 구현
데이터 원본: 모든 데이터 원본 인터페이스와 실체.실체는 데이터베이스에 기록으로 저장된 역 대상의 단일 실례를 나타낸다.DB 테이블 또는 API 끝점에서 열로 표시되는 속성이 있습니다.우리는 데이터가 외부 데이터 원본에서 어떻게 모델링되는지 제어할 수 없기 때문에 이러한 실체는 실현 과정에서 실체에서 역 모델로 비추어야 한다
우리의 첫 번째 임무는 항상 역 모델과 데이터 실체로부터 시작된다
struct Todo: Identifiable {
let id: Int
let title: String
let isCompleted: Bool
}
목록 보기에 이 항목들을 표시하려면 식별성이 필요합니다.이제 토도 실체를 만들어 보도록 하겠습니다.
struct TodoEntity: Codable {
let id: Int
let title: String
let completed: Bool
}
이제 TodoDatasource에 대한 인터페이스 (프로토콜) 를 작성합시다.protocol TodoDataSource{
func getTodos() async throws -> [Todo]
}
Dell은 ToDoapImpl이라는 이름의 프로토콜을 작성할 충분한 리소스를 보유하고 있습니다.enum APIServiceError: Error{
case badUrl, requestError, decodingError, statusNotOK
}
struct TodoAPIImpl: TodoDataSource{
func getTodos() async throws -> [Todo] {
guard let url = URL(string: "\(Constants.BASE_URL)/todos") else{
throw APIServiceError.badUrl
}
guard let (data, response) = try? await URLSession.shared.data(from: url) else{
throw APIServiceError.requestError
}
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else{
throw APIServiceError.statusNotOK
}
guard let result = try? JSONDecoder().decode([TodoEntity].self, from: data) else {
throw APIServiceError.decodingError
}
return result.map({ todoEntity in
Todo(
id: todoEntity.id,
title: todoEntity.title,
isCompleted: todoEntity.completed
)
})
}
}
주의: 이 저장소의 getTodos 함수는 처리해야 할 사항 목록을 되돌려줍니다.따라서 TodoEntity->Todo:ToDoRespository Impl을 작성하기 전에 도메인 계층에서 프로토콜을 작성합니다.
protocol TodoRepository{
func getTodos() async throws -> [Todo]
}
struct TodoRepositoryImpl: TodoRepository{
var api: TodoAPI
func getTodos() async throws -> [Todo] {
let _todos = try await api.getTodos()
return _todos
}
}
이제 Todo 저장소가 생겨서 GetTodos 용례를 작성할 수 있습니다enum UseCaseError: Error{
case networkError, decodingError
}
struct GetTodosUseCase{
var repo: TodoRepository
func execute() async -> Result<[Todo], UseCaseError>{
do{
let todos = try await repo.getTodos()
return .success(todos)
}catch(let error){
switch(error){
case APIServiceError.decodingError:
return .failure(.decodingError)
default:
return .failure(.networkError)
}
}
}
}
그리고 우리는 프레젠테이션 원고의 보기 모형과 보기를 작성할 수 있다@MainActor
class TodoListViewModel: ObservableObject {
var getTodosUseCase = GetTodosUseCase(repo: TodoRepositoryImpl(api: TodoAPIImpl()))
@Published var todos: [Todo] = []
@Published var errorMessage = ""
@Published var hasError = false
func getTodos() async {
errorMessage = ""
let result = await getTodosUseCase.execute()
switch result{
case .success(let todos):
self.todos = todos
case .failure(let error):
self.todos = []
errorMessage = error.localizedDescription
hasError = true
}
}
}
주의: 보기 모델 클래스에 @MainActor 속성을 사용합니다. 이 함수를 주 라인에서 실행해야 하기 때문입니다. 주 라인은 하나의 예제 참여자이며, 실행기는 주 스케줄링 대기열에 해당합니다.struct TodoListView: View {
@StateObject var vm = TodoListViewModel()
fileprivate func listRow(_ todo: Todo) -> some View {
HStack{
Image(systemName: todo.isCompleted ? "checkmark.circle": "circle")
.foregroundColor(todo.isCompleted ? .green : .red)
Text("\(todo.title)")
}
}
fileprivate func TodoList() -> some View {
List {
ForEach(vm.todos){ item in
listRow(item)
}
}
.navigationTitle("Todo List")
.task {
await vm.getTodos()
}
.alert("Error", isPresented: $vm.hasError) {
} message: {
Text(vm.errorMessage)
}
}
var body: some View {
TodoList()
}
}
따라서 다음과 같이 요약할 수 있습니다.
Reference
이 문제에 관하여(SwiftUI 5.5를 사용하여 아키텍처 청소), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/paulallies/clean-architecture-in-the-flavour-of-swiftui-55-jo2텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)