Database
https://www.mongodb.com/docs/realm/sdk/swift/quick-start/
데이터베이스 : 데이터를 저장한 파일들의 집합체
- DBMS : DataBase Management System : 데이터베이스를 관리하기 위한 소프트웨어, 엑셀도 마찬가지임
- RDBMS : 관계형 데이터 베이스 : relational Database management system
데이터를 표 안에 정리하는 것, 테이블 구조
RDBMS
테이블과 테이블 간 외래키를 통해 정보 구현
중복 데이터 저장 방지
데이터베이스 내의 테이블을 Schema
각각의 데이터 모델을 스키마
name, title, date를 이름지어서 정리하는데 이걸 Column = Attribute
저장되어 있는 하나의 row를 Record = Row
예시를 살펴보자면,,
근데 김수현이 동명이인이 발생할 수 있잖아? -> 좋지 못한 구조이지
각각의 고유 ID를 주면 좋겟지?
만약에 김수현이 개명을 하는데 우리의 테이블에는 데이터가 엄청 많아서 바꿔주기 너무 힘들어..
그럴 경우에는 Actor라는 테이블을 추가로 만들면 된다.
그래서 필모그래피 테이블에서 actorID로 접근하면 된다.
여기서 또 문제가 발생할 수도 있다.
별에서 온 그대가 2033년에 또 나올 수도 있고, 별그대에 다른 배우가 출연한 경우도 있고
그래서 title을 구분해주기 위해서 ID라는 컬럼을 추가한 것임
⭐️ ID가 중복이 되면 안된다. 고유키여야 하고, 빈값이면 안된다. = Primary Key (PK값)
그리고 PK값은 인덱스가 존재한다. 책의 목차 같은 느낌이라고 받아들이면 될 것 같다.
⭐️ actorID는 foreign Key (FK값, 외래키) 라고 생각하면 된다. Actor 테이블의 ID로 사용하기 때문이다.
다른 테이블의 Primary Key 역할을 하는 녀석이다.
⭐️ Actor의 Birth는 선택사항(null 가능)인데 중복이 안된다고 했을 시에 Unique Key (UK값)이라고 보면 된다.
약간 주민등록번호 같은 것임
그리고 이렇게 쪼개고, 서로 연관되어 있는 데이터를 묶어서 관리하게 된다.
효율성을 위해 테이블을 만들어서 나누는 것을 정규화라고 한다.
Swift의 데이터베이스
CoreData는 애플에서 자체적으로 만들어둔 데이터베이스
Realm은 모바일 클라이언트가 사용하기 가벼워서 자주 사용하고, spm으로 추가해서 사용
근데 Realm을 자주 쓰는 이유는 속도가 빠르고, 안드/아요 둘 다 대응이 된다.
따라서, 통계적으로 데이터를 내고 싶은 경우에는 Realm은 적합하지 않다.
MongoDB가 Realm을 인수했대~
RealmSwift
1. 첫 단계는 데이터 모델을 만드는 건데, 데이터베이스의 스키마를 정의하는 것이다.
테이블의 이름과 테이블의 컬럼을 정하는 것
2. 두 번째 단계는 로컬에 있는 realm 파일의 위치를 찾아 여는 것이다.
해당 테이블을 사용하기 위해서는 해당 파일의 위치를 찾아가서
우리 폰의 앱들은 각각 별개의 위치를 가지고 있다. 그리고 그 공간의 위치는 매번 바껴서 애플이 그런 식으로 보안을 유지하려고 한다.
그래서 realm도 나의 앱 위치를 잘 모르는데 이를 위해 만들어준 코드이다.
앱 내의 파일 위치를 찾기 위함
3. 스키마를 정의하는 것은 아래와 같다.
https://www.mongodb.com/docs/realm/sdk/swift/model-data/define-model/supported-types/
사용가능한 타입이고,
nil 값을 받을 수 있냐에 따라 작성하는 코드가 달라진다.
Required -> 빈값 허용 X
Optional -> 빈값 허용 O
⭐️ 본격적으로 테이블! 즉, 데이터베이스의 스키마를 만들어보쟈
import RealmSwift
// MARK: - UserDiary
/*
UserDiary : 테이블이름
@Persisted : 컬럼명
*/
class UserDiary: Object {
@Persisted var uuid: UUID
@Persisted var title: String
@Persisted var content: String?
@Persisted var createdAt = Date() // 작성 날짜
@Persisted var updatedAt = Date() // 등록 날짜
@Persisted var favorite: Bool // 즐겨찾기
@Persisted var image: String?
// PK, Primary Key : UUID or ObjectID
}
PK를 위해서 UUID or ObjectID를 쓰면 좋다.
Int를 써도 좋긴 한데 이걸 쓰면 인덱스에 따라 값을 더해줘야 함.
UUID는 16바이트, ObjectID는 12바이트로 이루어져 있다.
UUID는 애플에서 말하는 UUID와 다르다.
PK를 만들기 위해서는 아래처럼 해주면 된다.
PK는 기본적으로 인덱스 속성이 들어가는데 PK가 아니더라도 인덱스 효과를 주고 싶다면,
indexed: true 를 추가해서 검색 및 필터링하는 기능에서 속도를 높이게 할 수 있다.
그런데 모든 컬럼에 해당 기능을 추가하는 건 지양해야 한다. (속도, 성능이 오히려 저하된다.)
ex. 책에서 모든 단어들이 인덱싱되어 있는 것과 같음 - 효율적이지 못하다.
데이터 저장하고 가져올 때 사용할 초기화 구문
convenience가 뭐냐? 꼭 초기화해주지 않아도 되는 값은 제외하고 하겠다.
예를 들어, UUID (ObjectID)는 realm에서 자체적으로 초기화를 해주기 때문
CRUD
1. Create
Realm 경로에 접근해서 테이블에 데이터를 저장하는 코드
let localRealm = try! Realm()
테이블 이름이 UserDiary이고 읽어올 때 try문을 써서 오류를 대응해준다.
가져온 테이블에 task를 넣어주면 완료..!
@objc func touchupSaveButton() {
// Create Record
guard let title = writerView.titleTextField.text,
let content = writerView.diaryTextView.text,
let updatedAt = writerView.dateTextField.text,
let image = writerView.photoImageView.image else { return }
let task = UserDiary(title: title,
content: content,
createdAt: Date(),
updatedAt: updatedAt,
image: nil)
// 오류를 대응하기 위해서 try
try! localRealm.write {
localRealm.add(task)
print("Realm Succeed")
dismiss(animated: true)
}
}
## 이런 경우 오류가 발생한다
만약에 테이블에 데이터를 저장하고 나서 테이블 구조를 변경해준다면?
변수명이 마음에 안들어서 바꾸거나, 새로운 컬럼을 추가한다면? 아래와 같은 오류가 생길 것이다.
기존에 가지고 있던 테이블과 새로 만들어진 테이블과 충돌이 난 것이다.
realm이 한 번 만들어지고 나면 꼭 오류가 난다.
이걸 해결하기 위해서 구현 시에 가장 쉬운 방법은 앱을 삭제하고 다시 만드는 것이다.
이는 로컬에 있는 도큐먼트도 삭제되고 다시 생성되기 때문이다.
그러나!! 출시하고 업데이트하면서 테이블 구조가 바뀐 경우에는?
사용자의 데이터를 보존하기 위해서 앱 삭제를 하는 것은 좋지 못하다.
그래서 마이그레이션이라는 작업을 해줘야 한다. 이전 버전과 이후 버전을 일치시켜주는 작업이다.
데이터베이스에서는 스키마 버전을 관리하기 위해서 마이그레이션이라는 단어를 사용한다.
그래서 디버그 문구에서 아래와 같이 뜬다.
마이그레이션 코드는 출시 후에 한 명의 유저라도 테이블이 업데이트가 안된다면 쭉 가지고 가야 한다.
Realm Studio
우리의 저장된 데이터를 가져와서 확인해보려면? Realm Studio 데스크탑 앱을 사용해서 확인해야 한다.
1. Realm 경로에 가져오기
let localRealm = try! Realm()
그러면 우리의 local 어느 경로에 있는지 확인하기 위해서는 공식문서에서 알려준 방법으로 디버깅해보면 된다.
콘솔창에 나온 경로를 열면, RealmStudio가 열려서 테이블을 확인해볼 수 있다.
근데 시뮬이 아닌 실기기로 빌드해서 realmstudio를 열어주려고 할 경우에
싱크가 안맞아고, 경로가 안맞는 경우가 발생하니까 웬만하면 시뮬로 돌리자..
2. Realm 데이터 담아줄 배열 만들기
var tasks: Results<UserDiary>!
3. 데이터 가져오기
데이터를 가져오기 위해서 또 공식문서에 나온대로 따라한다.
4. 데이터 정렬 바꾸기
LocalRealm Data를 가져오면 Object를 추가한 순서대로 정렬될 것이다.
1. 정렬 순서를 바꾸고 싶으면 query를 주거나, (DB에서 알려주는 정렬방법)
2. sort, filter, 반복문을 통해서 새롭게 정렬한다. (Swift에서 알려주는 정렬방법)
주로 1번 방법을 많이 쓴다.
// 작성날짜 순으로 오름차순 false = 즉, 내림차순을 사용한 것임 (최근 날짜부터 ~)
let tasks = localRealm.objects(UserDiary.self).sorted(byKeyPath: "createdAt", ascending: false)
별개로,
overFullScreen/present/overCurrentContext으로 동작 시에는 viewWillAppear가 실행이 되지 않는다.
이전 rootViewController가 사라지지 않고 그대로 남아있는 상태에서 화면이 띄워지기 때문이다.
fullScreen으로 동작해야 실행이 된다.
화면 갱신은 화면 전환 코드 및 생명 주기 실행 점검을 해야 한다.
* 해당 글에 사용된 PPT의 출처는 SeSAC iOS 앱 개발자 데뷔 과정 강의 자료입니다~!
'⭐️ 개발 > iOS & Swift' 카테고리의 다른 글
[Swift] WMO - Swift 성능 최적화 (1) | 2022.08.26 |
---|---|
[Swift] Realm 진짜.그냥.간단.정리 (0) | 2022.08.24 |
[iOS] loadView() (0) | 2022.08.21 |
[Swift] Generic (0) | 2022.08.21 |
[iOS] UIView의 초기화 구문 다시 알자! (0) | 2022.08.19 |