VC와 dataLayer는 비즈니스 로직을 통해 상호작용한다.
각 계층의 책임을 분리하고 코드의 재사용성과 유지보수성을 기대할 수 있다
피치못할 엄청난 자연재해(업데이트 1시간전이라거나?)로인해 crud저장 역할을 하는 manager나 vc에 다른 기능과 한 메서드에 비즈니스 로직까지 때려박게되기도 하는데 이럴 경우, 다른 vc에서 같은 기능의 메서드가 필요할 때 재사용이 어려울 수 있다.
지금 진행중인 프로젝트의 경우 데이터와 관련하여 coredata를 주로 사용하는데
dataLayer는 CRUD 저장소인 DataManager 같은 것이 될 수 있다.
import CoreData
class DataManager {
static let shared = DataManager()
private init() {}
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "MyDataModel")
container.loadPersistentStores { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
}
return container
}()
// Create
func createItem(name: String) -> Item? {
let context = persistentContainer.viewContext
let item = Item(context: context)
item.name = name
item.createdAt = Date()
do {
try context.save()
return item
} catch {
print("Failed to create item: \(error)")
return nil
}
}
// Read
func fetchItems() -> [Item] {
let context = persistentContainer.viewContext
let fetchRequest: NSFetchRequest<Item> = Item.fetchRequest()
do {
return try context.fetch(fetchRequest)
} catch {
print("Failed to fetch items: \(error)")
return []
}
}
// Update
func updateItem(_ item: Item, newName: String) -> Bool {
let context = persistentContainer.viewContext
item.name = newName
do {
try context.save()
return true
} catch {
print("Failed to update item: \(error)")
return false
}
}
// Delete
func deleteItem(_ item: Item) -> Bool {
let context = persistentContainer.viewContext
context.delete(item)
do {
try context.save()
return true
} catch {
print("Failed to delete item: \(error)")
return false
}
}
}
매니저는 싱글톤으로 제작하여 불변성을 확보하고 crud에만 충실하도록 한다
그리고
class BusinessService {
private let dataManager = DataManager.shared
func createNewItem(name: String) -> Bool {
guard !name.isEmpty else { return false }
return dataManager.createItem(name: name) != nil
}
func getAllItems() -> [Item] {
return dataManager.fetchItems()
}
func updateItemName(_ item: Item, newName: String) -> Bool {
guard !newName.isEmpty else { return false }
return dataManager.updateItem(item, newName: newName)
}
func removeItem(_ item: Item) -> Bool {
return dataManager.deleteItem(item)
}
}
비즈니스 로직만을 담는 서비스 모델을 따로 제작하여 이로서 manager와 상호작용한다.
요청 흐름:
VC (View Controller) -> Logic (Business Logic) -> Manager (Data Manager)
응답 흐름:
Manager (Data Manager) -> Logic (Business Logic) -> VC (View Controller)
이렇게 정하므로서 또한 좋은 점은 내 파트가 아닌 부분에 대해서도 어느 파일에 있을지 대충 파악할 수가 있다
만약 DTO (Data Transfer Object)를 도입하면 아키텍처가 VC > DTO > Service > Manager 구조로 확장될 수 있다.
VC (View Controller): 사용자 인터페이스를 관리한다.
DTO (Data Transfer Object): 계층 간 데이터 전송을 위한 객체다.
Service: 비즈니스 로직을 처리한다. (이전의 BusinessLogic과 유사한 역할)
Manager: 데이터 저장소와의 직접적인 상호작용을 담당