[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
  • 인기 글

  • 최근 글

  • 태그

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

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

티스토리툴바