当我使用Core Data在我的iOS应用程序中保存数据时,我遇到了问题。
我的应用程序可以在一秒钟内从服务器接收许多短信。
所以我需要在我的数据库中保存这些消息,现在我在队列中使用NSOperations来保存消息(所以你可以想象NSOperationQueue中的NSOperation的数量)。
问题是经过一些指示后,我的NSOperationQueue被阻止,NSOperation的数量无限制地增加。
通过一些调查我发现问题在于保存上下文,保存上下文阻止NSOperation和NSOperation我永远不会结束,它永远不会出列,但我无法解决它。
这是我的NSOperation代码:
@interface SaveRecievedMessageOperation()
@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, strong) AppDelegate *appdelegate;
@property (nonatomic, assign) BOOL executing;
@property (nonatomic, assign) BOOL finished;
@end
@implementation SaveRecievedMessageOperation
@synthesize message;
@synthesize managedObjectContext;
@synthesize appdelegate;
@synthesize executing;
@synthesize finished;
- (id)initWithMessage:(SipMessage *)messageToSave
{
if (self = [super init]) {
self.message = messageToSave;
}
return self;
}
- (void)main
{
@autoreleasepool
{
self.appdelegate = [[UIApplication sharedApplication] delegate];
[self managedObjectContext];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(mergeChanges:)
name:NSManagedObjectContextDidSaveNotification
object:self.managedObjectContext];
[self saveMessage];
}
}
- (NSManagedObjectContext *)managedObjectContext
{
if (managedObjectContext != nil)
{
return managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self.appdelegate persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[managedObjectContext setPersistentStoreCoordinator:coordinator];
[managedObjectContext setMergePolicy:NSOverwriteMergePolicy];
}
return managedObjectContext;
}
- (void)saveMessage
{
NSDictionary *header = self.message.headers;
NSArray *bodies = self.message.bodies;
SipBody *sipBody;
NSDictionary* body;
NSData *ContentData;
if ([[header valueForKey:@"Content-Type"] rangeOfString:@"application/json"].location != NSNotFound)
{
sipBody = [bodies objectAtIndex:0];
body = [NSJSONSerialization
JSONObjectWithData:sipBody.content
options:NSJSONReadingAllowFragments
error:nil];
}
else if ([[header valueForKey:@"Content-Type"] rangeOfString:@"multipart/mixed"].location != NSNotFound)
{
for (SipBody *sipB in bodies) {
if ([[sipB.headers valueForKey:@"Content-Type"] rangeOfString:@"application/json"].location != NSNotFound)
{
body = [NSJSONSerialization
JSONObjectWithData:sipB.content
options:NSJSONReadingAllowFragments
error:nil];
}
else
{
ContentData = [NSData dataWithData:sipB.content];
}
}
}
else
{
return;
}
MGMPhone *sender;
NSArray *senders = [self updatePhonesFromMSISDNsList:[[header valueForKey:@"swfrom"] componentsSeparatedByString:MGMseparator]];
sender = senders[0];
NSError *error;
MGMMessage *aMesage = [MGMMessage createInContext:self.managedObjectContext];
[aMesage setBoxType:[NSNumber numberWithInteger:BoxTypeIncomingMessage]];
[aMesage setContent:[body valueForKey:@"Content"]];
[aMesage setContentType:[header valueForKey:@"Content-Type"]];
[aMesage setGroupMessage:( [[header valueForKey:@"groupmessage"] isEqualToString:@"true"]
?
[self saveContext];
}
#pragma mark core data
- (void)mergeChanges:(NSNotification *)notification
{
dispatch_async(dispatch_get_main_queue(), ^{
NSManagedObjectContext *mainContext = [appdelegate managedObjectContext];
[mainContext performSelector:@selector(mergeChangesFromContextDidSaveNotification:) withObject:notification];
[self setManagedObjectContext:nil];
}
- (void)saveContext
{
NSError *error = nil;
if (self.managedObjectContext != nil)
{
if ([self.managedObjectContext hasChanges]) {
BOOL isSaved = [self.managedObjectContext save:&error];
if(!isSaved){
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
else if (![self.managedObjectContext hasChanges]){
[self setManagedObjectContext:nil];
}
}
}
@end
这是一个共享实例。
#import "CoreDataService.h"
static CoreDataService *sharedService = nil;
@implementation CoreDataService
@synthesize coreDataReceptionQueue;
+ (id)sharedService
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (sharedService == nil) sharedService = [[self alloc] init];
});
return sharedService;
}
- (NSOperationQueue*) coreDataReceptionQueue
{
if (coreDataReceptionQueue)
{
return coreDataReceptionQueue;
}
coreDataReceptionQueue = [[NSOperationQueue alloc] init];
[coreDataReceptionQueue setMaxConcurrentOperationCount:1];
return coreDataReceptionQueue;
}
@end
以及我如何添加新操作
SaveRecievedMessageOperation *op = [[SaveRecievedMessageOperation alloc]initWithMessage:message];
[[[CoreDataService sharedService] coreDataReceptionQueue] addOperation:op];
答案 0 :(得分:0)
我试图在iPad上阅读它有点困难。您似乎没有将消息包装到'perform ...'块中的moc中 - 您必须这样做。此外,您也可以在其中执行saveContext。使用异步执行块保存信息和保存,使用同步进行读取。
答案 1 :(得分:0)
这可能不是答案,但这是我的观察:
1)您使用以下命令初始化您的操作上下文:NSPrivateQueueConcurrencyType
这将强制您使用上下文,如下所示:
[context performBlockAndWait:^{/*you code*/}]
(您使用“等待”,因为您不希望您的操作过早完成)。如果你不这样做,你的操作可能会挂起......
==>您可以使用NSConfinementConcurrencyType
并保留代码以解决此问题
2)使用“max concurrency”为1的操作队列。这会感染一个串行队列
您可以只保留一个NSPrivateQueueConcurrencyType
上下文,并在其上发出[context performBlock:^{/*your code*/}]
以达到相同的效果。