How To Use RealmDB With Combine Future

YongJunCha·2022년 1월 5일
0

Realm

목록 보기
3/4
post-thumbnail

When should We Send Sign To Observer?

  • Combine Future를 사용하면서 Realm의 Transaction이 정확히 언제 끝나는지
  • 그 때는 언제인지 어떻게 보내야 하는지 생각보다 문서가 없었고, 시도되지 않은 것 같아서 글을 남긴다.

Why We Use Combine Future?

  • RealmToken을 쓰면 UI업데이트는 다 거기서 하면 되지 않냐고 생각하는 사람이 있겠지만,
  • 생각보다 순차적으로 일이 끝나야하고 세부 컨트롤이 들어가야하는 일이 많다.
  • RealmToken으로 다 해결되면 내가 이 글을 안 쓰고 있었을 것 같다.

CodeLab

   public func insertFormattedKeyword(keywordEngineType: Int, keywords: [Keyword], promise: @escaping(Result<Bool,Error>) -> Void) {
        realm.executeTransactionAsync {
            do {
                guard let keywordEngine = realm.object(ofType: KeywordEngine.self, forPrimaryKey: keywordEngineType) else {
                    print("Contact \(keywordEngineType) not found")
                    return
                }
                try realm.write() {
                    print("KEYWORD COUNT DAO :: \(keywords.count)")
                    keywordEngine.keywords.append(objectsIn: keywords)
                    print("KEYWORD TIMESTAMP UPDATE : \(Date())")
                    keywordEngine.timestamp = Date()
                }
                promise(.success(true))
            } catch let error as NSError {
                print("\(error)")
                promise(.failure(error))
            }
        }
    }
  • 그렇다면 언제 우리는 Combine Future에 success 신호를 보내야할까?
  • 공식 문서에도 안 나와있고 내 나름대로 연구를 했다.
  • 우선은 상기의 코드에서 try realm.write의 구간이 모두 끝난 후에 성공신호를 보내면 된다.
  • 이유는 하기의 코드와 함께 설명하겠다.
/**
- parameter tokens: An array of notification tokens which were returned
                         from adding callbacks which you do not want to be
                         notified for the changes made in this write transaction.

     - parameter block: The block containing actions to perform.
     - returns: The value returned from the block, if any.

     - throws: An `NSError` if the transaction could not be completed successfully.
               If `block` throws, the function throws the propagated `ErrorType` instead.
     */
    @discardableResult
    public func write<Result>(withoutNotifying tokens: [NotificationToken] = [], _ block: (() throws -> Result)) throws -> Result {
        beginWrite()
        var ret: Result!
        do {
            ret = try block()
        } catch let error {
            if isInWriteTransaction { cancelWrite() }
            throw error
        }
        if isInWriteTransaction { try commitWrite(withoutNotifying: tokens) }
        return ret
    }
  • 상기의 코드는 realm의 코드이다.
  • realm.write의 클로저에 코드들을 다 담으면
  • beginWrite()로 realmDB의 트랜잭션을 시작하고
  • commitWrite()로 realmDB를 커밋한다.
  • 따라서 write문이 끝나는 시점은 DB입력이 commit이나 cancel이 결정된 상태이다.
  • 우리는 그 순간이 바로 약속의 시간 promise(.success(true))를 해야하는 순간이다.
  • Error Type도 정해져있으니 Catch 쪽에서는 NSError를 에러 타입으로 캐스팅해줘야한다.

0개의 댓글