SwiftUI ile Dependency Injection

Dependency Injection, yazılım geliştirme süreçlerinde bağımlılıkları daha iyi yönetmek, test edilebilir ve esnek bir kod oluşturmak için kullanılan bir tekniktir. SwiftUI’da Dependency Injection kullanımını açıklamak için gerçek hayat senaryolarından bir örnek verelim.

Örneğin, bir uygulama geliştiriyorsanız ve HTTP istekleri yapmanız gerekiyorsa, URLSession sınıfını veya Alamofire kütüphanesini kullanmanız gerekebilir. Dependency Injection kullanarak, bu bağımlılıkları uygulamanın diğer bileşenlerine enjekte edebilirsiniz. Bu, bu bağımlılıkların uygulama içinde daha kolay değiştirilebilir ve test edilebilir hale gelmesini sağlar.

Önce, bir URLSession kullanarak bir NetworkManager oluşturacağız. Daha sonra, bu NetworkManager’ı ViewModel’de veya başka bir yerde kullanabiliriz. Ardından, aynı şeyi Alamofire ile yapacağız.

// Dependency Protocol
protocol NetworkService {
    func fetchData(from url: URL, completion: @escaping (Data?, Error?) -> Void)
}

URLSession Servisi:


// URLSession Implementation
class URLSessionNetworkService: NetworkService {
    func fetchData(from url: URL, completion: @escaping (Data?, Error?) -> Void)
        URLSession.shared.dataTask(with: url) { data, _, error in
            completion(data, error)
        }.resume()
    }
}

Alamofire Servisi :

// Alamofire Implementation
class AlamofireNetworkService: NetworkService {
    func fetchData(from url: URL, completion: @escaping (Data?, Error?) -> Void) {
        AF.request(url).responseData { response in
            switch response.result {
            case .success(let data):
                completion(data, nil)
            case .failure(let error):
                completion(nil, error)
            }
        }
    }
}

View Model

class ViewModel: ObservableObject {
    @Published var data: Data?
    @Published var error: Error?
    
    private let networkService: NetworkService

    init(networkService: NetworkService) {
        self.networkService = networkService
        fetchData()
    }
    
    func fetchData() {
        guard let url = URL(string: "https://example.com") else { return }
        networkService.fetchData(from: url) { [weak self] data, error in
            DispatchQueue.main.async {
                self?.data = data
                self?.error = error
            }
        }
    }
}

Dependency Injection

struct ContentView: View {
    @StateObject var viewModel: ViewModel

    init() {
        let networkService: NetworkService = URLSessionNetworkService() // veya AlamofireNetworkService()
        let viewModel = ViewModel(networkService: networkService)
        _viewModel = StateObject(wrappedValue: viewModel)
    }

    var body: some View {
        Text("Data: \(String(data: viewModel.data ?? Data(), encoding: .utf8) ?? "Veri Yok!")")
            .onAppear {
                viewModel.fetchData()
            }
    }
}

Bu örnekte, NetworkManager sınıfı, URLSession veya Alamofire gibi ağ işlemlerini yapan sınıfların üzerine inşa edilmiştir. Daha sonra bu NetworkManager sınıfını ViewModel içinde veya başka bir yerde kullanabilirsiniz.

Not: _viewModel = StateObject(wrappedValue: viewModel)

_viewModel adında bir @StateObject özelliği tanımlanıyor ve bu özellik viewModel adındaki bir ViewModel örneği ile başlatılıyor. Bu, ViewModel’inizin ömrü boyunca aynı örneği kullanmasını sağlar ve bu nesnenin otomatik olarak SwiftUI tarafından yönetilmesini sağlar. Yani, bu özellik SwiftUI tarafından otomatik olarak yönetilen bir ViewModel referansıdır ve SwiftUI’nin ViewModel’i değiştirmesi gerektiğinde otomatik olarak güncellenir.

Yorum yapın