회사에서 서비스하는 앱이란건 보통 서버에서 데이터를 저장, 관리하기에 앱 단독으로 데이터 저장은 거의없었다.
개인 로그인 기록이나 편의성을 위한점때문에 userdefaults같은걸 써서 저장하거나 따로 파일을 만들어 저장하는게 편하기에 굳이 새로운 라이브러리를 넣어서 무겁게 돌릴필요가 없었다
그래도 방법은 있으니 혼자서 공부삼아 만들어보는 예제에서는 sqlite를 쓰거나 firebase를 로컬로쓰거나(듣기만했지 만들어보지도 찾아보지도 않았다.) 아니면 애플에서 제공하는 프레임워크인 Coredata를쓰거나! 한다.
그렇게 이글은 애플에서 제공하는 데이터 저장용 프레임워크인 coredata를 uikit이아닌 swiftui로 만들어 붙이는걸 공부하는 글이다.
4월달 내로 만들어서 내이름으로 처음 등록하려던 앱계획이 있었다. 하지만 정신상태가 흔들리는 일들을 계속 맛보고있는 와중이라 여러번 의욕이 꺽이면서 아직도 한참 멀었다 그앱은 자금사정상 서버를 이용한 기능은 빼고 로컬에서만 돌아가도록할건데 여기서 데이터가 영속적으로 유지해야하는 기능이 존재한다.
데이터가 영속적으로 존재하려면 위에서 쓴 서버를 이용하거나 텍스트파일로 쓰거나, 로컬db용 라이브러리를 쓰거나해야하는데 자금문제로 서버는 무리고 텍스트파일로 쓰기에는 뭔가 공부도 안될거같아 로컬db로 목표, 그리고 이왕이면 안해본걸 잡아보고싶어서 coredata로 하기로 마음먹었다.
기억이 가물가물하지만 보통 로컬디비가 보통 시작이 이랬을거다.
1. 디비용 클래스 초기화
2. 초기화시 디비 파일이 없다면 생성 및 스키마 뭐 그런 초기값들 설정
3. 디비 파일이 있다면 로드준비들
4. 해당 기능들을 래핑한 컨트롤러의 생성
5. 이제 컨트롤러를 이용해서 필요할때 백그라운드 스레드로 돌리면서 쿼리를 날리며 ui업데이트
이런식이였을거다.
프레임워크를 그냥 제공해주기에 별다른설치나 그런 고민없이 간단히 쓸수있을거라 생각하고 자료좀 찾아봤는데 뭔가 말이많다...
처음 아이폰개발 배웠을때도 이랬었나 고민하게되는 뭔가뭔가들이라 쉽게 손이 안가 그냥 튜토리얼을 따라하며 감을 잡아야겠다 싶어 따라했다
그렇게 대충 배운 내용으로는
아래와같다
1. 프로젝트 내에 엔티티 정의용 모델파일을 생성한다 - xcdatamodeld 라는 확장자를 가진 파일
2. 정의용 모델파일에서 스키마를 설정 - 서버용의 dbms에서 gui로 편하게 만드는 엔티티라는 느낌이였다
3. 컨트롤러 생성, 컨트롤러지만 컨트롤 기능정의가 아니라 단순 모델파일 로드 - 컨테이너생성
4. enviroment modifier로 managedObjectContext 키값에 만들어둔 컨트롤러에서 컨테이너의 뷰 컨텍스트 지정
ContentView()
.environment(\.managedObjectContext, presistenceController.contianer.viewContext)
5. 디비 접근이 필요한곳에서 viewContext 받아주기 + 저장된 값 불러오기
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(entity: Product.entity(), sortDescriptors: [ 값 정렬 ]
private var products: FetchedResults<Product>
뭐 그렇게 읽고
쓸때는 저기 Product라고 만들어준 엔티티를 생성해줘서 위에서 받아온 viewContext를 이용해 save() 메소드를 호출하면된다.
private func addProduct() {
withAnimation {
let product = Product(context: viewContext)
product.name = name
product.quantity = quantity
saveContext()
}
} // addProduct
private func saveContext() {
do {
try viewContext.save()
} catch {
let error = error as NSError
fatalError("An error occurred: \(error)")
}
}// saveContext
참고로 여기서 Product 타입은 엔티티 만드는곳에서 자동으로 생성해서 쓰고있다
이걸 따로 수동으로 만들어서 해줄수도 있음.
수동으로하려면 엔티티 생성해주는곳에서 메뉴얼을 선택해줘야한다. 아래 사진의 Codegen부분이다 Manual과 CategoryExtension이라는게 있던데 카테고리 뭐시기는 아직 안해봤다.
위에서 데이터 Fetch해줄때 그냥 전부 가져왔는데 조건문을 넣어서 불러오는것도 당연히 있다.
예제에서는 task 수정자를 이용해 하도록 안내해줬다
.task {
let fetchRequest: NSFetchRequest<Product> = Product.fetchRequest()
fetchRequest.entity = Product.entity()
fetchRequest.predicate = NSPredicate(format: "name CONTAINS %@", name)
matches = try? viewContext.fetch(fetchRequest)
}
contain연산자를 이용한 name 검색인데 별건 없다
자동으로 만들어준 Product라 그런가 별에 별게 다 미리 지정되어있다 fetchRequest라던가...
사실 이건 내부 들어가보면 별거 없긴한데 자동이라 편하다.
@nonobjc public class func fetchRequest() -> NSFetchRequest<Product> {
return NSFetchRequest<Product>(entityName: "Product")
}
그리고 마지막으로 crud에서 update는 안다룰거고... delete는 뭔가 해준 느낌이 안난다.
offsets.map { products[$0] }.forEach(viewContext.delete)
saveContext()
값을 list로 뿌려줬으니 offset값을 바로 가져올수있고 받아온 offset값에 대응하는 products값에서 delete메소드를 불러준후 save 메소드를 불러주는거로 끝이난다
기존 로컬디비 다루는법에서 다른점은
컨트롤러에서의 해주는게 사용하려는 클래스? 스트럭트? (swiftui는 죄다 구조체로 선언해서 용어적으로 뭘 불러야할지 모르겠다 )
사용하려는곳에서 프로퍼티래퍼를 달아줘서 기능을 사용한다는 점일까?
일단 이론적인 이야기로는
앱 -
영구컨테이너 -
관리 객체 콘텍스트 ~ 관리 객체 ~ 관리 객체 모델 ~ 엔티티 디스크립션 -
영구 저장소 코디네이터
영구 저장소 객체
데이터베이스
이런 레이어들이 쌓여서 서로 부르고 알고 모르니 하는 설명이 뭔가 많다.
예제에서 다루는 부분을 보면 우선 코디네이터 아래단은 전부 프레임워크에 역할을 맡기는거 같고
영구 컨테이너는 컨트롤러에서 생성, 그 생성할 관리 객체단이 xcdatamodeld파일이라는 느낌?
'iOS > swift' 카테고리의 다른 글
[swiftUI]Static method 'buildExpression' requires ~ (0) | 2025.04.22 |
---|---|
UIColor to Color?, 기존 uicolor색상을 swiftui 에서 사용하기 (0) | 2025.04.21 |
background audio play - 5 [SwiftUI로 변경] (0) | 2025.03.26 |
background audio play - 4 [mvvm 패턴] (1) | 2024.11.27 |
background audio play - 3 [제어센터에서의 컨트롤] (5) | 2024.11.10 |