- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
好吧,我对这个有点迷茫,我目前正在尝试使用类型设置为 NSPrivateQueueConcurrencyType 的第二个 ManagedObjectContext 运行后台核心数据操作,但由于上述错误而惨败。
我有一个 NSOperation 的自定义子类,它被传递给一个 NSArray 字符串,以及来自主线程的 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 对象的生命周期内一直存在吗?
我期望能够从 block 内的断点 PO 数组是错误的吗?
最佳答案
在这种情况下,错误消息“error: NULL _cd_rawData but the object is not being turned into a fault”表明您正在访问其上下文之外的托管对象。基本上,您的提取从您的持久存储中返回所有推文作为错误。一旦您尝试访问托管对象上的属性,Core Data 将引发错误并从存储中获取完整的对象。
通过使用 NSEnumerationConcurrent
选项调用 NSArray 方法 indexOfObjectWithOptions:passingTest:
您暗示您想要对数组中的元素执行异步执行。关键字 concurrent 表示可以使用多个线程对数组元素进行操作。
在您的上下文中,这意味着访问此 block 内的托管对象可能会导致在与拥有该对象的托管对象上下文不同的线程上访问它。因此,当您在条件检查中访问 tweetToCheck.text - if ([tweetToCheck.text rangeOfString:obj].location != NSNotFound)
时,Core Data 正在从持久存储中获取该托管对象并将其返回到不属于托管对象上下文线程的线程。
此外,没有必要使用 indexOfObjectWithOptions:passingTest:
方法,因为您实际上对该操作的结果并不感兴趣。
在我看来,使用 NSSet 可能更方便,因为您只是在测试给定的推文词是否存在于您的脏话中。引用 documentation对于 NSSet:“当元素的顺序不重要并且测试对象是否包含在集合中的性能是一个考虑因素时,您可以使用集合来替代数组”。显然这似乎符合您的标准。
所以你的 init 看起来像:
-(id)initWithStore:(NSPersistentStoreCoordinator*)store
badWords:(NSSet*)badWords
{
self = [super init];
if(self) {
self.persistentStoreCoordinator = store;
self.badWords = [words copy];
}
return self;
}
由于您只对更新尚未被标记为亵渎的推文感兴趣,您可能只想获取尚未被标记为亵渎的推文:
//Create new fetch request
NSFetchRequest *request = [[NSFetchRequest alloc] init];
//Setup the Request
[request setEntity:[NSEntityDescription entityForName:@"Tweet" inManagedObjectContext:self.backgroundContext]];
[request setPredicate:[NSPredicate predicateWithFormat:@"profanity = NO"]];
既然您有一组非亵渎的推文,您可以遍历您的推文并检查每个词是否包含亵渎词。您唯一需要处理的是如何将您的推文分成单词(忽略逗号和感叹号等)。然后,对于每个单词,您都需要去除变音符号并可能忽略大小写。所以你最终会遇到这样的人:
if([self.badWords containsObject:badWordString]) {
currentTweet.profanity = [NSNumber numberWithBOOL:YES];
}
请记住,您可以在 NSSet 上运行谓词,这样您就可以实际执行不区分大小写和变音符号的查询:
NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:@"SELF = %@[cd]",wordToCheck];
BOOL foundABadWord = ([[[self.badWords filteredSetUsingPredicate:searchPredicate] allObjects] count] > 0);
您可能要考虑的另一件事是删除推文中的重复词,您真的不想多次执行相同的检查。因此,根据您找到性能的方式,您可以将推文中的每个词放入 NSSet 并简单地对推文中的唯一词运行查询:
if([[self.badWords intersectsSet:tweetDividedIntoWordsSet]) {
//we have a profane tweet here!
}
您选择哪种实现取决于您,但假设您在应用中只使用英语,您肯定会想要运行不区分大小写和变音符号的搜索。
编辑
要注意的最后一件事是,无论您多么努力,人们始终是检测亵渎或侮辱性语言的最佳方式。我鼓励您阅读这篇关于检测亵渎行为的 SO 帖子 - How do you implement a good profanity filter?
关于objective-c - CoreData,单独线程上的子 MOC,意外 : error: NULL _cd_rawData but the object is not being turned into a fault,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22617977/
我创建 temporaryContext 如下所示。它会包含未保存的更改还是仅包含来自 Utility.managedObjectContext() 的已保存更改? let temporaryCont
我在 CoreData 和父子 MOC 上遇到了这个问题:当向子 MOC 添加对象、保存它们并保存父 MOC 时,所有对象的属性都会重置为默认值。 我在这里粘贴了两个 MOC 的日志,具体是这些日志中
自上周以来我遇到了一个大问题,但我找不到任何可行的解决方案。 当我编译 Qwt 6.1.2(然后尝试使用 6.1.3)时 Windows 7 32bits mingw32控制台,编译序列后,我收到以下
我遇到了一个我无法理解的NSObjectInaccessibleException: *** Terminating app due to uncaught exception 'NSObjectI
想象一下两个托管对象上下文,moc A 和 moc B,它们填充了相同的对象集并共享相同的持久存储协调器。现在,我从 moc A 中删除一个对象并保存上下文。它还会存在于 moc B 中吗? 我测试了
直到现在,我一直对主线程使用“main moc”,初始化如下: [[NSManagedObjectContext alloc] init]; 然后我有 NSOperation 子类,它们有自己的 mo
假设我有一个显示 MOC,用于显示从 Web 服务获取的地址簿联系人。在应用程序的其他地方,我有一个搜索功能,可以根据用户输入的查询搜索 Web 服务,我获取这些对象并将其存储在暂存器 MOC 中,这
我想使用 Q_CLASSINFO 宏存储一些类信息。但是我想将它包装在我自己的宏中,例如: #define DB_TABLE( TABLE ) \ Q_CLASSINFO( "db_table
我无法使用已连接到正确插槽的按钮。 这里是 infoPage.cpp 文件: #include "infoPage.h" InfoPage::InfoPage(QWidget *parent)
我在编译项目时遇到了这个非常奇怪的问题。MOC 似乎正在向被 moc'ed 的类名添加一个命名空间,尽管它在文件/类中的任何地方都没有提到。 然而,命名空间存在于我使用的库中,但它隐藏在头文件中很远的
我必须从 Qt 命令提示符运行以下命令:qmake -project 然后是 make,这会为我提供带有 Moc 文件的调试文件夹。 奇怪的是,这是我的 PC 生成 moc_.cpp 文件的唯一方式。
我希望主队列中的每个实体都有一个 moc,这样用户就可以同时修改多个实体。 假设有 2 个实体:“包”和“类别”,一个包可以有多个类别。因此,当用户在选择类别时修改/创建 Bag 中的项目时,用户也可
我正在尝试构建qteSTLib/tutorial1示例,但是运行nmake时未生成testqstring.moc文件(我在Windows XP SP3上运行Qt 4.5.2)。 我将testqstri
我正在开发一个使用 cmake 的基于 Qt 的项目。我所有生成的 moc 文件都被命名为 *.moc ,但我有一些文件,它们生成的 moc 文件的名称为 moc_*.cpp ,不是 *.moc .为
我有 1 个 parent 2 个 child 的 moc 情况。其中 1 个子级是主界面 moc,另一个是用于在云上同步更改的专用队列。 我遇到过这样的情况:私有(private)云同步子模块保存更
我正在使用 QT Creator 1.3.1 并尝试编译,但出现此错误... 请帮我摆脱它 mingw32-make[1]: Leaving directory `C:/Documents and S
我正在尝试将 ovpn3 的 ovpncli 示例转换为派生自 QObject 的类。我无法将源文件转换为单独的接口(interface) (.h) 和实现 (.cpp) 文件。为了让 MOC 满意,
我的实体上有类别,允许我将 JSON 解析为实体: - (id) populateFromJson: (NSDictionary *) json { ... } 然后使用 MagicalReco
我目前正在使用 Qt (4.7) 编写一个小型应用程序。我使用嵌套的命名空间,比如 namespace app { namespace core { class CoreCla
我正在编写一个项目。尝试进行静态构建后,我开始出现错误。我做了一些更改,我不记得了。但是,我确信如果可以清除这个 stub ,那么主项目也可以被清除。 这是头文件。 #ifndef MYLABEL_H
我是一名优秀的程序员,十分优秀!