-
[iOS_MyInventory] Realm 적용 2 - Struct 와 같이 사용하기Project/[release] iOS - MyInventory 2020. 3. 21. 11:02
Realm 에서 지원하는 객체모델은 다음과 같이 class 형태로 작성을 해야한다.
class Dog: Object { @objc dynamic var name = "" @objc dynamic var age = 0 }
Realm 객체모델을 구조체로(struct) 사용하기 위해서는,
struct <---> RealmObject 를 맵핑하는 중간다리가 필요하다.
이를 Persistable 프로토콜이 담당한다.
public protocol Persistable { associatedtype ManagedObject: RealmSwift.Object // RealmObject -> Struct 변환 init(managedObject: ManagedObject) // Struct -> RealmObject func managedObject() -> ManagedObject }
Realm모델에 따른 struct 모델을 구성한다.
새로운 Person 객체 생성시, 내부에서 id 를 1씩 증가해 나가므로, Person 에 해당하는 데이터만 넣어주면 된다.
그리고 Person Struct 는 Persistable 을 준수하여, Realm 객체를 Struct 로, 또는 Struct 를 Realm 객체로 변환하게 된다.
@objcMembers class RealmPerson: Object { dynamic var id: Int = 0 dynamic var firstName: String = "" dynamic var lastName: String = "" var gender = RealmOptional<Int>(0) var age = RealmOptional<Int>(0) dynamic var myImage: Data? = nil override static func primaryKey() -> String? { return "id" } } struct Person { public let id: Int public let firstName: String public let lastName: String public let gender: Int? public let age: Int? public let myImage: UIImage? public init(firstName: String, lastName: String, gender: Int?, age: Int?, myImage: UIImage? = nil) { self.id = try! RealmManager().incrementID() self.firstName = firstName self.lastName = lastName self.gender = gender self.age = age self.myImage = myImage } } //MARK: Struct To RealmObject extension Person: Persistable { // RealmObject -> Struct public init(managedObject: RealmPerson) { self.id = managedObject.id self.firstName = managedObject.firstName self.lastName = managedObject.lastName self.gender = (managedObject.gender as? Int ?? nil) self.age = (managedObject.age as? Int ?? nil) if let imageData = managedObject.myImage { self.myImage = UIImage(data: imageData) } else { self.myImage = nil } } // Struct -> RealmObject public func managedObject() -> RealmPerson { let person = RealmPerson() person.id = self.id person.firstName = self.firstName person.lastName = self.lastName person.age = RealmOptional<Int>(self.age) person.gender = RealmOptional<Int>(self.gender) person.myImage = self.myImage?.pngData() return person } }
그리고 Realm객체 변경을 담당하는 WriteTransaction Class 를 작성한다.
데이터 삽입작업(add) 을 할경우,
Persistable 을 준수하는 모델(struct)을 받아서, Realm객체로 변경하여 데이터 삽입을 하게된다.
public final class WriteTransaction { private let realm: Realm internal init(realm: Realm) { self.realm = realm } // Add newObject public func add<T: Persistable>(_ value: T) { realm.add(value.managedObject()) } }
마지막으로, realm에 관한 사용자 작업을 담당하는 RealmManager Class 를 수정한다.
여기서는 realm 인스턴스를 생성하고, 이 인스턴스를 통해 CRUD에 관련된 트랜젝션을 실행한다.
(모든 Realm 객체변경은 트랜젝션 내부에서 실행해야 한다)
/** * RealmManager Class */ internal static func realm() -> Realm? { do { return try Realm() } catch { print(error.localizedDescription) } return nil } public func write(_ block: (WriteTransaction) throws -> Void) throws { guard let realm = realm() else { return } let transaction = WriteTransaction(realm: realm) try realm.write { try block(transaction) } } func incrementID() -> Int { guard let realm = realm() else { return 0 } return (realm.objects(RealmPerson.self).max(ofProperty: "id") as Int? ?? 0) + 1 } public static let DBPath: URL? = { let appGroupID: String = K_GROUP_ID guard let groupDir: URL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupID) else { return nil } let realmPath = groupDir.appendingPathComponent(K_DB_NAME) return realmPath }()
ViewController 에서 데이터 추가를 하려면 이렇게 작성하면 된다.
let person = Person(firstName: "트랜잭션", lastName: "테스트", gender: 0, age: 22, myImage: UIImage(named: "IMG_3966")) let realmManager = try! RealmManager() try! realmManager.write { transaction in print(person) transaction.add(person) }
데이터 삽입 결과 기존의 struct 모델을 그대로 사용하여 realm객체에 맵핑할 수 있다는 장점이 있지만,
이를 위해서 중간에 protocol, generic, 함수형 프로그래밍을 통한, 재사용성과 확장성을 생각해야만 한다.
참고자료
https://medium.com/@ludovicjamet/how-to-use-struct-with-realm-615fcbc8f0ee
How to use struct with Realm ?
By default, Realm Objects are classes and not structs because they are not values, but auto-updating objects pointing to data in Realm…
medium.com
'Project > [release] iOS - MyInventory' 카테고리의 다른 글
[iOS_MyInventory] 뷰 디자인 적용 (0) 2020.04.01 [iOS_MyInventory] Realm 적용 3 - todayExtension (0) 2020.03.22 [iOS_MyInventory] Realm 적용 1 - ManagerClass 를 활용하기 (0) 2020.03.20 [iOS_MyInventory] 카테고리 수정, 아이템 리스트 화면 추가 (0) 2020.03.14 [iOS_MyInventory] 카테고리 메뉴 - 디자인 적용, 등록, 삭제 (0) 2020.03.10