iPhone Core 데이터를 웹 서버와 동기화 한 다음 다른 장비로 푸시하는 방법은 무엇입니까? [닫은]


293

나는 iPhone 응용 프로그램에 저장된 핵심 데이터를 iPad 또는 Mac과 같은 여러 장치간에 동기화하는 방법을 연구하고 있습니다. iOS의 Core Data와 함께 사용할 동기화 프레임 워크가 많지 않습니다 (있는 경우). 그러나 나는 다음 개념에 대해 생각하고있다.

  1. 로컬 코어 데이터 저장소가 변경되고 변경 사항이 저장됩니다. (a) 장치가 온라인 상태 인 경우 변경 세트를 보낸 장치의 장치 ID를 포함하여 변경 세트를 서버로 보내려고합니다. (b) 변경 세트가 서버에 도달하지 않거나 장치가 온라인이 아닌 경우 앱은 변경 세트를 대기열에 추가하여 온라인 상태가 될 때 전송합니다.
  2. 클라우드에있는 서버는 수신 한 특정 변경 세트를 마스터 데이터베이스와 병합합니다.
  3. 클라우드 서버에서 변경 세트 (또는 변경 세트 큐)를 병합 한 후 서버는 이러한 변경 세트를 모두 일종의 폴링 시스템을 사용하여 서버에 등록 된 다른 장치로 푸시합니다. (나는 Apple의 Push 서비스를 사용하려고 생각했지만 분명히 의견에 따르면 이것은 실행 가능한 시스템이 아닙니다.)

내가 생각해야 할 멋진 것이 있습니까? ObjectiveResource , Core ResourceRestfulCoreData 와 같은 REST 프레임 워크를 살펴 보았습니다 . 물론, 이것들은 모두 Ruby on Rails와 함께 작동하지만, 나는 묶이지 않았지만 시작해야 할 곳입니다. 내 솔루션에 필요한 주요 요구 사항은 다음과 같습니다.

  1. 메인 스레드를 일시 중지하지 않고 변경 사항을 백그라운드로 보내야합니다.
  2. 가능한 적은 대역폭을 사용해야합니다.

나는 많은 도전에 대해 생각했다 :

  1. 다른 장치의 다른 데이터 저장소에 대한 오브젝트 ID가 서버에 연결되어 있는지 확인하십시오. 즉, 데이터베이스에 저장된 개체에 대한 참조를 통해 연결된 개체 ID 및 장치 ID 테이블을 갖게됩니다. 레코드 (DatabaseId [이 테이블에 고유], ObjectId [전체 데이터베이스의 항목에 고유], Datafield1, Datafield2)를 가지며 ObjectId 필드는 다른 테이블 인 AllObjects : (ObjectId, DeviceId, DeviceObjectId)를 참조합니다. 그런 다음 장치가 변경 세트를 푸시하면 로컬 데이터 저장소의 핵심 데이터 개체에서 장치 ID와 objectId를 전달합니다. 그런 다음 내 클라우드 서버는 AllObjects 테이블에서 objectId 및 장치 ID를 확인하고 초기 테이블에서 변경할 레코드를 찾습니다.
  2. 모든 변경 사항은 타임 스탬프되어야 병합 할 수 있습니다.
  3. 장치는 너무 많은 배터리를 사용하지 않고 서버를 폴링해야합니다.
  4. 로컬 장치는 또한 서버에서 변경 사항을 수신 할 때 메모리에 보관 된 내용을 업데이트해야합니다.

여기서 누락 된 것이 있습니까? 이를 가능하게하기 위해 어떤 종류의 프레임 워크를 살펴 봐야합니까?


5
푸시 알림 수신에 의존 할 수 없습니다. 사용자는 간단히 터치하여 두 번째 알림이 도착하면 OS가 첫 번째 알림을 버립니다. IMO 푸시 알림은 사용자를 방해하기 때문에 동기화 업데이트를받는 나쁜 방법입니다. 앱은 시작될 때마다 동기화를 시작해야합니다.
Ole Begemann

확인. 서버를 지속적으로 폴링하고 시작시 업데이트를 확인하는 것 외에는 정보를 주셔서 감사합니다. 장치가 업데이트를받을 수있는 방법이 있습니까? 앱이 여러 장치에서 동시에 열려 있으면 작동하도록하고 싶습니다.
Jason

1
(나는 조금 늦게 알고 있지만 누군가가 이것을 발견하고 궁금해하는 경우를 대비하여) 여러 장치를 동시에 동기화하려면 다른 장치 또는 서버와의 열린 연결을 유지하고 다른 장치에 알리는 메시지를 보낼 수 있습니다 ) 업데이트가 발생할 때 (예 : IRC / 인스턴트 메시징 작동 방식)
Dan2552

1
@ Dan2552 : 당신이 묘사하는 것은 [long polling] [ en.wikipedia.org/wiki/… 로 알려져 있으며 훌륭한 연결이지만 오픈 연결은 모바일 장치에서 많은 배터리와 대역폭을 소비합니다.
johndodo

1
Ray Wenderlich의 앱과 웹 서비스 간 데이터 동기화 방법에 대한 유용한 자습서는 다음과 같습니다. raywenderlich.com/15916/…
JRG-Developer

답변:


144

Dan Grover가 iPhone 2009 컨퍼런스에서 논의한 동기화 전략을주의 깊게 읽고 구현하는 것이 좋습니다 . 여기 에서 pdf 문서로 제공됩니다.

이것은 실행 가능한 솔루션이며 Chris가 설명 한 솔루션과 겹치기 때문에 구현하기가 어렵지 않습니다 (Dan은 여러 응용 프로그램에서 이것을 구현했습니다). 동기화에 대한 심층적이고 이론적 인 토론은 MIT (Russ Cox)와 프린스턴 (Princeton)의 William Josephson의 논문을 참조하십시오.

벡터 시간 쌍을 사용한 파일 동기화

이는 명백히 수정 된 핵심 데이터에도 동일하게 적용됩니다. 이는 전반적으로 훨씬 강력하고 안정적인 동기화 전략을 제공하지만 올바르게 구현하려면 더 많은 노력이 필요합니다.

편집하다:

Grover의 pdf 파일을 더 이상 사용할 수없는 것 같습니다 (깨진 링크, 2015 년 3 월). 업데이트 : 링크는 웨이 백 머신을 통해 볼 수 있습니다 여기에

iCloud가 마침내 올바른 핵심 데이터 동기화를 지원하는 것으로 보이므로 ZSync 라는 Objective-C 프레임 워크 및 Marcus Zarra가 개발했습니다.


ZSync 비디오에 대한 업데이트 된 링크가 있습니까? 또한 ZSync는 계속 유지됩니까? 나는 지난 2010 년에 갱신 된 참조
제레미 Weldin을

github에 대한 ZSync의 마지막 커밋은 2010 년 9 월에 이루어졌으며 Marcus가 지원을 중단했다고 믿게되었습니다.
부패하기 쉬운 Dave

1
Dan Grover가 설명한 알고리즘이 매우 좋습니다. 그러나 새로운 업데이트를 확인하는 데 시간이 사용될 때 클라이언트가 업데이트를 놓치지 않도록 할 수있는 방법이 없기 때문에 멀티 스레드 서버 코드 (따라서 이것이 전혀 확장되지 않음)에서는 작동하지 않습니다. . 내가 틀렸다면 제발 수정하십시오. 작동하는 구현을보기 위해 죽일 것입니다.
masi

1
@Patt, 요청하신대로 pdf 파일을 보냈습니다. Massimo Cafaro, 건배
Massimo Cafaro

3
Dan Grover 의 누락 된 크로스 플랫폼 데이터 동기화 PDF 슬라이드는 Wayback Machine을 통해 액세스 할 수 있습니다.
Matthew Kairys

272

나는 당신이하려는 것과 비슷한 일을했습니다. 내가 배운 것과 내가 어떻게했는지 알려 드리겠습니다.

코어 데이터 객체와 서버의 모델 (또는 db 스키마) 사이에 일대일 관계가 있다고 가정합니다. 서버 내용을 클라이언트와 동기화 된 상태로 유지하려고하지만 클라이언트가 데이터를 수정하고 추가 할 수도 있습니다. 내가 그 권리를 얻는다면 계속 읽으십시오.

동기화를 돕기 위해 4 개의 필드를 추가했습니다.

  1. sync_status- 이 필드를 코어 데이터 모델에만 추가하십시오. 앱에서 항목에 보류중인 변경 사항이 있는지 확인하는 데 사용됩니다. 다음 코드를 사용합니다. 0은 변경이 없음을 의미하고 1은 서버와 동기화되도록 대기 중임을 의미하고 2는 임시 개체이므로 제거 할 수 있음을 의미합니다.
  2. is_deleted- 서버 및 코어 데이터 모델에 추가하십시오. Delete 이벤트는 데이터베이스 또는 클라이언트 모델에서 실제로 행을 삭제해서는 안됩니다. 다시 동기화 할 항목이 없기 때문입니다. 이 간단한 부울 플래그를 사용하여 is_deleted를 1로 설정하고 동기화하면 모든 사람이 행복해질 것입니다. 또한 "is_deleted = 0"으로 삭제되지 않은 항목을 쿼리하도록 서버와 클라이언트의 코드를 수정해야합니다.
  3. last_modified- 서버 및 코어 데이터 모델에 추가하십시오. 이 필드는 레코드에서 변경 될 때마다 서버에 의해 현재 날짜 및 시간으로 자동 업데이트됩니다. 클라이언트가 절대 수정해서는 안됩니다.
  4. guid- 서버 및 코어 데이터 모델에 글로벌 고유 ID ( http://en.wikipedia.org/wiki/Globally_unique_identifier 참조 ) 필드를 추가하십시오 . 이 필드는 기본 키가되며 클라이언트에서 새 레코드를 작성할 때 중요합니다. 일반적으로 기본 키는 서버에서 증가하는 정수이지만 컨텐츠를 오프라인에서 작성하고 나중에 동기화 할 수 있음을 명심해야합니다. GUID를 사용하면 오프라인 상태에서 키를 만들 수 있습니다.

클라이언트에서 변경 사항이 있거나 서버와 동기화해야 할 때마다 모델 오브젝트에서 sync_status를 1로 설정하는 코드를 추가하십시오. 새 모델 객체는 GUID를 생성해야합니다.

동기화는 단일 요청입니다. 요청에는 다음이 포함됩니다.

  • 모델 객체의 MAX last_modified 타임 스탬프 이렇게하면이 타임 스탬프 이후에만 변경을 원한다는 것을 서버에 알립니다.
  • sync_status = 1 인 모든 항목을 포함하는 JSON 배열입니다.

서버는 요청을 받고 다음을 수행합니다.

  • JSON 배열에서 내용을 가져 와서 포함하는 레코드를 수정하거나 추가합니다. last_modified 필드가 자동으로 업데이트됩니다.
  • 서버는 요청에서 전송 된 타임 스탬프보다 last_modified 타임 스탬프가 큰 모든 객체가 포함 된 JSON 배열을 반환합니다. 여기에는 방금받은 개체가 포함되며 레코드가 서버에 성공적으로 동기화되었다는 확인의 역할을합니다.

앱이 응답을 수신하고 다음을 수행합니다.

  • JSON 배열에서 내용을 가져 와서 포함하는 레코드를 수정하거나 추가합니다. 각 레코드는 sync_status를 0으로 설정합니다.

도움이 되길 바랍니다. 레코드와 모델이라는 단어를 서로 바꿔서 사용했지만 아이디어가 있다고 생각합니다. 행운을 빕니다.


2
last_modified 필드는 로컬 데이터베이스에도 있지만 iPhone 시계에 의해 업데이트되지 않습니다. 서버에 의해 설정되고 다시 동기화됩니다. MAX (last_modified) 날짜는 앱이 해당 날짜 이후 수정 된 모든 것을 다시 보내도록 서버에 보내는 날짜입니다.
chris

3
클라이언트의 전역 값은을 대체 할 수 MAX(last_modified)있지만 MAX(last_modified)충분 하므로 중복 됩니다. 는 sync_status다른 역할을한다. 앞서 MAX(last_modified)언급 했듯이 서버와 sync_status동기화해야 할 대상 을 결정 하고 서버와 동기화해야 할 대상 을 결정합니다.
chris

2
@Flex_Addicted 감사합니다. 예, 동기화하려는 각 엔티티에 대한 필드를 복제해야합니다. 그러나 모델을 관계 (예 : 일대 다)와 동기화 할 때는 더주의해야합니다.
chris

2
@ BenPackard-맞습니다. 이 접근법은 충돌 해결을 수행하지 않으므로 마지막 클라이언트가 승리합니다. 레코드가 단일 사용자에 의해 편집되므로 앱에서이 문제를 처리하지 않아도됩니다. 이 문제를 어떻게 해결하는지 궁금합니다.
chris

2
@noilly 님, 다음 경우를 고려하십시오. 로컬 객체를 변경하고 서버와 다시 동기화해야합니다. 동기화는 몇 시간 또는 며칠 후에 (예 : 오프라인 상태 인 경우) 발생할 수 있으며이 시간에 앱이 종료되고 몇 번 다시 시작되었을 수 있습니다. 이 경우 NSManagedObjectContext의 메소드는별로 도움이되지 않습니다.
chris

11

여전히 갈 길을 찾고 있다면 Couchbase 모바일을 살펴보십시오. 이것은 기본적으로 당신이 원하는 모든 것을합니다. ( http://www.couchbase.com/nosql-databases/couchbase-mobile )


3
관계형 데이터가 아닌 문서로 데이터를 표현할 수있는 경우에만 원하는 작업을 수행합니다. 해결 방법이 있지만 항상 예쁘거나 가치있는 것은 아닙니다.
Jeremie Weldin

소규모 어플리케이션에 적합한 문서
Hai Feng Kao

@radiospiel 링크가 깨졌습니다
Mick

또한 백엔드를 Couchbase DB로 작성해야하는 종속성이 추가됩니다. 심지어 동기화를 위해 NOSQL이라는 아이디어로 시작했지만 백엔드에서 MS SQL을 실행하므로 백엔드를 NOSQL로 제한 할 수 없습니다.
thesummersign

@Mick : 다시 작동하는 것 같습니다 (또는 누군가가 링크를 수정 했습니까? 감사합니다)
radiospiel

7

@Cris와 비슷하게 클라이언트와 서버 간의 동기화를 위해 클래스를 구현했으며 지금까지 알려진 모든 문제를 해결했습니다 (서버와 데이터를주고 받거나 타임 스탬프를 기반으로 충돌을 병합하고 신뢰할 수없는 네트워크 조건에서 중복 항목을 제거하고 중첩 된 데이터를 동기화하고 파일 등 ..)

클래스에 어떤 엔티티와 어떤 컬럼을 동기화해야하며 서버가 어디에 있는지 알려 주기만하면됩니다.

M3Synchronization * syncEntity = [[M3Synchronization alloc] initForClass: @"Car"
                                                              andContext: context
                                                            andServerUrl: kWebsiteUrl
                                             andServerReceiverScriptName: kServerReceiverScript
                                              andServerFetcherScriptName: kServerFetcherScript
                                                    ansSyncedTableFields:@[@"licenceNumber", @"manufacturer", @"model"]
                                                    andUniqueTableFields:@[@"licenceNumber"]];


syncEntity.delegate = self; // delegate should implement onComplete and onError methods
syncEntity.additionalPostParamsDictionary = ... // add some POST params to authenticate current user

[syncEntity sync];

github.com/knagode/M3Synchronization 에서 소스, 실제 예제 및 추가 지침을 찾을 수 있습니다 .


장치 시간을 비정상 값으로 변경해도 괜찮습니까?
Golden

5

푸시 알림을 통해 데이터를 업데이트하도록 사용자에게 알립니다. 앱에서 백그라운드 스레드를 사용하여 클라우드 서버에서 로컬 데이터 및 데이터를 확인하고 서버에서 변경이 발생하는 동안 로컬 데이터를 변경하거나 그 반대로 변경하십시오.

따라서 가장 어려운 부분은 어느 쪽이 무효화되는지를 추정하는 것입니다.

이것이 당신을 도울 수 있기를 바랍니다.


5

방금 SynCloud라고하는 새로운 Core Data Cloud Syncing API의 첫 번째 버전을 게시했습니다. SynCloud는 다중 사용자 동기화 인터페이스를 허용하므로 iCloud와 많은 차이점이 있습니다. 다중 테이블 관계형 데이터를 허용하기 때문에 다른 동기화 API와 다릅니다.

http://www.syncloudapi.com 에서 자세한 내용을 확인하십시오.

iOS 6 SDK로 빌드하면 2012 년 9 월 27 일 현재 최신 상태입니다.


5
스택 오버플로에 오신 것을 환영합니다! 답변을 게시 해 주셔서 감사합니다! 자체 프로모션에 대한 FAQ를 주의 깊게 읽으십시오 .
Andrew Barber

5

GUID 문제에 대한 좋은 해결책은 "분산 ID 시스템"이라고 생각합니다. 올바른 용어가 무엇인지 잘 모르겠지만 MS SQL 서버 문서가 그것을 호출하는 데 사용한 것입니다 (SQL은 분산 / 동기화 데이터베이스 에이 방법을 사용 / 사용했습니다). 꽤 간단합니다.

서버는 모든 ID를 할당합니다. 동기화가 완료 될 때마다 가장 먼저 확인되는 것은 "이 클라이언트에 몇 개의 ID가 남아 있습니까?"입니다. 클라이언트가 부족한 경우 서버에 새 ID 블록을 요청합니다. 그런 다음 클라이언트는 새 레코드에 해당 범위의 ID를 사용합니다. 다음 동기화 이전에 "절대로"실행되지 않을 정도로 큰 블록을 할당 할 수 있지만 시간이지나면서 서버가 부족할 정도로 큰 블록을 할당 할 수없는 경우 대부분의 요구에 적합합니다. 클라이언트가 부족한 경우 처리가 매우 간단 할 수 있습니다. 사용자에게 "동기화 할 때까지 더 이상 항목을 추가 할 수 없습니다"라고 말하십시오. 많은 항목을 추가하는 경우 오래된 데이터를 피하기 위해 동기화하지 않아야 어쨌든 문제?

임의 GUID는 100 % 안전하지 않으며 일반적으로 표준 ID (128 비트 대 32 비트)보다 훨씬 길어야하기 때문에 이것이 임의 GUID를 사용하는 것보다 우수하다고 생각합니다. 일반적으로 ID별로 색인이 있으며 종종 ID 번호를 메모리에 유지하므로 작게 유지하는 것이 중요합니다.

실제로 답변으로 게시하고 싶지는 않았지만 누구나 의견으로 볼 수 있다는 것을 모르겠습니다.이 주제에 중요하며 다른 답변에는 포함되지 않는다고 생각합니다.


2

먼저 얼마나 많은 데이터, 테이블 및 관계가 있는지 다시 생각해야합니다. 내 솔루션에서 Dropbox 파일을 통한 동기화를 구현했습니다. 주 MOC의 변경 사항을 관찰하고 이러한 데이터를 파일에 저장합니다 (각 행은 gzipped json으로 저장 됨). 인터넷 연결이 작동하는 경우 Dropbox에 변경 사항이 있는지 확인하고 (Dropbox에서 델타 변경 사항을 제공함) 다운로드하여 병합 (최신 승리) 한 다음 마지막으로 변경된 파일을 넣습니다. 동기화하기 전에 다른 클라이언트가 불완전한 데이터를 동기화하지 못하도록 Dropbox에 잠금 파일을 넣었습니다. 다운로드 변경시 부분 데이터 만 다운로드하는 것이 안전합니다 (예 : 인터넷 연결 끊김). 다운로드가 완료되면 (전체 또는 부분) 파일을 Core Data로로드하기 시작합니다. 해결되지 않은 관계가있는 경우 (모든 파일이 다운로드되는 것은 아님) 파일로드를 중지하고 나중에 다운로드를 완료하려고합니다. 관계는 GUID로만 ​​저장되므로 전체 데이터 무결성을 위해로드 할 파일을 쉽게 확인할 수 있습니다. 코어 데이터를 변경 한 후 동기화가 시작됩니다. 변경 사항이없는 경우 몇 분마다 및 앱 시작시 Dropbox의 변경 사항을 확인합니다. 또한 변경 사항이 서버로 전송되면 변경 사항을 알리기 위해 다른 장치로 브로드 캐스트를 보내서 더 빨리 동기화 할 수 있습니다. 동기화 된 각 엔티티에는 GUID 특성이 있습니다 (guid는 교환 파일의 파일 이름으로도 사용됨). 또한 각 파일의 Dropbox 개정판을 저장하는 Sync 데이터베이스가 있습니다 (Dropbox 델타가 상태를 재설정 할 때 비교할 수 있습니다). 파일에는 엔티티 이름, 상태 (삭제 / 삭제되지 않음), guid (파일 이름과 동일), 데이터베이스 개정 (데이터 마이그레이션을 감지하거나 절대 앱 버전과의 동기화를 피하기 위해) 및 물론 데이터 (행이 삭제되지 않은 경우)가 포함됩니다. 전체 데이터 무결성을 위해로드 할 파일을 쉽게 확인할 수 있습니다. 코어 데이터를 변경 한 후 동기화가 시작됩니다. 변경 사항이없는 경우 몇 분마다 및 앱 시작시 Dropbox의 변경 사항을 확인합니다. 또한 변경 사항이 서버로 전송되면 변경 사항을 알리기 위해 다른 장치로 브로드 캐스트를 보내서 더 빨리 동기화 할 수 있습니다. 동기화 된 각 엔티티에는 GUID 특성이 있습니다 (guid는 교환 파일의 파일 이름으로도 사용됨). 또한 각 파일의 Dropbox 개정판을 저장하는 Sync 데이터베이스가 있습니다 (Dropbox 델타가 상태를 재설정 할 때 비교할 수 있습니다). 파일에는 엔티티 이름, 상태 (삭제 / 삭제되지 않음), guid (파일 이름과 동일), 데이터베이스 개정 (데이터 마이그레이션을 감지하거나 절대 앱 버전과의 동기화를 피하기 위해) 및 물론 데이터 (행이 삭제되지 않은 경우)가 포함됩니다. 전체 데이터 무결성을 위해로드 할 파일을 쉽게 확인할 수 있습니다. 코어 데이터를 변경 한 후 동기화가 시작됩니다. 변경 사항이없는 경우 몇 분마다 및 앱 시작시 Dropbox의 변경 사항을 확인합니다. 또한 변경 사항이 서버로 전송되면 변경 사항을 알리기 위해 다른 장치로 브로드 캐스트를 보내서 더 빨리 동기화 할 수 있습니다. 동기화 된 각 엔티티에는 GUID 특성이 있습니다 (guid는 교환 파일의 파일 이름으로도 사용됨). 또한 각 파일의 Dropbox 개정판을 저장하는 Sync 데이터베이스가 있습니다 (Dropbox 델타가 상태를 재설정 할 때 비교할 수 있습니다). 파일에는 엔티티 이름, 상태 (삭제 / 삭제되지 않음), guid (파일 이름과 동일), 데이터베이스 개정 (데이터 마이그레이션을 감지하거나 절대 앱 버전과의 동기화를 피하기 위해) 및 물론 데이터 (행이 삭제되지 않은 경우)가 포함됩니다.

이 솔루션은 수천 개의 파일과 약 30 개의 엔티티에서 작동합니다. Dropbox 대신 키 / 값 저장소를 REST 웹 서비스로 나중에 사용할 수는 있지만 시간이 없습니다.) 현재로서는 내 솔루션은 iCloud보다 안정적이며 매우 중요합니다. 작동 방식을 완벽하게 제어 할 수 있습니다 (주로 내 코드이기 때문에).

또 다른 솔루션은 MOC 변경 사항을 트랜잭션으로 저장하는 것입니다. 서버와 교환되는 파일이 훨씬 적지 만 빈 코어 데이터에 적절한 순서로 초기로드를 수행하는 것이 더 어렵습니다. iCloud는 이런 방식으로 작동하고 있으며 다른 동기화 솔루션에도 유사한 접근 방식이 있습니다 (예 : TICoreDataSync) .

-업데이트

잠시 후, 나는 Ensembles 로 이주했습니다 -바퀴를 재발 명하는 것 보다이 솔루션을 권장합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.