objective c - CoreData, child MOC on separate thread, unexpected: error: NULL _cd_rawData but the object is not being turned into a fault -


ok, im bit lost one, trying run background core data operation using second managedobjectcontext type set nsprivatequeueconcurrencytype , failing miserably above error.

i have custom subclass of nsoperation, being passed nsarray of strings, , persistentstorecoordinator main thread, creates own managedobjectcontext, runs query , performs , operation.

here code class:

// //  processprofanity.m //  hashtag live desktop // //  created gareth jeanne on 24/03/2014. //  copyright (c) 2014 gareth jeanne. rights reserved. //  #import "processprofanity.h" #import "tweet.h"  static const int importbatchsize = 250;  @interface processprofanity () @property (nonatomic, copy) nsarray* badwords; @property (nonatomic, strong) nsmanagedobjectcontext* backgroundcontext; @property (nonatomic, strong) nspersistentstorecoordinator* persistentstorecoordinator; @end  @implementation processprofanity   {  }   - (id)initwithstore:(nspersistentstorecoordinator*)store badwords:(nsarray*)words { self = [super init]; if(self) {     self.persistentstorecoordinator = store;     self.badwords = words; } return self; }   - (void)main { _backgroundcontext = [[nsmanagedobjectcontext alloc] initwithconcurrencytype:nsprivatequeueconcurrencytype]; _backgroundcontext.persistentstorecoordinator = [self persistentstorecoordinator]; _backgroundcontext.undomanager = nil; [_backgroundcontext performblockandwait:^ {     [self import]; }]; }  - (void)import {  //create new fetch request nsfetchrequest *request = [[nsfetchrequest alloc] init];  //setup request [request setentity:[nsentitydescription entityforname:@"tweet" inmanagedobjectcontext:self.backgroundcontext]];  nserror *error = nil;  //create array returned objects nsarray* tweetstoprocess = [self.backgroundcontext executefetchrequest:request error:&error]; nsassert2(tweetstoprocess != nil && error == nil, @"error fetching events: %@\n%@", [error localizeddescription], [error userinfo]);  (tweet* tweettocheck in tweetstoprocess){     __block nsstring *result = nil;     [self.badwords indexofobjectwithoptions:nsenumerationconcurrent                                    passingtest:^(nsstring *obj, nsuinteger idx, bool *stop)      {          if (tweettocheck){              if ([tweettocheck.text rangeofstring:obj].location != nsnotfound)              {                  result = obj;                  *stop = yes;                  //return yes;              }          }          return no;      }];      if (!result){         //ddlogverbose(@"the post not contain of words naughty list");         if(tweettocheck){             tweettocheck.profanity = [nsnumber numberwithbool:false];         }     }     else{         if(tweettocheck){             //ddlogverbose(@"the string contains '%@' the naughty list", result);             tweettocheck.profanity = [nsnumber numberwithbool:true];         }     }  } [self.backgroundcontext save:null]; } 

@end

and how calling it:

-(void)checkforprofanity{  if(!self.operationqueue){ self.operationqueue = [[nsoperationqueue alloc] init]; }  nsarray* termstopass = [self.filterterms copy]; processprofanity* operation = [[processprofanity alloc] initwithstore:self.persistentstorecoordinator badwords:termstopass]; [self.operationqueue addoperation:operation];   } 

edit 1

the specific line seem getting error on, or @ least xcode breaking is:

if ([tweettocheck.text rangeofstring:obj].location != nsnotfound) 

i have managed narrow down bit, nsarray contains list of terms search strings potentially quite large, possibly on 1,000 nsstrings. if test array of size, issue. if reduce array around 15 nsstrings, not error, don't think thread related issue, i'm wondering if array getting released in main thread. have modified code make deep copy, , __block copy follows, doesn't seem have helped.

self.badwords = [[nsarray alloc] initwitharray:words copyitems:yes]; 

and

for (tweet* tweettocheck in tweetstoprocess){     __block nsarray *array = [[nsarray alloc] initwitharray:self.badwords copyitems:yes];     __block nsstring *result = nil;     [array indexofobjectwithoptions:nsenumerationconcurrent 

in fact, @ point xcode breaks, if po array, object not found message, if po result, correct object returned nil.

edit 2

so have made following changes, no change:

made nsarray strong rather copy:

@property (nonatomic, strong) nsarray* badwords; 

and made copy when allocated:

self.badwords = [[nsarray alloc] initwitharray:words copyitems:yes]; 

and created local copy of nsarray ___block declaration inside actual method processing objects:

__block nsarray *array = [[nsarray alloc] initwitharray:self.badwords copyitems:yes]; 

which should surely mean sticks around life of processprofanity object?

am wrong in expecting able po array breakpoint within block?

in instance error message "error: null _cd_rawdata object not being turned fault" indicates accessing managed object outside of context. fetch returns tweets persistent store faults. once try , access property on managed object, core data fire fault , fetch full object store.

by calling nsarray method indexofobjectwithoptions:passingtest: option of nsenumerationconcurrent implying want perform asynchronous execution on elements in array. keyword concurrent indicates multiple threads can used operate on array elements.

in context means accessing managed object inside block might result in accessing on different thread managed object context owns object. when access tweettocheck.text in conditional check - if ([tweettocheck.text rangeofstring:obj].location != nsnotfound), under hood core data fetching managed object persistent store , returning thread not part of managed object contexts thread.

furthermore, not necessary use method indexofobjectwithoptions:passingtest: since not interested in result of operation.

it seems me might more convenient use nsset testing see whether or not given tweet word exists in profane words. quoting documentation nsset: "you can use sets alternative arrays when order of elements isn’t important , performance in testing whether object contained in set consideration". seems meet criteria.

so init like:

 -(id)initwithstore:(nspersistentstorecoordinator*)store             badwords:(nsset*)badwords {    self = [super init];    if(self) {      self.persistentstorecoordinator = store;      self.badwords = [words copy];    }    return self; } 

since interested in updating tweets have not yet been tagged profanity want fetch tweets haven't been flagged profane:

//create new fetch request nsfetchrequest *request = [[nsfetchrequest alloc] init];  //setup request [request setentity:[nsentitydescription entityforname:@"tweet" inmanagedobjectcontext:self.backgroundcontext]]; [request setpredicate:[nspredicate predicatewithformat:@"profanity = no"]]; 

now have array of tweets not profane iterate through tweets , check each word if contains profane word. thing need deal how separate tweet words (ignoring commas , exclamation marks etc). each word going need strip of diacritics , ignore case. end along lines of:

if([self.badwords containsobject:badwordstring]) {     currenttweet.profanity = [nsnumber numberwithbool:yes]; } 

remember, can run predicates on nsset perform case , diacritic insensitive query:

nspredicate *searchpredicate = [nspredicate predicatewithformat:@"self = %@[cd]",wordtocheck]; bool foundabadword = ([[[self.badwords filteredsetusingpredicate:searchpredicate] allobjects] count] > 0); 

another thing might want consider removing duplicate words in tweets, don't want perform same check multiple times. depending on how find performance place each word of tweet nsset , run query on unique words in tweet:

if([[self.badwords intersectsset:tweetdividedintowordsset]) {     //we have profane tweet here! } 

which implementation choose assuming using english in app going want run case , diacritic insensitive search.

edit

one final thing note no matter how try, people best means of detecting profane or abusive language. encourage read so's post on detecting profanity - how implement profanity filter?


Comments

Popular posts from this blog

android - Get AccessToken using signpost OAuth without opening a browser (Two legged Oauth) -

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: mockito -

google shop client API returns 400 bad request error while adding an item -