关于新的NSManagedObjectContext并发类型,目前文献似乎有点稀疏.除了WWDC 2011 vids以及我在此过程中提到的其他一些信息之外,我仍然很难掌握每种并发类型的使用方式.以下是我如何解释每种类型.如果我理解错误,请纠正我.
这种类型在过去几年中一直是常态.MOC被屏蔽了每个线程.因此,如果线程A MOC想要通过保存消息合并来自线程B MOC的数据,则线程A将需要订阅线程B的MOC保存通知.
每个MOC树(父级和子级MOC)共享相同的队列,无论每个都在哪个线程上.因此,每当发送来自任何这些上下文的保存消息时,它都被放入专门为此MOC树制作的私有提示中.
仍然对这个感到困惑.从我收集的内容就像NSPrivateQueueConcurrencyType一样,只有私有队列在主线程上运行.我读到这对于与MOC的UI通信是有益的,但为什么呢?为什么我会选择NSPrivateQueueConcurrencyType?我假设因为NSMainQueueConcurrencyType在主线程中执行,这是否允许后台进程?这不是不使用线程吗?
我有一个问题,我已经工作了几个星期.每当我保存我的Core Data托管对象上下文时,它都会导致UI性能出现问题.我已经尽我所能并且正在寻找一些帮助.
我的应用程序使用两个NSManagedObjectContext实例 一个属于应用程序委托,并且附加了持久性存储协调器.另一个是主要MOC的一个孩子,属于一个Class叫做的对象PhotoFetcher.它使用,NSPrivateQueueConcurrencyType因此在此MOC上执行的所有操作都在后台队列中进行.
我们的应用程序从我们的API下载表示有关照片数据的JSON数据.为了从API检索数据,执行以下步骤:
NSURLRequest对象并使用该NSURLConnectionDataDelegate协议构造从请求返回的数据,或处理错误.NSJSONSerialization基础类实例解析JSON .SQLite商店.最后,向委托进行回调,通知他们响应已完全插入到Core Data存储中.保存背景MOC的代码如下所示:
[AppDelegate.managedObjectContext performBlock:^{
[AppDelegate saveContext]; //A standard save: call to the main MOC
}];
Run Code Online (Sandbox Code Playgroud)
当主对象上下文保存时,它还保存了自上次发生主对象上下文保存以来已下载的相当数量的JPEG.目前,在iPhone 4上,我们正在以70%的压缩率下载15个200x200 JPEG,或者总共下载大约2MB的数据.
这很有效,效果很好.我的问题是,一旦后台上下文保存,NSFetchedResultsController我的视图控制器中的运行将获取传播到主MOC的更改.它在我们PSTCollectionView的开源克隆中插入新细胞UICollectionView.在插入新单元格时,主上下文会将这些更改保存并写入磁盘.在运行iOS 5.1的iPhone 4上,这可以在250-350ms之间.
在三分之一秒内,该应用程序完全没有响应.暂停之前正在进行的动画暂停,并且在保存完成之前,没有新的用户事件发送到主运行循环.
我使用Time Profiler在Instruments中运行我们的app,以确定阻塞主线程的内容.不幸的是,结果相当不透明.这是我从仪器获得的最重的堆栈跟踪.

它似乎是保存持久存储的更新,但我无法确定.所以我完全删除了任何调用,saveContext因此MOC不会触及磁盘,并且主线程上的阻塞调用仍然存在.
文本形式的跟踪如下所示:
Symbol Name
-[NSManagedObjectContext(_NestedContextSupport) _parentObjectsForFetchRequest:inContext:error:]
-[NSManagedObjectContext executeFetchRequest:error:]
-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]
_perform
_dispatch_barrier_sync_f_invoke
_dispatch_client_callout
__82-[NSManagedObjectContext(_NestedContextSupport) …Run Code Online (Sandbox Code Playgroud) user-interface core-data objective-c nsmanagedobjectcontext ios
我使用RestKit 0.20来解析JSON数据并保存到数据库.这是一个映射的实体SchoolClass,由RestKit处理并保存好.我有另一个名为MyClass的实体,它存储我选择的类.这个只在设备上本地.
这是我创建的代码并保存MyClass实体
NSManagedObjectContext *managedObjCtx = [RKManagedObjectStore defaultStore].mainQueueManagedObjectContext;
MyClass* course = [managedObjCtx insertNewObjectForEntityForName:@"MyClass"];
.. set the data for course here
NSError *executeError = nil;
if(![managedObjCtx save:&executeError]) {
NSLog(@"Failed to save to data store");
}
Run Code Online (Sandbox Code Playgroud)
以下是初始化托管数据存储的代码
// Initialize managed object store
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
objectManager.managedObjectStore = managedObjectStore;
/**
Complete Core Data stack initialization
*/
[managedObjectStore createPersistentStoreCoordinator];
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"RKMainDb.sqlite"];
NSString *seedPath = [[NSBundle mainBundle] pathForResource:@"RKSeedDatabase" ofType:@"sqlite"];
NSError *error;
NSPersistentStore *persistentStore = …Run Code Online (Sandbox Code Playgroud) 我看过一些视频/帖子说可以创建'儿童'MOCs - 使用其他MOC作为持久存储的MOC.例如,在您正在线程化应用程序的上下文中,并希望拥有一个可以保存/回滚子线程创建的更改的主MOC时很有用.(根据我的理解,MOC和它的托管对象必须都在同一个线程上使用)
问题是,我如何创建一个儿童MOC?我无法追踪我正在观看的WWDC视频介绍它们,我所看到的一切都在讨论如何使用它们.我可以很容易地分配一个新的MOC,但我该怎么设置它持久存储是另一个MOC?该引用没有显示任何功能!
我在这里撞墙,我正在使用Core Data作为SQLLite数据库,我能够成功保存到数据库(我已经在离线SQLLite浏览器中检查了内容),但是在保存之后我试图运行的第一个查询返回下面看到的错误,我在互联网上找不到与此特定错误相关的任何有用信息:
核心数据:错误:-executeRequest:遇到异常=数据库显示已损坏.用户信息= {NSFilePath ="/ Users/user/Library/Application Support/iPhone Simulator/7.0.3/Documents/db.sqlite";(无效的主键);
这里的问题是导致这个错误的原因,因为我找不到任何与之相关的信息.
对于一些小背景,这是我的设置,请假设我已经有充分的理由进行设计并且没有提供"改变你的设计"的答案,除非你能看到从根本上打破了模式本身的东西.
我有3个托管对象上下文,它们都是NSPrivateQueueConcurrencyType,第一个(A)附加到持久性存储协调器,第二个(B)有A集作为其父上下文,第三个(C)有B设置为它的父上下文 - 链.原因是C是一个可写上下文,从网络源获取数据并同步并保存它,B是UI元素共享的上下文,我希望它是响应的,最后A是设计的背景上下文卸载任何延迟保存到磁盘关闭上下文B&C
PSC < - A < - B < - C.
如果我取出最后一步(将A保存到PSC),则应用程序运行良好,将所有内容保存在内存中并查询内存中的上下文.崩溃仅在我将保存步骤添加回来后才会发生,并且仅在保存后针对数据库运行的第一个查询运行时发生.我的Save和我的fetch执行都包含在performBlock中:
这是最后一次保存:
- (void)deepSave
{
// Save to the Save Context which happens in memory, so the actual write to disk operation occurs on background thread
// Expects to be called with performBlock
NSError *error = nil;
[super save:&error];
NSAssert(!error, error.localizedDescription);
// Trigger the save context to save to disk, operation will be queued and free up …Run Code Online (Sandbox Code Playgroud) 我有一个内存密集型的iOS应用程序,我正在努力确保内存使用不会随着时间的推移而累积.我的应用程序有一个"主要"上下文,它存在于应用程序的生命周期中,其他较小的上下文偶尔会为后台任务生成.
我注意到的一件事是NSManagedObjects似乎长期在主上下文中保持注册,并且真正回收与从DB中提取对象相关的所有内存的唯一方法是调用[NSManagedObjectContext reset].
这当然导致内存使用量大幅下降,因为最近关闭的列表视图中的所有已注册对象都从内存中正确弹出,但是它很烦人,因为您刚刚使该上下文中注册的每个对象无效,您仍然有参考to(即仍由打开的视图引用的对象),您现在需要从数据库中重新获取所有这些对象,以避免访问无效对象的异常.
这是从NSManagedObjectContext中清除注册对象集的唯一方法,还是有更好的方法可以成功弹出您不再引用的所有已注册对象,但不会使所有仍处于活动状态的NSManagedObject失效?
目标是获取当前的NSManagedObjectContext以使用Core Data.在iOS 4.3中,我将UINavigationController的委托设置为AppDelegate,如此(在AppDelegate.m中):
self.navigationController.delegate = self;
Run Code Online (Sandbox Code Playgroud)
我可以做这样的事情(无论我需要上下文):
NSManagedObjectContext *context = [self.navigationController.delegate performSelector:@selector(managedObjectContext)];
Run Code Online (Sandbox Code Playgroud)
现在,在iOS 5中,我使用的是Storyboard,我很难搞清楚如何实现这一目标.我首先使用了一个代理,因为我不认为你想要一直传递你的AppDelegate.h.
我创建了一个带有一个Entry:UserBase的UserModel.xcdatamodeld,我添加了一个名称为UserID且类型为Integer 32的属性.
之后,我使用file-> new file-> NSManagedOBject子类为它创建类,它自动创建UserBase.h和.m.
在我的控制器中导入了UserBase.h文件,并创建了一个属性:
NSManagedObjectContext *userBaseObjectContext;
Run Code Online (Sandbox Code Playgroud)
同
@property (nonatomic, retain) NSManagedObjectContext *userBaseObjectContext;
Run Code Online (Sandbox Code Playgroud)
在mycontroller.m文件中合成了userBaseObjectContext属性,在DidLoad函数中我尝试了这个:
UserBase *userObject=(UserBase *)[NSEntityDescription insertNewObjectForEntityForName:@"UserBase" inManagedObjectContext:userBaseObjectContext];
[userObject setUserID:[NSNumber numberWithInt:42]];
NSError *error;
if(![userBaseObjectContext save:&error])
{
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"Application error" message:@"error" delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil,nil];
[alert show];
[alert release];
}
else
NSLog(@"not working...");
Run Code Online (Sandbox Code Playgroud)
当我尝试构建我的项目时,我收到此错误:
Undefined symbols for architecture i386:
"_OBJC_CLASS_$_NSEntityDescription", referenced from:
objc-class-ref in LoginController.o
"_OBJC_METACLASS_$_NSManagedObject", referenced from:
_OBJC_METACLASS_$_UserBase in UserBase.o
"_OBJC_CLASS_$_NSManagedObject", referenced from:
_OBJC_CLASS_$_UserBase in UserBase.o
ld: symbol(s) not found for architecture i386
clang: error: linker command …Run Code Online (Sandbox Code Playgroud) 我创建了两个这样的上下文:
// create writer MOC
_privateWriterContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_privateWriterContext setPersistentStoreCoordinator:_persistentStoreCoordinator];
// create main thread MOC
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
_managedObjectContext.parentContext = _privateWriterContext;
Run Code Online (Sandbox Code Playgroud)
我有一个NSFetchResultedController发起人_managedObjectContext.
我知道这很奇怪,但我正在向父母添加一条记录_privateWriterContext,我就是saving它.
令人惊讶的是,子上下文因此FRC得到有关此事件的通知.为什么?我没有reset孩子,或其他任何东西.只要子上下文不会被保存,我认为它们是独立的实体.
在@pteofil文章中我找到了这一行:
当在上下文中进行更改但未保存时,它对所有'后代都可见,但对其'祖先不可见.
..它被推送到持久性存储(通过持久性存储协调器),并且对连接到商店的所有上下文都可见.
core-data nsfetchedresultscontroller nsmanagedobjectcontext ios
许多论坛都讨论过这个话题,但我仍然无法完全理解其performBlockAndWait实际效果如何.根据我的理解,context.performBlockAndWait(block: () -> Void)将在阻塞调用程序线程的同时在其自己的队列中执行该块. 文档说:
您将"标准"消息分组以发送到块中的上下文以传递给这些方法之一.
什么是"标准"消息?它还说:
基于队列的托管对象上下文的Setter方法是线程安全的.您可以直接在任何线程上调用这些方法.
这是否意味着我可以设置托管对象的属性,该对象是在performBlock*API之外的上下文的performBlockAPI中获取的?
根据我的理解,调用performBlockAndWait(block: () -> Void)具有并发类型的上下文.MainQueueConcurrencyType将在从主线程调用时创建死锁并永久阻止UI.但在我的测试中,它并没有造成任何僵局.
我认为它应该创建死锁的原因是,performBlockAndWait将首先阻塞调用程序线程,然后在其自己的线程上执行该块.由于上下文必须执行其块的线程与已被阻塞的调用者线程相同,因此它将永远无法执行其块并且线程将永远被阻塞.
但是我在一些奇怪的场景中遇到了僵局.我有以下测试代码:
@IBAction func fetchAllStudentsOfDepartment(sender: AnyObject) {
let entity = NSEntityDescription.entityForName("Department", inManagedObjectContext: privateContext)
let request = NSFetchRequest()
request.entity = entity
request.relationshipKeyPathsForPrefetching = ["students"]
var department: Department?
privateContext.performBlockAndWait { () -> Void in
department = try! self.privateContext.executeFetchRequest(request).first as? Department
print(department?.name)
guard let students = department?.students?.allObjects as? [Student] else {
return
}
for student in students …Run Code Online (Sandbox Code Playgroud) ios ×8
core-data ×7
objective-c ×4
xcode ×2
delegates ×1
ios5 ×1
iphone ×1
memory-leaks ×1
restkit ×1
sqlite ×1
storyboard ×1
swift ×1