Programing

CoreData와 REST 웹 서비스를 비동기 적으로 동기화하는 방법과 동시에 모든 REST 오류를 UI에 적절하게 전파하는 방법

lottogame 2020. 9. 19. 11:54
반응형

CoreData와 REST 웹 서비스를 비동기 적으로 동기화하는 방법과 동시에 모든 REST 오류를 UI에 적절하게 전파하는 방법


안녕하세요, 저는 여기서 앱의 모델 레이어를 작업하고 있습니다.

일부 요구 사항은 다음과 같습니다.

  1. iPhone OS 3.0 이상에서 작동합니다.
  2. 데이터 소스는 RESTful Rails 애플리케이션입니다.
  3. Core Data를 사용하여 데이터를 로컬로 캐시해야합니다.
  4. 클라이언트 코드 (우리의 UI 컨트롤러)는 가능한 한 네트워크 관련 지식이 거의 없어야하며 Core Data API로 모델을 쿼리 / 업데이트해야합니다.

나는 체크 아웃 한 WWDC10 세션 (117) , 건물에에게 서버 기반의 사용자 경험을 체크 아웃 시간을 보냈다 목적 자원 , 핵심 자원RestfulCoreData의 프레임 워크를.

Objective Resource 프레임 워크는 자체적으로 Core Data와 통신하지 않으며 REST 클라이언트 구현 일뿐입니다. Core Resource 및 RestfulCoreData는 모두 코드에서 Core Data와 통신한다고 가정하고 모델 계층의 백그라운드에서 모든 기본 사항을 해결합니다.

지금까지는 모두 괜찮아 보였고 처음에는 Core Resource 또는 RestfulCoreData가 위의 모든 요구 사항을 다룰 것이지만 ... 둘 중 어느 것도 제대로 해결되지 않는 것 같은 몇 가지가 있습니다.

  1. 서버에 로컬 업데이트를 저장하는 동안 메인 스레드를 차단해서는 안됩니다.
  2. 저장 작업이 실패하면 오류가 UI에 전파되고 변경 사항이 로컬 Core Data 저장소에 저장되지 않아야합니다.

Core Resource는 - (BOOL)save:(NSError **)errorManaged Object Context 를 호출 할 때 서버에 대한 모든 요청을 발행 하므로 어떻게 든 서버에 대한 기본 요청의 올바른 NSError 인스턴스를 제공 할 수 있습니다. 그러나 저장 작업이 완료 될 때까지 호출 스레드를 차단합니다. 불합격.

RestfulCoreData는 -save:호출을 그대로 유지하고 클라이언트 스레드에 대한 추가 대기 시간을 도입하지 않습니다. 단지를 감시 NSManagedObjectContextDidSaveNotification한 다음 알림 처리기에서 서버에 해당 요청을 보냅니다. 그러나 이렇게하면 -save:호출이 항상 성공적으로 완료되고 (핵심 데이터가 저장된 변경 사항에 문제가없는 경우) 실제로 호출 한 클라이언트 코드는 저장을 알 수있는 방법이 없습니다. 일부 404또는 421그 밖의 이유로 인해 서버로 전파되지 않았을 수 있습니다. 서버 측 오류가 발생했습니다. 더욱이 로컬 스토리지는 데이터를 업데이트하지만 서버는 변경 사항을 알 수 없습니다. 불합격.

따라서 이러한 모든 문제를 처리 할 수있는 가능한 솔루션 / 일반적인 관행을 찾고 있습니다.

  1. -save:네트워크 요청이 발생하는 동안 호출 스레드가 각 호출 을 차단하는 것을 원하지 않습니다 .
  2. 어떻게 든 UI에서 일부 동기화 작업이 잘못되었다는 알림을 받고 싶습니다.
  3. 서버 요청이 실패하면 실제 Core Data 저장도 실패하고 싶습니다.

어떤 아이디어?


이 사용 사례에 대해서는 RestKit ( http://restkit.org )을 살펴 봐야 합니다. 원격 JSON 리소스를 모델링하고 로컬 Core Data 지원 캐시에 동기화하는 문제를 해결하도록 설계되었습니다. 사용 가능한 네트워크가 없을 때 캐시에서 완전히 작동하는 오프라인 모드를 지원합니다. 모든 동기화는 백그라운드 스레드 (네트워크 액세스, 페이로드 구문 분석 및 관리되는 개체 컨텍스트 병합)에서 발생하며 진행 상황을 알 수 있도록 풍부한 위임 메서드 집합이 있습니다.


세 가지 기본 구성 요소가 있습니다.

  1. UI 작업 및 CoreData에 대한 변경 유지
  2. 그 변화를 서버까지 유지
  3. 서버의 응답으로 UI 새로 고침

NSOperation + NSOperationQueue는 네트워크 요청을 순서대로 유지하는 데 도움이됩니다. 위임 프로토콜은 UI 클래스가 다음과 같이 네트워크 요청의 상태를 이해하는 데 도움이됩니다.

@protocol NetworkOperationDelegate
  - (void)operation:(NSOperation *)op willSendRequest:(NSURLRequest *)request forChangedEntityWithId:(NSManagedObjectID *)entity;
  - (void)operation:(NSOperation *)op didSuccessfullySendRequest:(NSURLRequest *)request forChangedEntityWithId:(NSManagedObjectID *)entity;
  - (void)operation:(NSOperation *)op encounteredAnError:(NSError *)error afterSendingRequest:(NSURLRequest *)request forChangedEntityWithId:(NSManagedObjectID *)entity;
@end

프로토콜 형식은 물론 특정 사용 사례에 따라 다르지만 기본적으로 만드는 것은 변경 사항을 서버에 "푸시"할 수있는 메커니즘입니다.

다음으로 고려해야 할 UI 루프가 있습니다. 코드를 깔끔하게 유지하려면 save :를 호출하는 것이 좋을 것입니다. 변경 사항이 자동으로 서버에 푸시됩니다. 이를 위해 NSManagedObjectContextDidSave 알림을 사용할 수 있습니다.

- (void)managedObjectContextDidSave:(NSNotification *)saveNotification {
  NSArray *inserted = [[saveNotification userInfo] valueForKey:NSInsertedObjects];
  for (NSManagedObject *obj in inserted) {
    //create a new NSOperation for this entity which will invoke the appropraite rest api
    //add to operation queue
  }

  //do the same thing for deleted and updated objects
}

The computational overhead for inserting the network operations should be rather low, however if it creates a noticeable lag on the UI you could simply grab the entity ids out of the save notification and create the operations on a background thread.

If your REST API supports batching, you could even send the entire array across at once and then notify you UI that multiple entities were synchronized.

The only issue I foresee, and for which there is no "real" solution is that the user will not want to wait for their changes to be pushed to the server to be allowed to make more changes. The only good paradigm I have come across is that you allow the user to keep editing objects, and batch their edits together when appropriate, i.e. you do not push on every save notification.


This becomes a sync problem and not one easy to solve. Here's what I'd do: In your iPhone UI use one context and then using another context (and another thread) download the data from your web service. Once it's all there go through the sync/importing processes recommended below and then refresh your UI after everything has imported properly. If things go bad while accessing the network, just roll back the changes in the non UI context. It's a bunch of work, but I think it's the best way to approach it.

Core Data: Efficiently Importing Data

Core Data: Change Management

Core Data: Multi-Threading with Core Data


You need a callback function that's going to run on the other thread (the one where actual server interaction happens) and then put the result code/error info a semi-global data which will be periodically checked by UI thread. Make sure that the wirting of the number that serves as the flag is atomic or you are going to have a race condition - say if your error response is 32 bytes you need an int (whihc should have atomic acces) and then you keep that int in the off/false/not-ready state till your larger data block has been written and only then write "true" to flip the switch so to speak.

For the correlated saving on the client side you have to either just keep that data and not save it till you get OK from the server of make sure that you have a kinnf of rollback option - say a way to delete is server failed.

Beware that it's never going to be 100% safe unless you do full 2-phase commit procedure (client save or delete can fail after the signal from the server server) but that's going to cost you 2 trips to the server at the very least (might cost you 4 if your sole rollback option is delete).

Ideally, you'd do the whole blocking version of the operation on a separate thread but you'd need 4.0 for that.

참고URL : https://stackoverflow.com/questions/3077444/how-to-sync-coredata-and-a-rest-web-service-asynchronously-and-the-same-time-pro

반응형