1) ViewController 생명주기
2) 메모리 관리 이해
3) Core Data 와 UserDefaults
4) 네트워크 통신 이해
5) 날씨 앱 만들기
CRUD 개념자체는 익숙하니 후딱 넘어가기...
데이터 CRUD는 네이티브(앱)에서도 일어날 수 있고 서버에서도 일어날 수 있다.
: 앱에서 기기의 디스크에 데이터를 읽고 쓸 수 있게 해주는 프레임워크
Entity
생성
좌측 하단 Add Entity
눌러 빈 Entity
생성, 엔티티 이름 변경
attribute
(속성/열) 추가위 사진 우측 하단의 Add Attribute
눌러 입력하고자 하는 속성, Type 추가
Codegen
선택: Code Generator
의 줄임말로, 엔티티를 어떤 형식의 코드로 생성할 것인지 선택하는 속성
Manual/None
: 엔티티의 서브클래스 자동으로 생성하지 않고 개발자가 클래스 작성Class Definition
: 엔티티 서브클래스 자동생성Category/Extension
: 엔티티 클래스와 함께 extension 위한 파일까지 생성우선 Manual/None
으로 적용
4번까지 세팅해두고, Editor -> Create NSManagedObject Subclass를 누르면
원래 없었던 두 가지 파일이 생성된다.
📞 PhoneBook+CoreDataClass.swift
import Foundation
import CoreData
@objc(PhoneBook)
public class PhoneBook: NSManagedObject {
}
: NSManagedObject
는 Core Data 프레임워크에서 관리되는 객체를 나타내는 기본 클래스로,Core Data 엔티티와의 상호작용을 관리하고 속성 값의 저장 및 검색을 처리한다.
📞 PhoneBook+CoreDataProperties.swift
import Foundation
import CoreData
extension PhoneBook {
@nonobjc public class func fetchRequest() -> NSFetchRequest<PhoneBook> {
return NSFetchRequest<PhoneBook>(entityName: "PhoneBook")
}
@NSManaged public var name: String?
@NSManaged public var phoneNumber: String?
}
extension PhoneBook : Identifiable {
}
@nonobjc
= Objective-C 에서는 동작하지 않고 Swift 에서만 동작하는 메서드임을 명시.fetchRequest()
= PhoneBook 에 대한 여러가지 데이터 검색을 도움.@NSManaged
= CoreData 에 의해 관리되는 객체를 의미.Identifiable
= PhoneBook 타입이 고유하게 식별될 수 있음을 의미.NSPersistantContainer
관리: CoreData에서 데이터 저장하고 관리하는데 필요한 핵심 객체
프로젝트 생성시 CoreData
사용에 체크했기 때문에, Appdelegate.swift
에 이미 NSPersistantContainer를 세팅하는 코드가 존재한다.
그 밑에 saveContext()
메서드도 자동 생성되어 있는데, 데이터의 업데이트가 일어날 때 이를 호출해서 문맥을 저장해줘야 한다.
그럼 이제 직접 써보며 코드 사용법을 알아보자.
코드를 짜기 전에 PhoneBook+CoreDataClass
에 들어가서 다음과 같이 클래스를 세팅한다.
import Foundation
import CoreData
@objc(PhoneBook)
public class PhoneBook: NSManagedObject {
public static let className = "PhoneBook"
public enum Key {
static let name = "name"
static let phoneNumber = "phoneNumber"
}
}
- 자동완성 기능 사용 가능
- 손으로 phoneNumber 라고 타자를 치지 않기 때문에 휴먼 에러가 줄어들음
- 값을 수정해야 할 때 여기서만 고치면 됨
- 성격이 같은 프로퍼티끼리 모아 관리 가능
//shCoreData에 데이터 Create
func createData(name: String, phoneNumber: String) {
guard let entity = NSEntityDescription.entity(forEntityName: PhoneBook.className, in: self.container.viewContext) else {
return
}
let newPhoneBook = NSManagedObject(entity: entity, insertInto: self.container.viewContext)
newPhoneBook.setValue(name, forKey: PhoneBook.Key.name)
newPhoneBook.setValue(phoneNumber, forKey: PhoneBook.Key.phoneNumber)
do {
try self.container.viewContext.save()
print("문맥 저장 성공")
} catch {
print("문맥 저장 실패")
}
}
//shCoreData에서 데이터 Read
func readAllData() {
do {
let phoneBooks = try self.container.viewContext.fetch(PhoneBook.fetchRequest())
for phoneBook in phoneBooks as [NSManagedObject] {
if let name = phoneBook.value(forKey: PhoneBook.Key.name) as? String,
let phoneNumber = phoneBook.value(forKey: PhoneBook.Key.phoneNumber) as? String {
print("이름: \(name), 전화번호: \(phoneNumber)")
}
}
} catch {
print("데이터 읽기 실패")
}
}
//shCoreData에서 데이터 Update
func updateData(currentName: String, updateName: String) {
let fetchRequest = PhoneBook.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "name == %@", currentName)
do {
let result = try self.container.viewContext.fetch(fetchRequest)
for data in result as [NSManagedObject] {
//data 중 name의 값을 updateName으로 update
data.setValue(updateName, forKey: PhoneBook.Key.name)
}
try self.container.viewContext.save()
print("데이터 수정 성공")
} catch {
print("데이터 수정 실패")
}
}
//shCoreData에서 데이터 delete
func deleteData(name: String) {
let fetchRequest = PhoneBook.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "name == %@", name)
do {
let result = try self.container.viewContext.fetch(fetchRequest)
for data in result as [NSManagedObject] {
self.container.viewContext.delete(data)
}
try self.container.viewContext.save()
} catch {
print("데이터 삭제 실패")
}
}
import UIKit
import CoreData
class ViewController: UIViewController {
var container: NSPersistentContainer!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let appDelegate = UIApplication.shared.delegate as! AppDelegate
self.container = appDelegate.persistentContainer
createData(name: "SH", phoneNumber: "010-0000-1111")
updateData(currentName: "SH", updateName: "승희")
deleteData(name: "승희")
readAllData()
}
//shCoreData에서 데이터 Create
//shCoreData에서 데이터 Read
//shCoreData에서 데이터 Update
//shCoreData에서 데이터 delete
}
❗️ 위에서 CoreData는
디스크
에 데이터를 저장한다고 했으므로, 코드를 삭제하고 다시 실행해도 데이터가 남아있다.
: CoreData와 마찬가지로 디스크
에 데이터를 저장할 수 있게 돕는 도구
- CoreData보다 사용성 간단
key
,value
이용해 값을 저장- 대량의 데이터는
CoreData
로, 비교적 단순한 데이터는UserDefault
로 다루는 것이 적절
CoreData같이 엔티티를 만들고 복잡하게 할 필요 없이 간단하다.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//Create
UserDefaults.standard.set("010-0000-0000", forKey: "phoneNumber")
//Read
var phoneNumber = UserDefaults.standard.string(forKey: "phoneNumber")
print("저장된 전화번호: \(phoneNumber)") // optional로 출력됨 (key 일치값 없을수 있으니)
//Update
UserDefaults.standard.set("010-3333-4444", forKey: "phoneNumber")
phoneNumber = UserDefaults.standard.string(forKey: "phoneNumber")
print("저장된 전화번호: \(phoneNumber)")
//Delete
UserDefaults.standard.removeObject(forKey: "phoneNumber")
phoneNumber = UserDefaults.standard.string(forKey: "phoneNumber")
print("전화번호가 남아있는지 확인 \(phoneNumber)")
}
}
UserDefaults.standard.set()
메서드로 Create
, Update
UserDefaults.standard.string(forKey: "")
메서드를 통해 Read
, 뒤의 자료형에 따라 string
, bool
, integer
변경UserDefaults.standard.removeObject(forKey:"")
메서드를 통해 Delete
key에 대응하는 값이 있는지 없는지 모르기 때문에 Optional로 출력, 코드에도 주의표시 생성
주의표시 없애려면 옵셔널 바인딩 하여 사용하면 된다!