わかりました、これで少し迷っています。現在、タイプが NSPrivateQueueConcurrencyType に設定された 2 番目の ManagedObjectContext を使用してバックグラウンド コア データ操作を実行しようとしていますが、上記のエラーで惨めに失敗しています。
文字列の NSArray が渡される NSOperation のカスタム サブクラスと、メイン スレッドからの PersistentStoreCoordinator があり、独自の ManagedObjectContext を作成し、クエリを実行して操作を実行します。
クラスのコードは次のとおりです。
//
// ProcessProfanity.m
// Hashtag Live Desktop
//
// Created by Gareth Jeanne on 24/03/2014.
// Copyright (c) 2014 Gareth Jeanne. All 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 the Request
[request setEntity:[NSEntityDescription entityForName:@"Tweet" inManagedObjectContext:self.backgroundContext]];
NSError *error = nil;
//Create an array from the returned objects
NSArray* tweetsToProcess = [self.backgroundContext executeFetchRequest:request error:&error];
NSAssert2(tweetsToProcess != nil && error == nil, @"Error fetching events: %@\n%@", [error localizedDescription], [error userInfo]);
for (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 does not contain any of the words from the naughty list");
if(tweetToCheck){
tweetToCheck.profanity = [NSNumber numberWithBool:false];
}
}
else{
if(tweetToCheck){
//DDLogVerbose(@"The string contains '%@' from the the naughty list", result);
tweetToCheck.profanity = [NSNumber numberWithBool:true];
}
}
}
[self.backgroundContext save:NULL];
}
@終わり
そして、これが私がそれを呼んでいる方法です:
-(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];
}
編集 1
エラーが発生しているように見える特定の行、または少なくともXcodeが壊れている場所は次のとおりです。
if ([tweetToCheck.text rangeOfString:obj].location != NSNotFound)
これを少し絞り込むことができました。文字列を検索する用語のリストを含む NSArray は非常に大きくなる可能性があり、1,000 NSString を超える可能性があります。そのサイズの配列でテストすると、問題が発生します。ただし、配列を約 15 NSString に減らしてもエラーは発生しないため、これは必ずしもスレッド関連の問題ではないと思います。配列がメイン スレッドで解放されているかどうか疑問に思っています。コードを修正してディープ コピーを作成し、次のように __block コピーを作成しましたが、効果がないようです。
self.badWords = [[NSArray alloc] initWithArray:words copyItems:YES];
と
for (Tweet* tweetToCheck in tweetsToProcess){
__block NSArray *array = [[NSArray alloc] initWithArray:self.badWords copyItems:YES];
__block NSString *result = nil;
[array indexOfObjectWithOptions:NSEnumerationConcurrent
実際、Xcode が壊れた時点で、配列を PO にするとオブジェクトが見つからないというメッセージが表示されますが、結果を PO にすると nil のオブジェクトが返されます。
編集 2
したがって、次の変更を加えましたが、変更はありません。
NSArray をコピーではなく強力にしました:
@property (nonatomic, strong) NSArray* badWords;
そして、割り当て時にコピーを作成しました:
self.badWords = [[NSArray alloc] initWithArray:words copyItems:YES];
そして、オブジェクトを処理する実際のメソッド内で ___block 宣言を使用して NSArray のローカル コピーを作成しました。
__block NSArray *array = [[NSArray alloc] initWithArray:self.badWords copyItems:YES];
ProcessProfanity オブジェクトの存続期間中、それが存続することを意味するのはどちらでしょうか?
ブロック内のブレークポイントから配列を PO できると期待するのは間違っていますか?