Protocols/面向协议编程, DependencyInjection/依赖式注入 的使用

1. Protocols 定义实现协议,面向协议编码

1.1 创建面向协议实例 ProtocolsBootcamp.swift

Swift 复制代码
import SwiftUI

/// 颜色样式协议
protocol ColorThemeProtocol {
    var primary: Color { get }
    var secondary: Color { get }
    var tertiary: Color { get }
}

struct DefaultColorTheme: ColorThemeProtocol {
    let primary: Color   = .blue
    let secondary: Color = .white
    let tertiary: Color  = .gray
}

struct AlternativeColorTheme: ColorThemeProtocol {
    let primary: Color   = .red
    let secondary: Color = .white
    let tertiary: Color  = .orange
}

struct AnotherColorTheme: ColorThemeProtocol{
    var primary: Color  = .blue
    var secondary: Color = .red
    var tertiary: Color  = .purple
}

/// 定义按钮文字协议
protocol ButtonTextProtocol{
    var buttonText: String { get }
}

protocol ButtonPressedProtocol{
    func buttonPressed()
}

protocol ButtonDataSourceProtocol: ButtonTextProtocol, ButtonPressedProtocol{
}

class DefaultDataSource: ButtonDataSourceProtocol{
    var buttonText: String = "Protocols are awesome!"
    
    func buttonPressed(){
        print("Button was pressed!")
    }
}

class AlternativeDataSource: ButtonTextProtocol{
    var buttonText: String = "Protocols are lame."
}

/// 面向协议
struct ProtocolsBootcamp: View {
    let colorTheme: ColorThemeProtocol
    let dataSource: ButtonDataSourceProtocol
    
    var body: some View {
        ZStack {
            colorTheme.tertiary
                .ignoresSafeArea()
            Text(dataSource.buttonText)
                .font(.headline)
                .foregroundColor(colorTheme.secondary)
                .padding()
                .background(colorTheme.primary)
                .cornerRadius(10)
                .onTapGesture {
                    dataSource.buttonPressed()
                }
        }
    }
}

struct ProtocolsBootcamp_Previews: PreviewProvider {
    static var previews: some View {
        // DefaultColorTheme / AlternativeColorTheme / AnotherColorTheme
        ProtocolsBootcamp(colorTheme: DefaultColorTheme(), dataSource: DefaultDataSource())
    }
}

1.2 效果图:

2. DependencyInjection 依赖式注入

2.1 创建依赖式注入的实例 DependencyInjectionBootcamp.swift

Swift 复制代码
import SwiftUI
import Combine

// Problems with singletons
// 1. Singleton's are GLOBAL      单例模式是全局的
// 2. Can't customize the init!   不能自定义初始化
// 3. Can't swap out dependencies 不能交换式依赖
struct PostsMode: Identifiable, Codable{
    let userId: Int
    let id: Int
    let title: String
    let body: String
}

/// 定义协议 数据服务
protocol DataServiceProtocol {
    /// 获取数据
    func getData() -> AnyPublisher<[PostsMode], Error>
}

/// 生产者数据服务
class ProductionDataService: DataServiceProtocol{
    /// 单例 Singleton
   // static let instance = ProductionDataService()
    
    let url: URL
    
    init(url: URL) {
        self.url = url
    }
    
    func getData() -> AnyPublisher<[PostsMode], Error>{
        URLSession.shared.dataTaskPublisher(for: url)
            .map({$0.data})
            .decode(type: [PostsMode].self, decoder: JSONDecoder())
            .receive(on: DispatchQueue.main)
            .eraseToAnyPublisher()
    }
}

/// 模拟请求服务器返回数据
class MockDataService: DataServiceProtocol{
    let testData: [PostsMode]
    
    init(data: [PostsMode]? ) {
        self.testData = data ?? [
            PostsMode(userId: 1, id: 1, title: "One", body: "One"),
            PostsMode(userId: 2, id: 2, title: "Two", body: "Two"),
            PostsMode(userId: 3, id: 3, title: "Three", body: "Three")
        ]
    }
    
    func getData() -> AnyPublisher<[PostsMode], Error> {
        Just(testData)
            .tryMap({ $0 })
            .eraseToAnyPublisher()
    }
}

/// 依赖试
class Dependencies {
    let dataService: DataServiceProtocol
    
    init(dataService: DataServiceProtocol) {
        self.dataService = dataService
    }
}

/// ViewModel
class DependencyInjectionViewModel: ObservableObject{
    @Published var dataArray: [PostsMode] = []
    var cancellables =  Set<AnyCancellable>()
    let dataService: DataServiceProtocol
    
    init(dataService: DataServiceProtocol) {
        self.dataService = dataService
        loadPosts()
    }

    private func loadPosts(){
        dataService.getData()
            .sink { _ in
                
            } receiveValue: {[weak self] returnedPosts in
                self?.dataArray = returnedPosts
            }
            .store(in: &cancellables)
    }
}

/// 依赖注入
struct DependencyInjectionBootcamp: View {
    @StateObject private var vm: DependencyInjectionViewModel
    
    init(dataService: DataServiceProtocol){
        _vm = StateObject(wrappedValue: DependencyInjectionViewModel(dataService: dataService))
    }
    
    var body: some View {
        ScrollView {
            VStack {
                ForEach(vm.dataArray) { post in
                    Text(post.title)
                    Divider()
                }
            }
        }
    }
}

struct DependencyInjectionBootcamp_Previews: PreviewProvider {
    // static let dataService = ProductionDataService(url: URL(string: "https://jsonplaceholder.typicode.com/posts")!)
    static let dataService = MockDataService(data: [
        PostsMode(userId: 12, id: 12, title: "test", body: "test"),
        PostsMode(userId: 123, id: 123, title: "123", body: "123")
    ])
    
    static var previews: some View {
        DependencyInjectionBootcamp(dataService: dataService)
    }
}

2.2 效果图:

相关推荐
HarderCoder37 分钟前
我们真的需要 typealias 吗?——一次 Swift 抽象成本的深度剖析
swift
★YUI★1 小时前
学习游戏制作记录(制作系统与物品掉落系统)8.16
学习·游戏·ui·unity·c#
HarderCoder1 小时前
ByAI-Swift 6 全览:一份面向实战开发者的新特性速查手册
swift
百锦再2 小时前
一文精通 Swagger 在 .NET 中的全方位配置与应用
后端·ui·.net·接口·配置·swagger·访问
HarderCoder2 小时前
Swift 中 let 与 var 的真正区别:不仅关乎“可变”与否
swift
HarderCoder3 小时前
深入理解 Swift 6.2 并发:从默认隔离到@concurrent 的完整指南
swift
2501_916007473 小时前
iOS App 上架实战 从内测到应用商店发布的全周期流程解析
android·ios·小程序·https·uni-app·iphone·webview
wjm04100612 小时前
ios八股文 -- Objective-c
开发语言·ios·objective-c
麦兜*21 小时前
Swift + Xcode 开发环境搭建终极指南
开发语言·ios·swiftui·xcode·swift·苹果vision pro·swift5.6.3
CodeCraft Studio1 天前
在 Python 中操作 Excel 文件的高效方案 —— Aspose.Cells for Python
python·ui·excel·报表·aspose·aspose.cells