ios - How can I guarantee unique entries in a Core Data store in a shared app container used by both the host app and an extension? -


to ask question effectively, let's first consider exact scenario i'm facing:

general setup

  • a host ios 8 app.
  • one or more ios 8 extensions (watchkit, share, etc.) bundled host app.
  • the host app , extensions share same core data sqlite store in shared app group container.
  • each app/extension has own nspersistentstorecoordinator , nsmanagedobjectcontext.
  • each persistent store coordinator uses persistent store shares same sqlite resources in group container other persistent stores.
  • the app , extensions use common codebase syncing content remote api resource on internet.

sequence of events leading problem

  1. the user launches host app. begins fetching data remote api resource. core data model objects created based on api response , "upserted" host app's managed object context. each api entity has uniqueid identifies in remote api backend. "upsert," mean each api entity, host app creates new entry in core data if existing entry given uniqueid cannot found.

  2. meanwhile, user launches 1 of host app's extensions. it, too, performs kind of fetch same remote api. attempts perform "upsert" when parsing api responses.

  3. the problem: happens if both host app , extension try upsert core data entry same api entity @ same time? see how come about, let's @ sequence of events upsert:

core data upsert sequence:

  1. the api parsing code parses uniqueid given api entity.
  2. the parser performs core data fetch entry matches predicate uniqueid equal parsed uniqueid.
  3. if existing entry not found, parser inserts new core data entry api entity, set's uniqueid attribute parsed uniqueid.
  4. the parser saves managed object context, pushes new entry data down sqlite backing store.

problem in detail

let's assume host app , extension independently parsing api response same api entity @ same time. if both host app , extension reach step 3 before either of them has finished step 4, both trying insert new core data entry same uniqueid. when reach step 4 , call save: on respective managed object contexts, core data happily create duplicate entries.

as far i'm aware, core data doesn't have way mark attribute unique. need core data equivalent sqlite insert or ignore + update combo.. or else need way "lock" persistent store's sqlite backing store, sounds recipe trouble.

is there known approach rather novel problem introduced ios 8 extensions?

is there known approach rather novel problem introduced ios 8 extensions?

yes, it's same approach applies when using icloud core data: let duplicates happen, go , clean them up. both situations run risk of creating duplicate entries, , there's no reliable way prevent them. since have uniqueid key, you're in shape far concerned.

it lot easier, dave delong notes, avoid problem in first place. if that's impossible, can deal it, work.

finding duplicates like:

nserror *error = nil; nsmanagedobjectcontext *moc = [[nsmanagedobjectcontext alloc] init]; [moc setpersistentstorecoordinator:self.persistentstorecoordinator];  nsfetchrequest *fr = [[nsfetchrequest alloc] initwithentityname:@"myentityname"]; [fr setincludespendingchanges:no];  nsexpression *countexpr = [nsexpression expressionwithformat:@"count:(uniqueid)"]; nsexpressiondescription *countexprdesc = [[nsexpressiondescription alloc] init]; [countexprdesc setname:@"count"]; [countexprdesc setexpression:countexpr]; [countexprdesc setexpressionresulttype:nsinteger64attributetype];  nsattributedescription *uniqueidattr = [[[[[_psc managedobjectmodel] entitiesbyname] objectforkey:@"myentityname"] propertiesbyname] objectforkey:@"uniqueid"]; [fr setpropertiestofetch:[nsarray arraywithobjects:uniqueidattr, countexprdesc, nil]]; [fr setpropertiestogroupby:[nsarray arraywithobject:uniqueidattr]];  [fr setresulttype:nsdictionaryresulttype];  nsarray *countdictionaries = [moc executefetchrequest:fr error:&error]; 

this pretty core data equivalent of in sql:

select uniqueid, count(uniqueid) myentityname group uniqueid; 

you array of dictionaries, each of contains uniqueid , count of number of times value used. run through dictionary , deal duplicates appropriately.

i described in more detail in a blog post. there's sample project apple demonstrates process, called sharedcoredata, believe it's available part of wwdc 2012 sample code bundle. described in session 227 @ conference.


Comments

Popular posts from this blog

java - Oracle EBS .ClassNotFoundException: oracle.apps.fnd.formsClient.FormsLauncher.class ERROR -

c# - how to use buttonedit in devexpress gridcontrol -

nvd3.js - angularjs-nvd3-directives setting color in legend as well as in chart elements -