프로그래밍/Swift

UserDefaults, FileManager, CoreData

시르베어 2025. 3. 6. 16:34

UserDefaults

UserDefaults.standard.set(_ value: Any?, forKey: String)

  • 데이터를 저장, value가 Any? 이므로 원하는 데이터 아무거나 가능 UserDefaults.standard.불러올타입(forKey: String)
  • 불러올 타입에 string, integer, bool 등 기본적인 타입은 대부분 가능
  • 불러올 타입에 data, array 등은 중간 캐스팅 과정을 걸치거나 data로 받은 뒤 JSONDecoder().decode를 통해서 값을 변환시켜야한다.
// 데이터 저장
func saveData() {
	UserDefaults.standard.set("UIKit 강의", forKey: "courseName")
	print("데이터 저장 완료")
}
// 데이터 불러오기
func loadData() {
	let courseName = UserDefaults.standard.string(forKey: "courseName") ?? "데이터 없음"
	print("불러온 데이터: \\\\(courseName)")
}

FileManager

  • JSON, 이미지, 동영상과 같은 파일을 저장하는 데 사용
  • 데이터 구조를 직접 설계하고 관리해야 함
struct Note: Codable {
	var title: String
	var content: String
}
let fileName: String = "notes.json"

func saveNote() {
	// 저장할 파일 생성
	let note = Note(title: "iOS 개발", content: "FileManager 예제 학습 중")
	// 데이터 저장을 위해 파일을 인코딩 - 데이터화
	if let data = try? JSONEncoder().encode(note) {
		// 디렉토리 생성
		let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
		// 디렉토리에 파일 경로 추가
		let fileURL = documentDirectory.appendingPathComponent(fileName)
		do {
			// 파일 경로에 데이터화한 데이터를 작성
			try data.write(to: fileURL)
			print("노트 저장 성공: \\\\(fileURL)")
		}catch {
			print("노트 저장 실패: \\\\(error)")
		}
	}
}

func loadNote() {
	// 디렉토리 생성
	let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
	// 디렉토리에 파일 경로 추가 - 해당 경로를 출력해서 실제로 가보면 파일이 있음
	let fileURL = documentDirectory.appendingPathComponent(fileName)
	// 파일 경로의 파일에서 데이터를 불러옴
	if let data = try? Data(contentsOf: fileURL) {
		// 데이터를 디코딩 - 원하는 타입에 대입
		// 만약 불러온 값을 Note 배열에 넣고 싶다면?? .decode([Note].self, from: data)
		if let note = try? JSONDecoder().decode(Note.self, from: data) {
			print("불러온 노트: \\\\(note.title), \\\\(note.content)")
		}
	}
}

Core Data

  • 데이터를 저장하고 관리하기 위한 프레임워크
  • SQLite 기반이지만, 직관적인 API를 제공
  • Entity, VO, DTO의 구조는 같다고 보면되지만, 사용목적(역할)에 따라서 명칭이 달라진다.
  • try save() : context를 저장
  • try fetch() : request에 predicate 를 같이 보낼경우 기준에 해당하는 객체 context에 반환
  • "Core Data <--> Context <--> 변수" 로 이해

Q) saveData에서 context.save()를 안하면 어떻게되나!?

A) fetch에서 context의 값을 불러오기 때문에 당장은 사용이 가능하지만 어플을 껐다가 키면 저장이 안되어있기 때문에 데이터가 날라감 (항상 context.save 를 해주자!)

 

AppDelegate에서 컨테이너 설정을 해줘야함

lazy var persistentContainer: NSPersistentContainer = {
	let container = NSPersistentContainer(name: ".xcdatamodeld 파일 이름")
	container.loadPersistentStores{ storeDescription, error in
		if let error = error as NSError? {
			fatalError("Unresolved error \\\\(error), \\\\(error.userInfo)")
		}
	}
    return container
}()

func saveContext() {
	let context = persistentContainer.viewContext
	if context.hasChanges {
		do {
			try context.save()
		}catch {
			print(error)
		}
	}
}

 

데이터 저장하기

func saveData(title: String, content: String) {
	guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
	let context = appDelegate.persistentContainer.viewContext
	// context에 빈 Note Entity를 생성
	let note = NSEntityDescription.insertNewObject(forEntityName: "Note", into: context)
	// 빈 Note Entity 값을 지정
	note.setValue(title, forKey: "title")
	note.setValue(content, forKey: "content")
	note.setValue(Date(), forKey: "createdDate")
	do {
		try context.save()
		print("데이터 저장 성공!")
	} catch {
		print("❌ 데이터 저장 실패: \\\\(error)")
	}
}

 

데이터 불러오기

func fetchData() {
	guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
	let context = appDelegate.persistentContainer.viewContext
	// 요청할 Entity
	let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Note")
	do {
		// 해당 Entity를 배열로 불러옴
		let notes = try context.fetch(fetchRequest)
		for note in notes {
			// 각 애트리뷰트에 접근
			let title = note.value(forKey: "title") as? String ?? ""
			let content = note.value(forKey: "content") as? String ?? ""
			print("📝 불러온 노트: \\\\(title) - \\\\(content)")
		}
	}catch {
		print(error)
	}
}

 

데이터 삭제하기

func deleteData(title: String) {
	guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
	let context = appDelegate.persistentContainer.viewContext
	// 요청할 Entity
	let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Note")
	// Entity의 조건 추가
	fetchRequest.predicate = NSPredicate(format: "title == %@", title)
	do {
		let notes = try context.fetch(fetchRequest)
		for note in notes {
			// context에서 값을 삭제
			context.delete(note)
		}
		// 변경된 context를 저장
		try context.save()
	}catch {
		print(error)
	}
}