iOS |知识点整理(8)

503 阅读5分钟

延续上一篇iOS |知识点整理(7)

关于NSObjectID

Once you save, you get a persistent object ID... unless you are not connected directly to a PSC, and have a parent MOC instead. Basically, you only get a persistent object ID when saving from a MOC directly connected to a PSC. However, you can convert into a persistent object ID anytime you want with the NSManagedObjectContext method

- (BOOL)obtainPermanentIDsForObjects:(NSArray *)objects
                               error:(NSError **)error;

Edit

First, if your code depends on knowing if an object ID is temporary or not, you should rethink you logic... this does not sound right, unless you are writing some special core data code. Second, if your MOC has a PSC and not a parent MOC, you must be querying the objectID and it's temp/perm status before the context is saved. Why don't you do something like this where you save the context...

NSLog(@"before save: %@", [moc registeredObjects]);
BOOL result = [moc save:&error];
NSLog(@"after save: %@", [moc registeredObjects]);

and you will see the IDs of all objects... you can visually distinguish between the ones that are temporary and the ones that are permanent. The temporary ones look like this...

<NSManagedObject: 0x7f8834836e10> (
  entity: Foo;
  id: 0x7f8834836e70 <x-coredata:///Foo/tECDD46E2-3D01-4E5D-BCE8-1DD8DB2138A512>;
  data: { identifier = 8; }),

The permanent ones look like this...

<NSManagedObject: 0x7f8834836e10> (
  entity: Foo;
  id: 0x7f8834c231e0 <x-coredata://38B5921E-4638-42FD-AD94-78555561DBA7/Foo/p2>;
  data: { identifier = 8; }),

After the save, all objects should have permanent IDs.

Remember, the FRC will get updates anytime the MOC changes, and not just when a save occurs. The exception you reference at the end of your question looks like a bad indexPath.

关于Core Data的优化

Entity类:

#import "Entity.h"
@implementation Entity
@dynamic name;
@dynamic orgName;
@dynamic jobTitle;
@dynamic school;
-(void)awakeFromFetch{
    [super awakeFromFetch];
    NSLog(@"awakeFromFetch");
}
@end


//    self.managedObjectContext.stalenessInterval=0;
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Entity" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];
    NSError *error = nil;
    NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
    Entity* e=fetchedObjects.lastObject;
    NSLog(@"%@",e.name);
    [self.managedObjectContext refreshObject:fetchedObjects.lastObject mergeChanges:YES];
    NSLog(@"%@",e.name);

关于Core Data的优化 上海-老坛酸菜-IOS() 17:21:09 Student* s= fetch from MOC s.name=@"8888" //重新fetch同一个对象 Student* s= fetch from MOC s.name仍然为@"8888" 桦木沉海-iOS(903102) 17:21:31 就是属性被回滚了。我试试 上海-老坛酸菜IOS() 17:21:39 我的问题是 既然对象的状态没有发生变化,第二次fetch为什么还执行了sql查询 桦木沉海-iOS() 17:22:26 sql查询是因为他在查询前不知道是不是同一个对象啊。。 桦木沉海-iOS() 17:22:39 你如果不让他查询,就应该用ManagedObjectId 桦木沉海-iOS() 17:24:02 CoreData是有对数据做缓存的。 CoreData的数据并跟数据库里的内容完全同步。。。这明显是优化啊。。。 桦木沉海-iOS() 17:24:16 并不同步 上海-老坛酸菜-IOS() 17:24:53 是啊,要同步,得强制让他变成Fault 桦木沉海-iOS() 17:25:20 变fault也不会同步 桦木沉海-iOS() 17:25:25 吧? 上海-老坛酸菜-IOS() 17:25:38 怎么不会? 桦木沉海-iOS() 17:25:49 得调用save才挣的存到数据库里吧?不清楚 上海-老坛酸菜-IOS() 17:26:36 文档里说,你得调用refreshObject:mergeChanges 上海-老坛酸菜-IOS() 17:26:57 最后那个参数为YES时,就会合并一下那个对象的变化 上海-老坛酸菜-IOS() 17:27:46 你core data用得还是不错的!


NSManagedObjectContext: undo save-operation?

Could you use a child managed object context to do your save (which pushes it up to the parent, but doesn't touch the file on disk), and then do a rollback on the parent if you want to undo it?

I think calling save is like committing all the changes you've made since the last save, and rollback is like discarding them. Once you've committed the changes, they're in the persistent store and there's nothing keeping transaction logs in order to support rolling back.

Can you explain a bit more about why you want a save in the middle of your transaction? stackoverflow.com/questions/1…


求单个属性的和

There are two ways to solve this problem: first - get your data to NSSet or NSArray and use @sum operator: count 为 Pen的一个属性.

//assume that `pens` are NSArray of Pen
NSNumber *countSum=[pens valueForKeyPath:"@sum.count"];

performBlockAndWait所在线程

performBlock: Asynchronously performs a given block on the receiver’s queue.

performBlockAndWait: Synchronously performs a given block on the receiver’s queue. 在当

[context performBlock:^{
    //会在新的线程中gg
    [context performBlockAndWait:^{
    //就在调用该代码的当前线程上干活,  这么做也是符合下面的使用的规则的,也就是说,同步获取了manage object以后
    就可以直接在相应的线程中使用了.
       }]

以这个方法建立的context:

[[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

在使用上面的block的注意事项:

Working with Data Between Blocks
• ObjectIDs often useful
■ Rematerialize into MO with objectWithID:
■ objectWithID will reuse cached data
• Also, okay to retain MOs but not look or use outside block
• Use __block variables
• Remember NSError are autoreleased

ref:CoreData performBlock


CoreData多线程使用原则

Before doing anything concurrent with Core Data, it is important to get the basics right. We strongly recommend reading through Apple’s Concurrency with Core Dataguide. This document lays down the ground rules, such as never passing managed objects between threads. This doesn’t just mean that you should never modify a managed object on another thread, but also that you should never read any properties from it. To pass around an object, pass its object ID and retrieve the object from the context associated to the other thread.

Doing concurrent programming with Core Data is simple when you stick to those rules and use the method described in this article.

Managed Object只能在其对应的MOC所在的线程中,进行写或读操作. 如果要放到 其它线程进行操作,那么需要在不同的线程传递object ID.


关于core data的child context以及parent context

Finally, there is a lot of noise about child contexts these days. Our advice is not to use them for background operations. If you create a background context as a child of the main context, saving the background context will still block the main threada lot. If you create the main context as a child of a background context, you actually don’t gain anything compared to a more traditional setup with two independent contexts, because you still have to merge the changes from the background to the main context manually.

当以main context作为parent context的时候,当background context保存的时候,一样会阻塞main thread.

The setup with one persistent store coordinator and two independent contexts is the proven way of doing core data in the background. Stick with it unless you have really good reasons not to.

关于UIBezierPath的旋转 1.路径没有所谓的