[iOS/Swift] Realm - 백업 및 복구 구현하기

2023. 9. 16. 23:21·iOS/UIKit&SwiftUI

💡 백업 / 복구

개인 앱의 경우 개개인에게 백업 복구의 책임을 넘긴다.

개발자 → 기능만 제공, 백업 알아서,,

구글 드라이브, 드랍박스로 백업하기

→ 써드파티 프로그램의 정책으로 유지보수 비용이 높다

아이폰 파일 앱 사용하여 백업 복구하도록 하기

 

1. realm 파일 자체를 압축

마이그레이션 대응이 잘 되어야 한다.

사용자가 백업해두고 한참 뒤에 복구할 수 있기 때문

realm 파일을 복구할 때는 복구 완료 후 앱을 껐다 켜야 함

 

2. json으로 압축하기

다른 sql을 쓰더라도 대응하기 좋음

🔎 realm 파일 압축하기

  1. 백업하고자 하는 파일들의 경로 배열 생성
var urlPaths = [URL]() 
  1. 도큐먼트 위치
guard let path = documentDirectoryPath() else {
    print("도큐먼트 위치에 오류가 있습니다.")
    return
}
  1. 백업하고자 하는 파일 경로 ex) ~//~~~/Document/default.realm
let realmFile = path.appendingPathComponent("default.realm") 
  1. 3번 경로가 유효한지 확인
guard FileManager.default.fileExists(atPath: realmFile.path) else {
    print("백업할 파일이 없습니다.")
    return
}
  1. 압축하고자 하는 파일을 배열에 추가 
urlPaths.append(realmFile) 
  1. 압축

압축 오픈소스

https://github.com/marmelroy/Zip

보안, 진행률 등 소스 사용할 수 있다

do {
    let zipFilePath = try Zip.quickZipFiles(urlPaths, fileName: "JYArchive")
    print("location: \(zipFilePath)")
} catch {
    print("압축을 실패했어요")
}

Untitled.png

💻 전체 코드

// 1. 백업하고자 하는 파일들의 경로 배열 생성
var urlPaths = [URL]()

// 2. 도큐먼트 위치
guard let path = documentDirectoryPath() else {
    print("도큐먼트 위치에 오류가 있습니다.")
    return
}

// 3. 백업하고자 하는 파일 경로 ex) ~~~/~~/~~~/Document/default.realm
let realmFile = path.appendingPathComponent("default.realm")

//4. 3번 경로가 유효한지 확인
guard FileManager.default.fileExists(atPath: realmFile.path) else {
    print("백업할 파일이 없습니다.")
    return
}

// 5. 압축하고자 하는 파일을 배열에 추가
urlPaths.append(realmFile)

// 6. 압축
do {
    let zipFilePath = try Zip.quickZipFiles(urlPaths, fileName: "JYArchive")
    print("location: \(zipFilePath)")
} catch {
    print("압축을 실패했어요")
}

압축한 백업 파일 이름을 테이블 뷰에 보여준다.

🔎 복구하기

func fetchZipList() -> [String] {
  var list: [String] = []
  
  do {
      guard let path = documentDirectoryPath() else { return list }
      let docs = try FileManager.default.contentsOfDirectory(at: path, includingPropertiesForKeys: nil)
      let zip = docs.filter { $0.pathExtension == "zip"}
      for i in zip {
          list.append(i.lastPathComponent)
      }
  } catch {
      print("ERROR")
  }
  
  return list
}

Untitled.pngUntitled.pngUntitled.pngUntitled.png

💡 백업 파일을 아이폰 파일 앱에 저장하기

Untitled.png

💡 앱 삭제 후 다시 빌드하여 복구하기

고려해볼 것

  1. 파일 없음
  2. 저장 공간
  3. 인디케이터 + 클릭 방지
  4. 복구 후 zip 파일 제거
  5. 선택한 앱의 구조와 맞는 zip 파일인지 체크
@objc func restoreButtonTapped() {
  // 파일 앱을 활용한 복구
  let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [.archive], asCopy: true)
  documentPicker.delegate = self
  documentPicker.allowsMultipleSelection = false // 다중 선택 방시
  present(documentPicker, animated: true)
}

 

 

 

파일 앱에서 접근 할 파일의 확장자를 제한

Untitled.pngUntitled.png

✅ didPickDocumentsAt

파일 앱에서 선택한 파일로 복구하기

guard let selectedFileURL = urls.first else { // 파일 앱 내의 url 주소
    print("선택한 파일에 오류가 있어요")
    return
}

guard let path = documentDirectoryPath() else {
    print("도큐먼트 위치에 오류가 있어요")
    return
}

 

도큐먼트 폴더 내 저장할 경로 설정

let sandboxFileURL = path.appendingPathComponent(selectedFileURL.lastPathComponent) 

~~~/~~~/document/default.realm

-> 최종 url 만들기

 

경로에 복구할 파일(zip)이 이미 있는지 확인

이미 파일이 있다면

 

경로에 복구 할 파일이 없을 때 

💻  압축 해제 코드

func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
        
    guard let selectedFileURL = urls.first else { // 파일 앱 내의 url 주소
        print("선택한 파일에 오류가 있어요")
        return
    }
    
    guard let path = documentDirectoryPath() else {
        print("도큐먼트 위치에 오류가 있어요")
        return
    }
    
    // 도큐먼트 폴더 내 저장할 경로 설정
    let sandboxFileURL = path.appendingPathComponent(selectedFileURL.lastPathComponent)
    print(sandboxFileURL)
    
    // 경로에 복구할 파일(zip)이 이미 있는지 확인
    if FileManager.default.fileExists(atPath: sandboxFileURL.path) {
        
        let fileURL = path.appendingPathComponent("JYArchive.zip")
        
        do {
            try Zip.unzipFile(fileURL, destination: path, overwrite: true, password: nil, progress: { progress in // 진행률
                print("progress: \(progress)")
            }, fileOutputHandler: { unzippedFile in // 압축 해제 완료
                print("압축 해제 완료: \(unzippedFile)")
            })
        } catch {
            print("압축 해제 실패")
        }
        
    } else {
        
        // 경로에 복구할 파일이 없을 때의 대응
        do {
            try FileManager.default.copyItem(at: selectedFileURL, to: sandboxFileURL)
            let fileURL = path.appendingPathComponent("JYArchive.zip")
            
            try Zip.unzipFile(fileURL, destination: path, overwrite: true, password: nil, progress: { progress in // 진행률
                print("progress: \(progress)")
            }, fileOutputHandler: { unzippedFile in // 압축 해제 완료
                print("압축 해제 완료: \(unzippedFile)")
            })
            
        } catch {
            print("압축 해제 실패")
        }
    }
    
    
}

백업 버튼 누르면

~~/document/default.realm 파일을 압축하여 저장한다.

백업 파일은 같은 이름으로 설정하면 덮어쓰기된다.

  • 복구해서 압축을 풀었으면 zip 파일을 제거해야 한다. zip 파일 삭제하지 않으면 계속 남게된다.
  • 사용자가 아무 zip파일을 선택할 수 있다.
    • 하지만 해당 앱과 구조가 다른 파일일 수 있다
    • 압축 해제 후 파일 이름과 개수를 체크

'iOS > UIKit&SwiftUI' 카테고리의 다른 글

[iOS/Swift] MapKit - 원하는 곳에 어노테이션을 찍어보자  (1) 2023.10.01
[iOS/Swift] MapKit - 위치 권한 설정을 구현해보자!  (1) 2023.10.01
[iOS/Swift] Realm - Migration  (1) 2023.09.16
[iOS/Swift] Realm - 이미지 파일 저장하기  (0) 2023.09.16
[iOS/Swift] Realm - CRUD  (1) 2023.09.16
'iOS/UIKit&SwiftUI' 카테고리의 다른 글
  • [iOS/Swift] MapKit - 원하는 곳에 어노테이션을 찍어보자
  • [iOS/Swift] MapKit - 위치 권한 설정을 구현해보자!
  • [iOS/Swift] Realm - Migration
  • [iOS/Swift] Realm - 이미지 파일 저장하기
김졀니
김졀니
🍎 iOS 개발
  • 김졀니
    졀니의 개발 공부✨
    김졀니
  • 전체
    오늘
    어제
    • 분류 전체보기
      • iOS
        • Swift
        • UIKit&SwiftUI
        • RxSwift&Combine
        • WWDC
      • Study
        • 🚨 TroubleShooting
        • 🌱 SeSAC
  • 블로그 메뉴

    • 홈
    • Github
  • 인기 글

  • 최근 글

  • 태그

    인앱리뷰
    Drawing Cycle
    kingfisher header
    의존성 주입
    위치 권한
    traits
    observable
    @PropertyWrapper
    동시성프로그래밍
    CLLocation
    mainactor
    Swift
    pointfree
    clipstobounds
    swiftdata
    Sendable
    actor
    mapkit
    OperationQueue
    displayPriority
    concurrency
    RxSwift
    Realm
    layoutIfNeeded
    FileManager
    swift concurrency
    ios
    이미지 캐싱
    ReactorKit
    wwdc23
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
김졀니
[iOS/Swift] Realm - 백업 및 복구 구현하기
상단으로

티스토리툴바