다음을 통해 공유


iOS 모바일 앱과 오프라인 동기화 사용

개요

이 자습서에서는 iOS용 Azure App Service의 Mobile Apps 기능과 오프라인 동기화에 대해 설명합니다. 오프라인 동기화를 통해 최종 사용자는 네트워크 연결이 없는 경우에도 모바일 앱과 상호 작용하여 데이터를 보거나 추가하거나 수정할 수 있습니다. 변경 내용은 로컬 데이터베이스에 저장됩니다. 디바이스가 다시 온라인 상태가 된 후 변경 내용은 원격 백 엔드와 동기화됩니다.

Mobile Apps에 대한 첫 번째 환경인 경우 먼저 iOS 앱 만들기자습서를 완료해야 합니다. 다운로드한 빠른 시작 서버 프로젝트를 사용하지 않는 경우 프로젝트에 데이터 액세스 확장 패키지를 추가해야 합니다. 서버 확장 패키지에 대한 자세한 내용은 Azure Mobile Apps용 .NET 백 엔드 서버 SDK작업을 참조하세요.

오프라인 동기화 기능에 대한 자세한 내용은 Mobile Apps 오프라인 데이터 동기화참조하세요.

클라이언트 동기화 코드 검토

iOS 앱 만들기 자습서용으로 다운로드한 클라이언트 프로젝트에는 로컬 Core 데이터 기반 데이터베이스를 사용하여 오프라인 동기화를 지원하는 코드가 이미 포함되어 있습니다. 이 섹션에서는 자습서 코드에 이미 포함된 내용을 요약합니다. 이 기능에 대한 개념적 개요는 Mobile Apps 오프라인 데이터 동기화참조하세요.

Mobile Apps의 오프라인 데이터 동기화 기능을 사용하여 최종 사용자는 네트워크에 액세스할 수 없는 경우에도 로컬 데이터베이스와 상호 작용할 수 있습니다. 앱에서 이러한 기능을 사용하려면 MSClient 동기화 컨텍스트를 초기화하고 로컬 저장소를 참조합니다. 그런 다음 MSSyncTable 인터페이스를 통해 테이블을 참조합니다.

QSTodoService.m(Objective-C) 또는 ToDoTableViewController.swift(Swift)에서 syncTable 멤버의 형식이 MSSyncTable 임을 확인하세요. 오프라인 동기화는 MSTable 대신 이 동기화 테이블 인터페이스를 사용합니다. 동기화 테이블을 사용하는 경우 모든 작업은 로컬 저장소로 이동하고 명시적 푸시 및 끌어오기 작업으로 원격 백 엔드와만 동기화됩니다.

동기화 테이블에 대한 참조를 얻으려면 MSClient 메서드를 사용합니다. 오프라인 동기화 기능을 제거하려면 tableWithName 대신 사용합니다.

테이블 작업을 수행하려면 먼저 로컬 저장소를 초기화해야 합니다. 관련 코드는 다음과 같습니다.

  • Objective-C. QSTodoService.init 메서드:

    MSCoreDataStore *store = [[MSCoreDataStore alloc] initWithManagedObjectContext:context];
    self.client.syncContext = [[MSSyncContext alloc] initWithDelegate:nil dataSource:store callback:nil];
    
  • Swift. ToDoTableViewController.viewDidLoad 메서드:

    let client = MSClient(applicationURLString: "http:// ...") // URI of the Mobile App
    let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!
    self.store = MSCoreDataStore(managedObjectContext: managedObjectContext)
    client.syncContext = MSSyncContext(delegate: nil, dataSource: self.store, callback: nil)
    

    이 메서드는 Mobile Apps SDK에서 제공하는 MSCoreDataStore 인터페이스를 사용하여 로컬 저장소를 만듭니다. 또는 MSSyncContextDataSource 프로토콜을 구현하여 다른 로컬 저장소를 제공할 수 있습니다. 또한 MSSyncContext 첫 번째 매개 변수는 충돌 처리기를 지정하는 데 사용됩니다. nil을 통과했기 때문에 기본 충돌 처리기를 얻었고, 이것은 모든 충돌에서 실패합니다.

이제 실제 동기화 작업을 수행하고 원격 백 엔드에서 데이터를 가져옵니다.

  • Objective-C. syncData 먼저 새 변경 내용을 푸시한 다음, pullData 호출하여 원격 백 엔드에서 데이터를 가져옵니다. 차례로 pullData 메서드는 쿼리와 일치하는 새 데이터를 가져옵니다.

    -(void)syncData:(QSCompletionBlock)completion
    {
         // Push all changes in the sync context, and then pull new data.
         [self.client.syncContext pushWithCompletion:^(NSError *error) {
             [self logErrorIfNotNil:error];
             [self pullData:completion];
         }];
    }
    
    -(void)pullData:(QSCompletionBlock)completion
    {
         MSQuery *query = [self.syncTable query];
    
         // Pulls data from the remote server into the local table.
         // We're pulling all items and filtering in the view.
         // Query ID is used for incremental sync.
         [self.syncTable pullWithQuery:query queryId:@"allTodoItems" completion:^(NSError *error) {
             [self logErrorIfNotNil:error];
    
             // Lets the caller know that we have finished.
             if (completion != nil) {
                 dispatch_async(dispatch_get_main_queue(), completion);
             }
         }];
    }
    
  • Swift:

    func onRefresh(sender: UIRefreshControl!) {
        UIApplication.sharedApplication().networkActivityIndicatorVisible = true
    
        self.table!.pullWithQuery(self.table?.query(), queryId: "AllRecords") {
            (error) -> Void in
    
            UIApplication.sharedApplication().networkActivityIndicatorVisible = false
    
            if error != nil {
                // A real application would handle various errors like network conditions,
                // server conflicts, etc. via the MSSyncContextDelegate
                print("Error: \(error!.description)")
    
                // We will discard our changes and keep the server's copy for simplicity
                if let opErrors = error!.userInfo[MSErrorPushResultKey] as? Array<MSTableOperationError> {
                    for opError in opErrors {
                        print("Attempted operation to item \(opError.itemId)")
                        if (opError.operation == .Insert || opError.operation == .Delete) {
                            print("Insert/Delete, failed discarding changes")
                            opError.cancelOperationAndDiscardItemWithCompletion(nil)
                        } else {
                            print("Update failed, reverting to server's copy")
                            opError.cancelOperationAndUpdateItem(opError.serverItem!, completion: nil)
                        }
                    }
                }
            }
            self.refreshControl?.endRefreshing()
        }
    }
    

먼저 Objective-C 버전에서는 syncData동기화 컨텍스트에서 pushWithCompletion을 호출합니다. 이 메서드는 모든 테이블에서 변경 내용을 푸시하기 때문에 동기화 테이블 자체가 아닌 MSSyncContext 멤버입니다. CUD 작업을 통해 어떤 방식으로든 로컬로 수정된 레코드만 서버로 전송됩니다. 그런 다음, MSSyncTable.pullWithQuery 호출하여 원격 데이터를 검색하고 로컬 데이터베이스에 저장하는 pullData 도우미가 호출됩니다.

Swift 버전에서는 푸시 작업이 엄격하게 필요하지 않았기 때문에 pushWithCompletion 호출이 없습니다. 밀어넣기 작업을 수행하는 테이블의 동기화 컨텍스트에서 보류 중인 변경 사항이 있는 경우, 풀은 항상 푸시를 먼저 진행합니다. 그러나 둘 이상의 동기화 테이블이 있는 경우 푸시를 명시적으로 호출하여 모든 것이 관련 테이블에서 일관되도록 하는 것이 가장 좋습니다.

Objective-C 및 Swift 버전 모두에서 pullWithQuery 메서드를 사용하여 검색하려는 레코드를 필터링하는 쿼리를 지정할 수 있습니다. 이 예제에서 쿼리는 원격 TodoItem 테이블의 모든 레코드를 검색합니다.

pullWithQuery 두 번째 매개 변수는 증분 동기화사용되는 쿼리 ID입니다. 증분 동기화는 레코드의 UpdatedAt 타임스탬프를 사용하여 마지막 동기화 이후 수정된 레코드만 검색합니다(로컬 저장소에서 updatedAt). 쿼리 ID는 앱의 각 논리 쿼리에 대해 고유한 설명 문자열이어야 합니다. 증분 동기화를 옵트아웃하려면 nil 쿼리 ID로 전달합니다. 이 방법은 각 끌어오기 작업의 모든 레코드를 검색하기 때문에 잠재적으로 비효율적일 수 있습니다.

Objective-C 앱은 데이터를 수정하거나 추가할 때, 사용자가 새로 고침 제스처를 수행하고 시작할 때 동기화됩니다.

사용자가 새로 고침 제스처를 수행하고 시작할 때 Swift 앱이 동기화됩니다.

데이터가 수정될 때마다(Objective-C) 또는 앱이 시작될 때마다(Objective-C 및 Swift) 앱이 동기화되므로 앱은 사용자가 온라인 상태라고 가정합니다. 이후 섹션에서는 사용자가 오프라인일 때도 편집할 수 있도록 앱을 업데이트합니다.

핵심 데이터 모델 검토

Core Data 오프라인 저장소를 사용하는 경우 데이터 모델에서 특정 테이블과 필드를 정의해야 합니다. 샘플 앱에는 올바른 형식의 데이터 모델이 이미 포함되어 있습니다. 이 섹션에서는 이러한 테이블의 사용 방법을 보여 줍니다.

QSDataModel.xcdatamodeld엽니다. SDK에서 사용되는 테이블 3개와 to-do 항목 자체에 사용되는 테이블 3개 등 4개의 테이블이 정의됩니다.

  • MS_TableOperations: 서버와 동기화해야 하는 항목을 추적합니다.
  • MS_TableOperationErrors: 오프라인 동기화 중에 발생하는 오류를 추적합니다.
  • MS_TableConfig: 모든 끌어오기 작업에 대한 마지막 동기화 작업의 마지막 업데이트 시간을 추적합니다.
  • TodoItem: to-do 항목을 저장합니다. 시스템 열 createdAt, updatedAt버전은 선택적인 시스템 속성입니다.

비고

Mobile Apps SDK는 "``"로 시작하는 열 이름을 예약합니다. 이 접두사는 시스템 열 외에는 사용하지 마세요. 그렇지 않으면 원격 백 엔드를 사용할 때 열 이름이 수정됩니다.

오프라인 동기화 기능을 사용하는 경우 세 개의 시스템 테이블과 데이터 테이블을 정의합니다.

시스템 테이블

MS_TableOperations

MS_TableOperations 테이블 특성MS_TableOperations table attributesMS_TableOperations table attributes

특성 유형
아이디 정수 64
아이템 ID 문자열
속성 이진 데이터
테이블 문자열
테이블 유형 정수 16

MS_TableOperationErrors

MS_TableOperationErrors 테이블 특성

특성 유형
아이디 문자열
operationId 정수 64
속성 이진 데이터
테이블 유형 정수 16

MS_TableConfig

특성 유형
아이디 문자열
열쇠 문자열
키타입 (keyType) 정수 64
테이블 문자열
가치 문자열

데이터 테이블

TodoItem

특성 유형 비고
아이디 필수로 표시된 문자열 원격 저장소의 기본 키
완성하다 불리언 (Boolean) 할 일 항목 필드
문자 메시지 문자열 할 일 항목 필드
생성일시 날짜 (선택 사항) 은(는) createdAt 시스템 속성에 매핑됩니다.
업데이트된 시간 날짜 (선택 사항) updatedAt 시스템 속성에 매핑됩니다.
버전 문자열 (선택 사항) 충돌을 감지하고 버전에 매핑하는 데 사용됩니다.

앱의 동기화 동작 변경

이 섹션에서는 앱 시작 시 또는 항목을 삽입하고 업데이트할 때 동기화되지 않도록 앱을 수정합니다. 새로 고침 제스처 단추가 수행될 때만 동기화됩니다.

Objective-C:

  1. QSTodoListViewController.mviewDidLoad 메서드를 변경하여 메서드 끝에 [self refresh] 호출을 제거합니다. 이제 데이터가 앱 시작 시 서버와 동기화되지 않습니다. 대신 로컬 저장소의 콘텐츠와 동기화됩니다.

  2. QSTodoService.m항목이 삽입된 후 동기화되지 않도록 addItem 정의를 수정합니다. self syncData 블록을 제거하고 다음으로 바꿉다.

    if (completion != nil) {
        dispatch_async(dispatch_get_main_queue(), completion);
    }
    
  3. 앞에서 설명한 대로 completeItem 정의를 수정합니다. self syncData 대한 블록을 제거하고 다음으로 바꿉다.

    if (completion != nil) {
        dispatch_async(dispatch_get_main_queue(), completion);
    }
    

Swift:

viewDidLoad, 의 ToDoTableViewController.swift파일에서 앱 시작 시 동기화를 중지하려면 여기에 표시된 두 줄의 코드를 주석 처리하세요. 이 문서를 작성할 때 Swift Todo 앱은 누군가가 항목을 추가하거나 완료할 때 서비스를 업데이트하지 않습니다. 앱 시작 시만 서비스를 업데이트합니다.

self.refreshControl?.beginRefreshing()
self.onRefresh(self.refreshControl)

앱 테스트

이 섹션에서는 잘못된 URL에 연결하여 오프라인 시나리오를 시뮬레이션합니다. 데이터 항목을 추가하면 로컬 Core Data 저장소에 보관되지만 모바일 앱 백 엔드와 동기화되지 않습니다.

  1. QSTodoService.m의 모바일 앱 URL 잘못된 URL로 변경하고 앱을 다시 실행합니다.

    Objective-C. QSTodoService.m에서:

    self.client = [MSClient clientWithApplicationURLString:@"https://sitename.azurewebsites.net.fail"];
    

    Swift. ToDoTableViewController.swift에서:

    let client = MSClient(applicationURLString: "https://sitename.azurewebsites.net.fail")
    
  2. 일부 to-do 항목을 추가합니다. 시뮬레이터를 종료하거나 강제로 앱을 닫은 다음 다시 시작합니다. 변경 내용이 지속되는지 확인합니다.

  3. 원격 TodoItem 테이블의 내용을 봅니다.

    • Node.js 백 엔드의 경우 Azure 포털로 이동한 후, 모바일 앱 백 엔드에서 Easy Tables>TodoItem을 클릭하세요.
    • .NET 백 엔드의 경우 SQL Server Management Studio와 같은 SQL 도구 또는 Fiddler 또는 Postman과 같은 REST 클라이언트를 사용합니다.
  4. 새 항목이 서버와 동기화되지 않았는지 확인합니다.

  5. QSTodoService.mURL을 올바른 URL로 다시 변경하고 앱을 다시 실행합니다.

  6. 항목 목록을 끌어서 새로 고침 제스처를 수행합니다.
    진행률 스피너가 표시됩니다.

  7. TodoItem 데이터를 다시 봅니다. 이제 새 항목과 변경된 to-do 항목이 표시됩니다.

요약

오프라인 동기화 기능을 지원하기 위해 MSSyncTable 인터페이스를 사용하고 로컬 저장소를 사용하여 MSClient.syncContext 초기화했습니다. 이 경우 로컬 저장소는 핵심 데이터 기반 데이터베이스였습니다.

Core Data 로컬 저장소를 사용하는 경우 올바른 시스템 속성을 사용하여 여러 테이블을 정의해야 합니다.

모바일 앱에 대한 일반적인 CRUD(만들기, 읽기, 업데이트 및 삭제) 작업은 앱이 여전히 연결된 것처럼 작동하지만 모든 작업은 로컬 저장소에 대해 발생합니다.

로컬 저장소를 서버와 동기화할 때 MSSyncTable.pullWithQuery 메서드를 사용했습니다.

추가 리소스