Re: Core Data mergeChangesFromContextDidSaveNotification: does not *completely* update the context ?

2010-12-20 Thread Ben Trumbull

On Dec 19, 2010, at 9:49 PM, Aurélien Hugelé wrote:

 Hi!
 
 I think mergeChangesFromContextDidSaveNotification: does not work as most 
 people expect:
 I have a mainthread and a subthread. My subthread updates a managed object 
 (change one of the property value) and save.
 In the mainthread, I use [mainThreadContext 
 mergeChangesFromContextDidSaveNotification:subThreadNotification]; and it 
 merges the main thread context as expected (binded UI is updated)
 
 What is not expected is :
 
 1/ asking the main thread for its updatedObjects (just after the 
 mergeChangesFromContext... but before the save:) does not show the changes 
 made in the subthread! So updated objects in subthread are not seen as 
 updated in the main thread after the mergeChangesFromContext call!
 2/ Saving the main thread generates a did save notification, that does not 
 contain changes made in the subthread (and merged) !
 
 The subthread is temporary (does it job in an NSOperation that terminates 
 quickly), its context is also temporary. 
 
 In the mainthread, *many* controllers are observers of the did save 
 notification of the main thread context. How am I supposed to make them 
 listen to changes made in a temporary, dumb, subthreaded managed context 
 without using mergeChangesFromContext... call ???
 
 I'm pertty sure, most developers expect the 
 mergeChangesFromContextDidSaveNotification: API to really merge the data in 
 the main thread context and set the merged updated objects as *really* 
 updated, as if the change really occured in the main thread!


The method is merging the state into the receiving context purely from the 
perspective of results.  Deleted objects are deleted, updated objects have new 
values, inserted objects exist.  It does not replay the individual changes, nor 
does it guarantee any particular path or implementation for getting the state 
of MOC B to look like the state of MOC A.  For efficiency, it prefers 
refreshing existing objects from the PSC's cache over replaying individual 
changes whenever possible.  

Refreshing is observable by KVO.  These objects are also noted in the 
NSManagedObjectContextObjectsDidChangeNotification with the 
NSRefreshedObjectsKey.  This is how NSArrayController observes these kinds of 
events.

The objects aren't updated in the sense that they'll be saved again.  Because 
they won't.  They've already been saved a first time.  They *were* updated, and 
NSManagedObjectContext's -updatedObjects reports the state about next upcoming 
save, not the last save.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: KVO and Core data

2010-08-09 Thread Ben Trumbull
 Hi all,
 
 I have a KVO registration like this:
 
 [self addObserver:self forKeyPath:@toOne.attribute options:0 context:NULL];
 
 I establish this on -awakeFromInsert or -awakeFromFetch, and have the 
 corresponding removeObserver called on -willTurnIntoFault.
 
 The problem is that when I do a Save As on my document, it migrates the 
 persistent store, which appears to cause the object at the destination of the 
 toOne relationship to be turned into a fault before the object that 
 registered as an observer is. Now when I check the observationInfo for the 
 object that is being faulted (at the end of the toOne relationship), it has 
 itself registered as an observer for attribute. 
 
 I guess this means that behind the scenes, the KVO establishes observation 
 information automatically at every level of a key path (something I hadn't 
 realized before, but which appears to make sense). 
 
 Then something behind the scenes tries to access the attribute on an object 
 that has been turned into a fault, and invalidated, and everything comes 
 crashing down.
 
 So I have two questions:
 
 1. Is it the right way for me to be adding observation on the awake methods 
 and removing it on willTurnToFault?
 
 2. If this is OK, then what could be affecting the system such that it 
 doesn't remove the observation information in the destination of the to-one 
 relationship? I'm wondering if there could be something in my data model that 
 could be affecting it. This relationship is modeled as a one to one, with a 
 delete rule of cascade from the parent to the child, and the inverse 
 relationship is also modeled, with a deny rule. There's also another optional 
 relationship from the child to the parent with a deny rule, modeled in one 
 direction only (and not used in the data I am testing with anyway).

Your problem here is this MOC is being torn down, and the toOne managed 
object is already toast.  So it's not possible to get its attribute.  KVO 
isn't really in a position to deal with this.

Probably the best solution is for the toOne object to traverse the inverse and 
tell it's parent when to add or remove the KVO observation.  So this way when 
attribute is nuked, parent stops observing it.

Another possibility is to just have the accessor methods on toOne for the 
setter for attribute traverse the inverse manually and inform the parent 
outside of KVO.

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Core Data : Multiuser ?

2010-08-07 Thread Ben Trumbull
 Can more than one process be accessing the same Core Data sqlite file?
 
 This post from author Marcus Zarra says no∑
 
   http://forums.pragprog.com/forums/90/topics/1476
 
 But this post from Ben Trumbull seems to say yes, as long as the two 
 processes are accessing it via the same filesystem:
 
   
 http://www.cocoabuilder.com/archive/cocoa/184606-core-data-file-sharing-via-an-afp-alias.html
 
 Which one am I misunderstanding?

There is a big difference between multiple processes accessing the same Core 
Data file and multiple machines.  Multiple processes on the same local machine 
work fine.  Several Apple products do this.  Multiple processes across multiple 
physical machines will not work well (AFP) or at all (NFS).

So we don't recommend targeting a multi-user configuration.  As I mentioned in 
that earlier post, your best bet is probably write the proper service that uses 
Core Data, and vends to your client processes via IPC (like a web service).   
The client processes might independently use Core Data for local caching 
(replication).

It possible, but inefficient, for a very limited number of clients to share 
over AFP.  NFS doesn't work correctly at all.  This is restricted by file 
caching issues underneath us.  There are a lot of limitations and sharp edges 
here, so we actively recommend against multiple computers simultaneously 
accessing the same db.  Support for it is disabled by default for projects 
built with a deployment target = 10.6

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Core Data : Multiuser ?

2010-08-07 Thread Ben Trumbull
p.s. 
http://www.cocoabuilder.com/archive/cocoa/283632-coredata-database-sharing-and-migration.html#283632

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data : Multiuser ?

2010-08-07 Thread Ben Trumbull
When you add the persistent store to the coordinator, in the store options 
dictionary, use the option NSSQLitePragmasOption (which is a sub dictionary of 
pragma keys  values) to pass the  @lock_proxy_file key with a value of 
NSNull.

- Ben

On Aug 7, 2010, at 7:17 AM, Hunter Hillegas wrote:

 Given those limitations, how does one enable support for a 10.6+ target?
 
 On Aug 6, 2010, at 11:38 PM, Ben Trumbull wrote:
 
 It possible, but inefficient, for a very limited number of clients to share 
 over AFP.  NFS doesn't work correctly at all.  This is restricted by file 
 caching issues underneath us.  There are a lot of limitations and sharp 
 edges here, so we actively recommend against multiple computers 
 simultaneously accessing the same db.  Support for it is disabled by default 
 for projects built with a deployment target = 10.6
 


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data : Multiprocess (was Multiuser) ?

2010-08-07 Thread Ben Trumbull
 Sorry.  I see I've created confusion by putting Multiuser in the subject.  
 I should have said Multiprocess

yeah.

 Yes, several Apple frameworks use Core Data databases from multiple 
 processes simultaneously with a single user account and single physical 
 machine.
 
 Later, a reference is made to the iCal, Mail and Address Book apps. 
 
 That's what I'm interested in.  Specifically, an app + a background process, 
 same Mac, same user, sharing a non-document sqlite file.  So it appears that 
 all should work, presumably as described in the Change Management section 
 of Core Data Programming Guide.

yes, that works out of the box.

 One thing still bothers me.  Twice in that document, it mentions managed 
 object contexts in the *same application*.  What if they are in *different 
 processes*?  Possibly the author just wasn't thinking of that?

On the same physical machine and local file system, the behavior between MOCs 
in the same process but with different PSCs and MOCs in different processes is 
effectively the same.

 I've done some more testing since my original post and it appear does appear 
 to work ˆ the errors I was seeing yesterday were Could not merge changes 
 errors (133020 in NSCocoaErrorDomain), and I presume these were due to the 
 fact that I had not set a merge policy on these managed object contexts.  

yes.  That's correct.

 But I have yet to reproduce and prove this.  Any additional assurance that 
 what I'm doing should work would be appreciated.

There are a few things to be mindful of:

(1) creating the db originally requires additional coordination (like your own 
NSDistributedLock).  Basically, there can be a race condition between the 2 
processes creating the file.  After creating the db, you'll want to save 
immediately to force the schema and UUID to get persisted so other processes 
see the same one at that path

(2) store metadata does not have optimistic concurrency control like the 
managed objects do (e.g. no version tracking).  you'll want to minimize any 
custom metadata, and perhaps store it in an entity with a single row.

(3) you may want to refresh data more aggressively.  If so, you should NEVER 
use -refreshObject:mergeChanges:NO on objects that are -isInserted, -isUpdated, 
or -isDeleted.  You should use -refreshObject:mergeChanges:YES on any dirty 
managed objects.

Depending on how much data you want merged into the other process, you may wish 
to send a little IPC or NSDistributedNotification with bread crumbs to only 
refresh the changed objects of importance.  It's a common mistake to post a 
generic notification to the other process that says world changed; have fun.

(4) As with multi-threading, deleting data out from underneath the other MOCs 
can create challenges (faults that throw because the requested data has been 
nuked into oblivion).  You'll probably want to use prefetching and 
setReturnsObjectsAsFaults:NO more than usual as well as this method added in 
10.6 instead of -objectWithID:

/* returns the object for the specified ID if it is already registered in the 
context, or faults the object into the context.  It might perform I/O if the 
data is uncached.  If the object cannot be fetched, or does not exist, or 
cannot be faulted, it returns nil.  Unlike -objectWithID: it never returns a 
fault.  */
- (NSManagedObject*)existingObjectWithID:(NSManagedObjectID*)objectID 
error:(NSError**)error __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0);


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Cant read second table from same sqlite database iphone

2010-04-11 Thread Ben Trumbull
I'm afraid I can't be much more help if you don't have the return codes from 
each of the SQLite statements.  I do note in the second method, you're asking 
for column values out of order, which is pretty unusual.

- Ben

On Apr 10, 2010, at 6:42 PM, charisse napeÿf1as wrote:

 I was able to successfully retrieve data on the first table. But I can't seem 
 to retrieve from the second table. I know it has data inside it because I 
 used an SQLite Browser to view the data. I also tried performing queries 
 there and it worked fine. Only when I used the queries in the code that it 
 doesn't work. 
 
 Below is the code writing the database in the Users/Documents folder for 
 Iphone
 
 - (void) createDatabaseIfNeeded
 {
 NSError * error;
 
 //gets access to the file system
 NSFileManager * fileManager = [NSFileManager defaultManager];
 
 // gets the complete users document directory path
 NSArray * paths = 
 NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, 
 YES);
 
 // gets the first path in the array
 NSString * documentsDirectory = [paths objectAtIndex:0];
 
 // create the complete path for the database file
 NSString * databasePath = [documentsDirectory 
 stringByAppendingString:@/Database.sql];
 
 DebugLog(databasePath = %s\n,[databasePath UTF8String]);
 
 // check if file exists or not
 BOOL success = [fileManager fileExistsAtPath:databasePath];
 
 if (success) return;
 
 // the database does not exist so copy it in the users documents directory
 NSString * dbPath = [[[NSBundle mainBundle] resourcePath] 
 stringByAppendingPathComponent:@/Database.sql];
 
 DebugLog(dbpath is %s\n,[dbPath UTF8String]);
 
 //copy the database file to ther users docuement directory
 
 success = [fileManager copyItemAtPath:dbPath toPath:databasePath 
 error:error];
 
 if (!success)
 NSAssert(0,@Failed to copy Database!\n);
 }
 
 
 From: Ben Trumbull trumb...@apple.com
 To: cnape...@yahoo.com
 Cc: Cocoa dev cocoa-dev@lists.apple.com
 Sent: Sunday, April 11, 2010 9:27:46
 Subject: re: Cant read second table from same sqlite database iphone
 
  Hello All,
  
  I am having trouble reading the second table from my database because it 
  returns nothing even if there is data inside it.
 
 How do you know it has data inside it ?  A common mistake is to try to write 
 to databases in the read only part of an application's sandbox on the iphone. 
  Where in the sandbox is the database ?
 
  - (NSMutableArray*) getProvinces
  {
 NSMutableArray * data = [[NSMutableArray alloc] init];
 const char * sql = SELECT * FROM Provinces;
 sqlite3_stmt * statement;
  
 //prepare the select statement
 int returnValue = sqlite3_prepare_v2(mDatabase, sql, -1, statement, 
  NULL);
  
 DebugLog(return value = %d\n,returnValue);
  
 if (returnValue == SQLITE_OK)
 {
 //sqlite3_bind_int(statement, 1, regionID);
 //loop all the rows returned by the query
 while (sqlite3_step(statement) == SQLITE_ROW)
 {
 
 
 You don't check the return codes here properly.  sqlite3_prepare_v2() can 
 return SQLITE_BUSY, or SQLITE_SCHEMA, or SQLITE_MISUSE.  More importantly, 
 you don't check if sqlite3_step() returns SQLITE_DONE which would indicate 
 that you have 0 rows in this table.
 
 - Ben
 
 
 
 
 New Email names for you! 
 Get the Email name you've always wanted on the new @ymail and @rocketmail.
 Hurry before someone else does!


- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Cant read second table from same sqlite database iphone

2010-04-10 Thread Ben Trumbull
 Hello All,
 
 I am having trouble reading the second table from my database because it 
 returns nothing even if there is data inside it.

How do you know it has data inside it ?  A common mistake is to try to write to 
databases in the read only part of an application's sandbox on the iphone.  
Where in the sandbox is the database ?

 - (NSMutableArray*) getProvinces
 {
NSMutableArray * data = [[NSMutableArray alloc] init];
const char * sql = SELECT * FROM Provinces;
sqlite3_stmt * statement;
 
//prepare the select statement
int returnValue = sqlite3_prepare_v2(mDatabase, sql, -1, statement, NULL);
 
DebugLog(return value = %d\n,returnValue);
 
if (returnValue == SQLITE_OK)
{
//sqlite3_bind_int(statement, 1, regionID);
//loop all the rows returned by the query
while (sqlite3_step(statement) == SQLITE_ROW)
{


You don't check the return codes here properly.  sqlite3_prepare_v2() can 
return SQLITE_BUSY, or SQLITE_SCHEMA, or SQLITE_MISUSE.  More importantly, you 
don't check if sqlite3_step() returns SQLITE_DONE which would indicate that you 
have 0 rows in this table.

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Problem with vCard and AddressBook ABPerson UID, HELP!!

2010-04-07 Thread Ben Trumbull
 've been fighting now with the AdressBook API for a while and found a 
 disturbing problem. Maybe someone can help.
 
 I'm trying to use the AddressBook as my main person database in my 
 application. I've create a small function that accepts drag - drops from the 
 Address book to add a new person in my app. So far so good.
 
 I'm trying after to show in my application details about that linked person 
 and that's where everything falls down.
 
 On drop, I read the vCard created by the AddressBook using this line:
 
 ABPerson* aPerson = [[ABPerson alloc] initWithVCardRepresentation:filedata];

That always creates a brand new contact with a brand new uniqueID.  As you 
observe.  I'm pretty sure it's not an appropriate way to pass around a 
*reference* to an existing contact.  That's what -[ABRecord uniqueId] is for.  
You should get the uniqueId, pass that around, and then use -[ABAddressBook 
recordForUniqueId:] to look up the contact.

- Ben

 
 When doing this, the UID of my person gets re-generated. I wanted to use the 
 UID as my reference to my original address book record and dig the 
 information using it. But since its re-generated upon read of the vCard, no 
 luck. So the call:
   ABAddressBook* addressBook = [ABAddressBook addressBook];
   ABRecord* abRecord = [addressBook recordForUniqueId:personId];
 
 always return null. 
 But, if I use the sharedAddressBook instead, my UIDs still get re-generated 
 but this guy (the sharedAddressBook) can find the records but only in the 
 same execution of the application. Upon restart, same old no-match problem.
 
 There must be something i REALLY don't understand about the AB but can't find 
 anything more, out of ideas.
 
 Anybody knows what's going on? Any way we can prevent my vCard initialization 
 from re-genrating the UID? If not, then what would be the correct way to 
 refer to AB records from another application? Running a search based on names 
 sounds bad compared to using direct pointers to records, the UID.

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Finding managed objects by URI representation

2010-04-05 Thread Ben Trumbull

On Apr 5, 2010, at 8:18 AM, Gideon King wrote:

 On 05/04/2010, at 6:51 AM, Ben Trumbull wrote:
 
 No, this is going the wrong way.  The objectID is the object's identity in 
 the persistent store (e.g. primary key).  You don't need to store pieces of 
 it somewhere else.
 
 NSPredicate *predicate = [NSPredicate predicateWithFormat:@self == %@, 
 myobjectid];
 or
 NSPredicate *predicate = [NSPredicate predicateWithFormat:@self in %@, 
 objectidarray];
 
 
 Can I just clarify a couple of things about this:
 
 1. The documentation says Important:  If the receiver has not yet been 
 saved, the object ID is a temporary value that will change when the object is 
 saved. Now I want to use the IDs as keys in a dictionary, which of course 
 copies the keys, and it is very likely that the objects will be added to the 
 dictionary before saving, and referenced after save. I have checked, and the 
 documentation is true 

Yes, the documentation is true :-)

 But when I try that, it throws an exception saying Can't resolve how to 
 assign objects to stores; Coordinator does not have any stores. 

What is going on is that you haven't yet saved the NSDocument so there is no 
database backing it.  Until the first save, the document is entirely in memory. 
 We cannot assign a permanent objectID until you actually have a persistent 
store file.

 The documentation says Any object not already assigned to a store is 
 assigned based on the same rules Core Data uses for assignment during a save 
 operation (first writable store supporting the entity, and appropriate for 
 the instance and its related items).. 

Yes.  You can explicitly set the object to a store as well.

 My store class is registered in applicationWillFinishLaunching:, and 
 everything seems to work OK while saving, so I would have expected it to be 
 able to create one if it needed to, but the error seems to imply that I have 
 to manually create my atomic store and add it to the coordinator before this, 
 in order to be able to get it to generate the permanent ID. 

That's the store Class.  The exception message is that your NSDocument's PSC 
doesn't actually have any stores (files) added to it at all.

 I just want to check that I haven't gone off on the wrong path again with 
 this, and that I really do have to do all this to get a stable ID...it just 
 seems to me that if I have to do all this just to get a stable ID, maybe 
 there is some more fundamental design issue with my program, or concept I am 
 not getting, and maybe I am trying to work against the way the framework is 
 supposed to be used.


Well, what are you doing such that you need this dictionary that maps object 
IDs before the document has ever been saved ?  Where are you sending this 
dictionary off to ?



 2. From the Predicate Programming Guide, it says that SELF refers to the 
 objects that are being searched. I read through the whole guide and found 
 nothing there stating that it could also refer to the managed object ID. I 
 did eventually find it in the Core Data Programming Guide, but even when I 
 knew what I was looking for, it took ages to find. I really think it should 
 be mentioned in the Predicate Programming Guide - should I file a bug against 
 that documentation?


Please do.

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Finding managed objects by URI representation

2010-04-04 Thread Ben Trumbull
 I have some queries that used to look up objects based on an elementID 
 attribute, which used to be my unique identifier for objects, created when 
 the objects were inserted or loaded. I am now moving away from that and using 
 the standard managed object IDs and reference objects.
 
 So I used to do things like for a drag and drop of objects, I would have 
 predicates like this (where the identifiers were the elementIDs of the 
 objects I was dragging):
 
NSPredicate *predicate = [NSPredicate predicateWithFormat:@%K in %@, 
 @elementID, identifiers];
 
 I guess that I will now have to use a different way of referencing it, and 
 was thinking that I could create the identifiers as:
 
[[[theManagedObject objectID] URIRepresentation] absoluteString]
 
 but if I was to do that, in order to search using a predicate, I would have 
 to create a read only attribute on my managed objects that would return that 
 value, right?

No, this is going the wrong way.  The objectID is the object's identity in the 
persistent store (e.g. primary key).  You don't need to store pieces of it 
somewhere else.

NSPredicate *predicate = [NSPredicate predicateWithFormat:@self == %@, 
myobjectid];
or
NSPredicate *predicate = [NSPredicate predicateWithFormat:@self in %@, 
objectidarray];

 I'm sort of looking at possible alternatives like using the MOCs 
 persistentStoreCoordinator to get the managedObjectIDForURIRepresentation:, 
 and then the MOC objectWithID: method to get the actual object back, but 
 don't know if managedObjectIDForURIRepresentation: would handle the temporary 
 ID situation and potential switch to a permanent ID on save.
 
 I see a few posts along these lines in the past, but I haven't specifically 
 seen anything that says whether any of the methods will cope with looking up 
 a temporary URI, if it has now been turned into a permanent one.


If you stash a temporary URIRepresentation from an unsaved newly inserted 
object externally, like in the pasteboard, then no these methods won't track 
the switch to a permanent ID.  Of course, passing around IDs to objects that 
don't exist in the persistent store yet is juggling fire.  Those objects only 
exist in the MOC in which they were inserted until save, so nobody else can 
actually use their IDs yet.

If you need a permanent ID immediately, you can call 
-obtainPermanentIDsForObjects:error: on the NSManagedObjectContext

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: iPhone CoreData TableView not updating

2010-04-03 Thread Ben Trumbull
 I did the first 7 chapters of More iPhone 3 Development, tackling iPhone 
 SDK3 from Apress regarding the use of CoreData. In these 7 chapters a lot is 
 explained and finally a series of classes and categories are being build that 
 one can use as a Generic Controller for editing data stored in CoreData.
 
 So I bult a new application where I inserted these classes, and created a new 
 viewController for my specific needs. Almost everything works, except that 
 the tableView is not updated when I create a new item for in the DB, The item 
 is however created, but only visible if I quit the App and start it again. 
 Apparently something is not right.
 
 I double checked the 4 NSFetechedResult delegates, but it just does not work. 
 I tried to insert [self.tableView reloadData] on a number of places, but to 
 no avail.

Have you tried starting a new project from the template ?  That produces a 
completely functional Core Data application you can experiment with.  I'm not 
familiar with the book, it's possible there's a bug in their sample code.

If you're having problems with the NSFetchedResultsController, please note that 
the cache is *persistent* across application runs.  The NSFetchRequest is a 
read only property.  You should not mutate it.  If you change the 
NSFetchRequest, NSPredicate (or the varargs), or NSSortDescriptor in any way, 
the cache will be invalid.  In 3.1, this kinda usually worked anyway.  In 3.2 
and later, the caching is more aggressive and produces much faster launch times 
for FRC with complex string queries.  This also means that buggy code that got 
away with it on 3.1 will no longer if it's recompiled against the 3.2 SDK (3.1 
binaries still run fine)

You may find the behavior more intuitive if you opt out with a nil cache name.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Invalidated managed objects

2010-04-03 Thread Ben Trumbull
 When I create a document, save it, then save as, then save as again, it 
 duplicates the persistent store, so the managed objects I have been using in 
 my application are all invalidated. 
 
 Now there are a whole lot of places in my application where I have KVO set up 
 on properties of the managed objects, and some places where I have the 
 managed objects set as instance variables of my objects. I was not expecting 
 them to be invalidated by the save as operation. 

They are not invalidated as part of Save.  They are as part of Save As since 
that creates a new document, with a new persistent store, a new coordinator, 
new pretty much everything.  Save As is creating a duplicate, so the original 
content still exists.  However, the UI needs to be bound to the new content.  
Think of the behavior of TextEdit.  Save As is like close old, duplicate, open 
new

 And created a method to refresh my data:
 
 
 - (void)managedObjectsChanged:(NSNotification *)notification {
   if ([[notification userInfo] objectForKey:NSInvalidatedObjectsKey]) {
   NSSet *objects = [[notification userInfo] 
 objectForKey:NSInvalidatedObjectsKey];
   for (NSManagedObject *obj in objects) {
   [[self managedObjectContext] refreshObject:obj 
 mergeChanges:YES];
   }
   } else if ([[notification userInfo] 
 objectForKey:NSInvalidatedAllObjectsKey]) {
   for (NSManagedObject *obj in [[self managedObjectContext] 
 registeredObjects]) {
   [[self managedObjectContext] refreshObject:obj 
 mergeChanges:YES];
   }
   }
 }
 
 I have confirmed that this is called in the save/save as/save as scenario, 
 with the NSInvalidatedAllObjectsKey, and my object is getting sent the 
 refreshObject message...But when I go to access my data, it still tells me 
 that it has been invalidated. Am I doing something wrong here?

Yes.  You cannot resurrect invalidated objects.  They are toast.  That's why 
you're getting an exception.  Nor would you want to in this case as they all 
represent content from the old (closed) document not the new saved as document. 
 You need to toss all these references and then go through the regular I just 
opened a new document code path for your newly saved document to reconstruct 
the KVO observations.

The canonical solution is to tell your controller objects like 
NSArrayController to refetch from the new document.   It sounds like you're 
fighting the document based Save As behavior.  It's close the existing 
document, save the current state to a new document, open new document

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: NSPredicate/NSExpression - can they solve this Core Data problem?

2010-04-03 Thread Ben Trumbull
They are noted in the NSExpression.h header with API to create them and a 
comment to their functionality.

- Ben

 Is the use of SUBQUERY() documented anywhere?  The only mention I've seen of 
 it is in the reserved keywords section of the Predicate Format String Syntax 
 guide.
 
 Dave
 
 On Apr 2, 2010, at 3:42 PM, Ben Trumbull wrote:
 
  NSComparisonPredicate* exprPred = (NSComparisonPredicate*)[NSPredicate 
 predicateWithFormat:@SUBQUERY(self, $key, %...@.$key != nil) == 0, obj];
  NSExpression* expr = [exprPred leftExpression];
  NSLog(@expression subquery results = %@, [expr 
 expressionValueWithObject:keys context:nil]);

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Invalidated managed objects

2010-04-03 Thread Ben Trumbull

On Apr 3, 2010, at 5:07 PM, Gideon King wrote:

 Wow, this is huge! Obviously the user doesn't expect the document to 
 disappear and a new one open up just because they did a Save As operation

I have I'm afraid led you astray.  The invalidated objects are not coming from 
the Save As operation.  The managed objects in the MOC bound to the 
NSPersistentDocument, and any other MOCs bound to that same PSC will keep the 
NSManagedObjects themselves in sync with the underlying document even as it is 
remapped to a new file.  I'll send you a sample project from the template that 
logs the notifications from NSManagedObjectContext and 
NSPersistentStoreCoordinator.  The NSManagedObject pointers remain undisturbed. 

2010-04-03 18:13:41.110 testDocs[14260:a0f] PSC changed:  {
changedUUID = (
NSSQLCore: 0x1025513e0,
NSSQLCore: 0x103051890,
(
0x1025a4bc0 
x-coredata://7401BACF-50F9-4699-8B65-520963A9B084/Entity/p3,
0x103055bc0 
x-coredata://9D960070-9CAE-4BDD-9EDF-99ACCD83AF7F/Entity/p1,
0x102504fb0 
x-coredata://7401BACF-50F9-4699-8B65-520963A9B084/Entity/p2,
0x103051d40 
x-coredata://9D960070-9CAE-4BDD-9EDF-99ACCD83AF7F/Entity/p3,
0x102598810 
x-coredata://7401BACF-50F9-4699-8B65-520963A9B084/Entity/p1,
0x1004eeb10 
x-coredata://9D960070-9CAE-4BDD-9EDF-99ACCD83AF7F/Entity/p2
)
);
}
2010-04-03 18:13:41.112 testDocs[14260:a0f] PSC changed.  Registered objects = 
{(
NSManagedObject: 0x1004db090 (entity: Entity; id: 0x103051d40 
x-coredata://9D960070-9CAE-4BDD-9EDF-99ACCD83AF7F/Entity/p3 ; data: {
name = baz;
}),
NSManagedObject: 0x1004db120 (entity: Entity; id: 0x103055bc0 
x-coredata://9D960070-9CAE-4BDD-9EDF-99ACCD83AF7F/Entity/p1 ; data: {
name = foo;
}),
NSManagedObject: 0x1004daea0 (entity: Entity; id: 0x1004eeb10 
x-coredata://9D960070-9CAE-4BDD-9EDF-99ACCD83AF7F/Entity/p2 ; data: {
name = zap;
})
)}
2010-04-03 18:13:53.604 testDocs[14260:a0f] PSC changed:  {
changedUUID = (
NSSQLCore: 0x103051890,
NSSQLCore: 0x103062860,
(
0x10305b680 
x-coredata://9D960070-9CAE-4BDD-9EDF-99ACCD83AF7F/Entity/p1,
0x10306a890 
x-coredata://381F89A2-9204-45E8-850B-1CED8022E32E/Entity/p1,
0x10305b3c0 
x-coredata://9D960070-9CAE-4BDD-9EDF-99ACCD83AF7F/Entity/p2,
0x10306aa80 
x-coredata://381F89A2-9204-45E8-850B-1CED8022E32E/Entity/p2,
0x1030681e0 
x-coredata://9D960070-9CAE-4BDD-9EDF-99ACCD83AF7F/Entity/p3,
0x10306ae20 
x-coredata://381F89A2-9204-45E8-850B-1CED8022E32E/Entity/p3
)
);
}
2010-04-03 18:13:53.604 testDocs[14260:a0f] PSC changed.  Registered objects = 
{(
NSManagedObject: 0x1004db090 (entity: Entity; id: 0x10306ae20 
x-coredata://381F89A2-9204-45E8-850B-1CED8022E32E/Entity/p3 ; data: {
name = baz;
}),
NSManagedObject: 0x1004db120 (entity: Entity; id: 0x10306a890 
x-coredata://381F89A2-9204-45E8-850B-1CED8022E32E/Entity/p1 ; data: {
name = foo;
}),
NSManagedObject: 0x1004daea0 (entity: Entity; id: 0x10306aa80 
x-coredata://381F89A2-9204-45E8-850B-1CED8022E32E/Entity/p2 ; data: {
name = zap;
})
)}


There are no invalidate managed objects if you create a Core Data document 
based app from the Xcode template and then perform Save As.  I'll take another 
look at your sample project.

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Invalidated managed objects

2010-04-03 Thread Ben Trumbull

On Apr 3, 2010, at 6:25 PM, Gideon King wrote:

 Phew, that's a relief. I'll look forward to hearing what I'm doing wrong in 
 my sample project then.
 
 Regards
 
 Gideon 
 
 On 04/04/2010, at 11:22 AM, Ben Trumbull wrote:
 
 
 On Apr 3, 2010, at 5:07 PM, Gideon King wrote:
 
 Wow, this is huge! Obviously the user doesn't expect the document to 
 disappear and a new one open up just because they did a Save As operation
 
 I have I'm afraid led you astray.  The invalidated objects are not coming 
 from the Save As operation.  The managed objects in the MOC bound to the 
 NSPersistentDocument, and any other MOCs bound to that same PSC will keep 
 the NSManagedObjects themselves in sync with the underlying document even as 
 it is remapped to a new file.  I'll send you a sample project from the 
 template that logs the notifications from NSManagedObjectContext and 
 NSPersistentStoreCoordinator.  The NSManagedObject pointers remain 
 undisturbed. 


Okay.  The invalidations are coming from the PSC when it removes the old store. 
 At this point it's already added the new store, and it's already told the MOC 
to switch all the objectIDs from its MOs to point to the new store.  The 
problem is that your custom store wasn't being honest about the objectIDs, it 
wasn't even saving them at all, so the remapping between the old and new store 
fails.  At that point, the MOC still has objects from the old store in it, 
because the new store handed out random IDs and the mapping failed to find them.

So I changed your save method to write out both the UUID and the string data so 
your store could properly reconstruct the cache node it loads.  

There was another subtle issue from your reusing the metadata dictionary to 
hold your row data.  The problem is you set the metadata at unfortunate times, 
both before and after the store is created.  Instead of changing it in -init 
(too soon) and in -load (too late), it works better to use -loadMetadata.  This 
is a problem for you since you were overwriting the in memory metadata with the 
plist you wrote to disk which effectively caused the store to change it's UUID. 
 The documentation isn't clear on this, so you shouldn't feel bad about missing 
this part.  You also had -metadata spontaneously mutate the row data, which is 
bad.

It's really important for stores to keep their UUID, and for them to hand back 
the same objectID for an object that they did when we asked before.  Otherwise 
constructing a map from old ids to new ids and looking up stores by their UUID 
is kinda hard.

I'll send you back the original and edited sample projects so you can diff them.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Invalidated managed objects

2010-04-03 Thread Ben Trumbull

On Apr 3, 2010, at 9:44 PM, Gideon King wrote:

 Excellent, thanks for that. I thought that once a managed object ID had been 
 assigned, that newReferenceObjectForManagedObject: should always return the 
 same value, so I was regenerating it from the previous data instead of 
 generating a new one if it either had a temporary object id or no object id. 
 I will switch over my code to do this.

Uhm, that's not exactly what I said.  It should look something like:

- (id)newReferenceObjectForManagedObject:(NSManagedObject *)managedObject {
id result = nil;
NSManagedObjectID* oid = [managedObject objectID];
if ((oid == nil) || [oid isTemporaryID]) {
CFUUIDRef uuidRef = CFUUIDCreate(NULL);
CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef);
result = [[NSString alloc] 
initWithString:(NSString*)uuidStringRef];
CFRelease(uuidStringRef);
CFRelease(uuidRef); 
} else {
result = [[self referenceObjectForObjectID:oid] retain];
}
return result;  
}

although all the Core Data stores use a single 64 bit integer with the current 
seed value stored in the metadata instead of UUIDs.

 In my current implementation, I have a base class for all my managed objects 
 that has an id string (elementID) set in it. The only times it is persisted 
 is for objects that I need to refer to in relationships. This means I can 
 regenerate the value from the managed objects if necessary, so my new method 
 will look like this:

The objectID value (referenceObject) needs to be the same every time you load 
the document.  If you open the document multiple times, and give the same 
objects different objectIDs, badness happens.  For Save As, we're generating a 
dictionary of old IDs - new IDs.  When we add the new store to the 
coordinator, if the store hands back random values for the migrated objects, 
then the MOC can't fix its MOs to point to the new store's cache nodes.

if you:

(1) open the document 
(2)  fetch all the objects into array 'results' (with a sort ordering)
(3) NSLog(@results = %@, [results valueForKey:@objectID]), 
(4) close the document
(5) repeat steps 1-4
(6) compare the 2 logs 

If the strings don't match, you're SOL.

 There is only one area of my code where this will cause an issue, where I 
 pre-generate some of the xml for my file using some references to some 
 managed objects. I'm sure I'll be able to find a way around this though.
 
 Hopefully that will resolve that issue.
 
 Also, I had not noticed the loadMetadata: method, so was just creating it in 
 the init for new files, or in my load method for existing ones. I will have 
 to do a bit of work to change that to load using loadMetadata: since I will 
 have to extract the file from a zip file separately from the main load method 
 which already unzips to a temporary folder. Not a biggie though.


You don't have to use it, but for the sample project you sent that conflated 
the metadata and raw data, it was the best way to avoid nuking the already 
loaded metadata when you loaded the raw data.  It's probably all around better 
though.

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: NSPredicate/NSExpression - can they solve this Core Data problem?

2010-04-02 Thread Ben Trumbull
 Objects:
  - NSManagedObject *item - some managaged object
  - NSArray *attributes - an array of the item's attributes
 
 Desired Result:
  - a possibly smaller array of attribites where [item valueForKey:an 
 attribute] != nil.
 
 In code, I can simply iterate over the keys, perform the valueForKey, 
 and skip nil values. I played around with expressions and predicates to 
 solve this, to no avail.

Having the array of attributes unrolled separately is a little odd.  Do you 
mean you have an array of attribute names from, say the entity, and you want to 
ask a MO for all its non-nil attribute values and get back an array of matching 
attribute names for those non-nil values?

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: NSPredicate/NSExpression - can they solve this Core Data problem?

2010-04-02 Thread Ben Trumbull

On Apr 2, 2010, at 1:30 PM, David Hoerl wrote:

 Having the array of attributes unrolled separately is a little odd.  Do you 
 mean you have an array of attribute names from, say the entity, and you want 
 to ask a MO for all its non-nil attribute values and get back an array of 
 matching attribute names for those non-nil values?
 
 Specifically, here is what I'm trying to do:
 I have a NSManagedObject Address (and no treecontroller) that has 
 properties - lets say name, homePhone, and workPhone. workPhone is optional.
 So, one Address record has obj.name = Joe Blow, obj.homePhone = 555-1212 
 and obj.workPhone = nil
 I put the Address object's property keys in an NSArray *attributes = { 
 @name, @homePhone, @workPhone )
 The exercise is to reduce the attribute array to just the set of keys that 
 when applied to the object result in a value - that is, not nil.


Two approaches:

NSDictionary* obj = [NSDictionary dictionaryWithObjectsAndKeys:@Joe 
Blow, @name, @555-1212, @homePhone, nil];
NSArray* keys = [NSArray arrayWithObjects:@name, @homePhone, 
@workPhone, nil];
NSPredicate* pred = [NSPredicate predicateWithFormat:@%...@.self != 
nil, obj];
NSLog(@filtered array results = %@, [keys 
filteredArrayUsingPredicate:pred]);

NSComparisonPredicate* exprPred = (NSComparisonPredicate*)[NSPredicate 
predicateWithFormat:@SUBQUERY(self, $key, %...@.$key != nil) == 0, obj];
NSExpression* expr = [exprPred leftExpression];
NSLog(@expression subquery results = %@, [expr 
expressionValueWithObject:keys context:nil]);

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data doesn't save toMany relations please HELP :S

2010-03-29 Thread Ben Trumbull
 So was digging more into the problem, and realize that  the Items are being 
 saved the ItemXInvoice are being saved and related to the invoice, but I 
 can't acces the invoice detail (ItemXInvoice) immediately I get a console 
 error:

The array controller doesn't appreciate what you're doing to it.  Is there a 
reason you haven't just configured it in Entity mode with an Entity name and a 
Managed Object Context binding ?  Then the array controller will just listen to 
the NSManagedObjectContext notifications and do most of this for you.

 Cannot remove an observer NSTableBinder 0x116087000 for the key path 
 toItem.descr from ItemXInvoice 0x116024800, most likely because the value 
 for the key toItem has changed without an appropriate KVO notification 
 being sent. Check the KVO-compliance of the ItemXInvoice class.

Somewhere you've changed the toItem property without going through the setter 
method properly.

 I then checked the class and in the setItem Im doing:
 
 -(void)setToItem:(Item *)value{
   [self willChangeValueForKey:@toItem];
   [value retain];
   [self setPrimitiveValue:value forKey:@toItem];
   [self didChangeValueForKey:@toItem];
 }

Where'd you get this ?  It's not from any of the Xcode templates, and it's 
wrong (leaks).  There is no need to retain value, and since this setter doesn't 
do anything interesting, you should just delete it and use the @dynamic 
property from the Xcode Design menu - Data  Modeling - Copy Objective-C 2.0 
Method Declarations to Clipboard

 -(IBAction)addItemXInvoice:(id)sender{
 
   Item  * newItem = [NSEntityDescription 
 insertNewObjectForEntityForName:@Item inManagedObjectContext:[self 
 managedObjectContext]];
   ItemXInvoice * newItemXInvoice = [NSEntityDescription 
 insertNewObjectForEntityForName:@ItemXInvoice inManagedObjectContext: [self 
 managedObjectContext]];
   [newItemXInvoice willChangeValueForKey:@toItem];
   [newItemXInvoice setValue:newItem forKey:@toItem];
   [newItemXInvoice didChangeValueForKey:@toItem];
   [_itemsArrayController addObject:newItemXInvoice];
   if(_newInvoice == nil){
   _newInvoice = [NSEntityDescription 
 insertNewObjectForEntityForName:@Invoice inManagedObjectContext:[self 
 managedObjectContext]];
   }   
   [_newInvoice addToItemsXInvoiceObject:newItemXInvoice];
   [_tempItemsArray addObject:newItem]; //I need to keep track of the 
 newly created itmes by this method so I can safelty remove them.
   //Set the creationItemPrice for each ItemXInvoice
   
 
 }

uhm.   lots of not healthy things here.  You shouldn't be calling 
-willChange/-didChange explicitly here.  That's the purpose of the setter 
methods (or KVC).  Not sure why a bunch of this code isn't in -awakeFromInsert. 
 Or why you have _tempItemsArray at all.

As others have noted, Cocoa Bindings isn't your Model layer and trying to use 
it that way is both tedious and error prone.  It's the Controller layer that 
intermediates between your Model objects and the UI.  You really want to focus 
these kinds object graph (data management) operations on the Core Data objects, 
and leverage those APIs along with KVO and NSNotification.

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: NSSortDescriptor and Block

2010-03-24 Thread Ben Trumbull
 while experimenting with sorting methods I got a strange error message with 
 -sortDescriptorWithKey:ascending:comparator:.
 
 In the following listing (as simple as possible) an Array can be sorted with
 -sortedArrayUsingDescriptors: with a selector, and
 -sortedArrayUsingComparator:
 
 But -sortedArrayUsingDescriptors: with a comparator results in 
 Error: -[NSCFNumber rx]: unrecognized selector.
 
 So the method expects the key rx not in my class as it should but in the 
 NSNumber class.
 A bug? Or is something wrong in my approach?

The arguments to the Block with the NSSortDescriptor are the results of calling 
valueForKeyPath, not the original objects in the array.  NSSortDescriptor has 
already pulled the values for the keypaths out and caches them.  So your using 
the key @rx with that block is like:

[[obj1 valueForKeyPath:@rx] rx]

If you don't want NSSortDescriptors KVC functionality, you can just use 
-sortedArrayUsingComparator:.  You can also try a nil keypath, although I'm not 
certain that works.

- Ben

 // Sort array with -sortDescriptorWithKey:ascending:comparator:
 // Error: -[NSCFNumber rx]: unrecognized selector
 NSSortDescriptor *descr3 = [ NSSortDescriptor sortDescriptorWithKey:@rx 
 ascending:YES
 comparator:^NSComparisonResult(id obj1, id obj2) {
   if ([obj1 rx]  [obj2 rx]) { return NSOrderedAscending; }
   else if ([obj1 rx]  [obj2 rx]) { return NSOrderedDescending; }
   return NSOrderedSame;
 }];


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: NSSortDescriptor and Block

2010-03-24 Thread Ben Trumbull
Well, if you need a nil keypath you probably shouldn't be using sort 
descriptors.  The primary value of sort descriptors are (a) the KVC caching and 
(b) an OO representation of a sort criteria.  

The standard -sortedArrayUsingComparator: is for blocks like the one you wrote 
that are completely free form.

- Ben


On Mar 24, 2010, at 3:55 AM, Jochen Moeller wrote:

 Hello Ben,
 
 thanks very much for your answer. Your idea with the nil keypath works!
 
 So changing the line in question to:
 
 NSSortDescriptor *descr3 = [ NSSortDescriptor sortDescriptorWithKey:nil 
 ascending:YES
   comparator:^NSComparisonResult(id obj1, id obj2) {
 
 is sorting the array without claims.
 
 The syntax of that method is a bit confusing. When using a selector the key 
 is required, and when using a comparator it is not.
 
 Thanks again,
 Jochen Moeller
 
 
 Am 24.03.2010 um 11:12 schrieb Ben Trumbull:
 
 while experimenting with sorting methods I got a strange error message with 
 -sortDescriptorWithKey:ascending:comparator:.
 
 In the following listing (as simple as possible) an Array can be sorted with
 -sortedArrayUsingDescriptors: with a selector, and
 -sortedArrayUsingComparator:
 
 But -sortedArrayUsingDescriptors: with a comparator results in 
 Error: -[NSCFNumber rx]: unrecognized selector.
 
 So the method expects the key rx not in my class as it should but in the 
 NSNumber class.
 A bug? Or is something wrong in my approach?
 
 The arguments to the Block with the NSSortDescriptor are the results of 
 calling valueForKeyPath, not the original objects in the array.  
 NSSortDescriptor has already pulled the values for the keypaths out and 
 caches them.  So your using the key @rx with that block is like:
 
 [[obj1 valueForKeyPath:@rx] rx]
 
 If you don't want NSSortDescriptors KVC functionality, you can just use 
 -sortedArrayUsingComparator:.  You can also try a nil keypath, although I'm 
 not certain that works.
 
 - Ben
 
 // Sort array with -sortDescriptorWithKey:ascending:comparator:
 // Error: -[NSCFNumber rx]: unrecognized selector
 NSSortDescriptor *descr3 = [ NSSortDescriptor sortDescriptorWithKey:@rx 
 ascending:YES
   comparator:^NSComparisonResult(id obj1, id obj2) {
 if ([obj1 rx]  [obj2 rx]) { return NSOrderedAscending; }
 else if ([obj1 rx]  [obj2 rx]) { return NSOrderedDescending; }
 return NSOrderedSame;
 }];
 
 
 


- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Merge changes between two Managed Object Contexts

2010-03-23 Thread Ben Trumbull
If you saved the temporary MOC, then all you have to do is call 
-[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:] on the 
main MOC with the save notification from the temporary MOC.

It's moving unsaved changes around that's cumbersome.

- Ben


 Thank you Joanna, that was very helpful.  So, from your experience, 
 mergeChangesFromContextDidSaveNotification: will not pick up adding a new 
 object, just editing an existing one?  It seems like the real pain point is 
 having to re-create the new object in the second managedObjectContext and 
 copy all it's properties.
 
 Austin
 
 On Mar 21, 2010, at 6:48 PM, Joanna Carter wrote:
 
 Hi Austin
 
 I've got a Core Data project and I have a window controlled by an 
 NSWindowController that is used to add or edit an NSManagedObject.  I 
 wanted to create a separate Managed Object Context in the 
 NSWindowController so that the changes made to the object aren't seen by 
 the UI below and so I can just throw away the changes if the user clicks 
 Cancel.  If the user clicks Save' I wanted to merge the changes from the 
 temporary MOC to the main MOC being used by the rest of the application.
 
 What is the best way to merge those changes back to the main MOC?  Do I 
 have to recreate the object in the main MOC as is done in this example: 
 http://www.timisted.net/blog/archive/multiple-managed-object-contexts-with-core-data?
   Or, can I use - (void)refreshObject:(NSManagedObject *)object 
 mergeChanges:(BOOL)flag to merge the changes?  If i use 
 refreshObject:mergeChanges, can I pass it my NSManagedObject from the 
 temporary MOC and do I need to call save: on the temporary MOC before doing 
 that?


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: CoreData database sharing and migration

2010-03-23 Thread Ben Trumbull

On Mar 22, 2010, at 4:06 AM, Steve Steinitz wrote:

 On 18/3/10, Ben Trumbull wrote:
 
 there wasn't a good solution for multiple machines simultaneously
 accessing an SQLite db file (or most other incrementally updated
 binary file formats).  By good I mean a solution that worked
 reliably and didn't make other more important things work less well.
 
 I'm curious about the reliability issues you saw.  Also, by less well do you 
 mean slower?

Because the different NFS clients have file caches with differing amounts of 
staleness, and the SQLite db is updated incrementally, it's possible for an NFS 
client to think it has the latest blocks, and then derive material from one and 
write it into another (it is after all a b-tree).  The written blocks have 
implicit dependencies on all the other active blocks in the database, so having 
stale data is bad.

 For nearly all Mac OS X customers (sadly not you) achieving a near
 100x performance boost when accessing database files on an AFP or SMB
 mount (like their home directory in educational deployments) is pretty
 huge.
 
 I agree.  But wouldn't those same educational institutions be prime 
 candidates for multiple machine access?

No.  The restriction is multiple physical machines using the same database 
files simultaneously (open).  While AFP will allow multiple logins to the same 
account when configured with an advanced setting, in general, AFP servers 
actually prevent users from multiple simultaneous logins to the same account.

 To address both sets of problems on all network FS, we enforce a
 single exclusive lock on the server for the duration the application
 has the database open.  Closing the database connection (or logging
 out) allows another machine to take its turn.
 
 Could my application close the database connection and re-open it to work 
 around the problem?  How would I do that?  I suppose once I got it going I'd 
 have to retry saves, fetches etc.

In theory, one could, but in practice that won't be very manageable without 
architectural changes.  Something along the lines of open the remote 
connection, pull down interesting data and save it to a local file, and close 
the remote connection.  Given your current deployment set up provides adequate 
performance, and all you need is a bug fix, I'm not sure this would be very 
helpful.

 You'll get the 10.5 performance characteristics, however.
 
 Again, the 10.5 performance over gigabit ethernet is almost unbelievably 
 fast.  I may know why.  Despite your helpful explanations I'm still not 
 exactly clear on the relationship between caching and locking, but I wonder 
 if the speed we are seeing is helped by the fact that the entire database 
 fits into the Synology NAS's 128meg cache?

That probably doesn't hurt.

 In another message in this thread, you made a tantalizing statement:
 
 Each machine can have its own database and they can share their results
 with NSDistributedNotification or some other IPC/networking protocol. You 
 can hook into the NSManagedObjectContextDidSaveNotification to track
 when one of the peers has committed changes locally.
 
 Let me guess how that would work: before saving, the peer would create a 
 notification containing the inserted, updated and deleted objects as recorded 
 in the MOC.  The receiving machine would attempt to make those changes on its 
 own database.  Some questions:
 
Would that really be feasible?

yes, but as you observe, it's more tractable for simple data records than 
complex graphs with common merge conflicts

Would it be a problem that each machine would have having different 
 primary keys?

yes

How would the receiving machine identify the local objects that changed 
 remotely?

typically this is done with a UUID  a fetch.  Since each database on each 
client is different, the stores themselves have different UUIDs, and any 
encoded NSManagedObjectID URI will note which store the objectID came from, so 
you could also map them the objectID URIs to the local value directly.

Could relationships (indeed the object graph itself) feasibly be 
 maintained?

yes.  Updates to to-many relationships require the use of a (additions, 
subtractions) pair instead of simply setting the new contents.

How would relationships between the remote objects be identified?  
 Hand-parsing?

Either by UUID or objectID URI.

Has anyone done it that you know of?

yes.  I'm aware of 4 solutions, however, I would only recommend 1 as 
appropriate for the general (skill, time, pain threshold) and it avoids complex 
relationship graphs.  Basic data record replication over DO.

Is there sample code?


no.  The only real trick in converting the didSave notification into something 
appropriate for DO to consume is to copy it and replace the NSManagedObjects 
with a dictionary that has a UUID instead of an object ID, the attribute 
values, and the relationship contents expressed as a list of UUIDs.

- Ben

Re: CoreData database sharing and migration

2010-03-20 Thread Ben Trumbull
I'm not sure I understand your question.  How is they just use Core Data with 
our SQLite NSPersistentStore and it works for multiple processes on a single 
machine.  For most but not all customers, that's coordinated with POSIX byte 
range advisory locks (fcntl).  Why is to have Cocoa frameworks vending the 
user's Contacts and Events to various apps through an API.  Mail, iCal, and 
Address Book may all be working with Contacts data simultaneously.  etc.

- Ben

On Mar 19, 2010, at 12:42 PM, Aurélien Hugelé wrote:

 Hi Ben,
 
 Can you be kind enough to explain how Apple frameworks do that ? (multiple 
 processes, single machine, one SQLite database)
 I'm thinking of CalendarStore, AddressBook framework. Can you describe what 
 is the general idea behind those Apple frameworks?
 
 
 Aurélien,
 Objective Decision Team
 
 
 
 
 On 17 mars 2010, at 22:29, Ben Trumbull wrote:
 
 I am wondering whether it is possible to create a database in core  
 data that can be opened by more than one application at the same time.  
 It is currently impossible to handle one SQLite database with two  
 instances of the same app. The problem is if user1 quits the app, the  
 data is saved but user2's instance of the app doesn't recognize this  
 file system change and just overwrites its version in memory. So the  
 data from user1 is gone. Is there a way I can handle this?
 
 Second -- I am having more than two database versions now but still  
 want to support my version 1.0 but the mapping model only allows one  
 source model as well as only one target model. I would have to remove  
 one version but that makes version 1.0 users' database unusable.
 
 Has anyone gotten something like this to work?
 
 Yes, several Apple frameworks use Core Data databases from multiple 
 processes simultaneously with a single user account and single physical 
 machine.
 
 Do you mean more than one application simultaneously on more than one 
 physical computer over NFS/AFP/SMB ?  Don't do that.
 
 Or do you mean an NSDocument based application using Core Data  an SQLite 
 store ?  NSDocuments intentionally behave like TextEdit.  Last writer wins, 
 overwites everything.  If so, you should be using a non-document based Core 
 Data project template.
 
 - Ben
 
 ___
 
 Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
 
 Please do not post admin requests or moderator comments to the list.
 Contact the moderators at cocoa-dev-admins(at)lists.apple.com
 
 Help/Unsubscribe/Update your Subscription:
 http://lists.apple.com/mailman/options/cocoa-dev/hugele.aurelien%40objective-decision.com
 
 This email sent to hugele.aurel...@objective-decision.com
 


- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Checking integrity of a Core Data document with SQLite store

2010-03-18 Thread Ben Trumbull
The integrity check will do that, but there's no way to mitigate the I/O costs. 
 Conceptually, if you added a simple checksum, you'd still have to read the 
entire file to verify it matched the checksum.

This file corruption should be extremely rare, and should only occur after 
power loss or kernel panic or a user hitting the power button for an unclean 
reboot.  If not, please file a bug.  If so, but you have data you are willing 
to share with us, also please file a bug.

- Ben

On Mar 17, 2010, at 10:04 PM, Dave Fernandes wrote:

 Thanks, Ben and mmalc for the responses.
 
 I found that prefetching the commonly accessed objects in my document's 
 initWithContentsOfURL:ofType:error method finds the corruption pretty 
 reliably. Hopefully, this is a reasonably robust check without being as i/o 
 intensive as an integrity check.
 
 It would be nice, though, to have a method that I was sure provided good 
 coverage of the physical file. 
 
 Dave
 
 On 2010-03-15, at 11:03 PM, Ben Trumbull wrote:
 
 
 On Mar 15, 2010, at 7:49 PM, Dave Fernandes wrote:
 
 
 On 2010-03-15, at 3:30 PM, Ben Trumbull wrote:
 
 Running an integrity check can be useful if you have previously gotten a 
 corrupt db error back from fetching or saving, or your app previously 
 crashed, or you have some other active indicator it might be worthwhile.  
 However, it's quiet expensive in I/O and you should not do it on every app 
 launch / document open.  Customers with account home directories on AFP, 
 NFS or SMB servers will be very unhappy, and if your files become large 
 enough so will people using local drives.
 
 That's a shame. It would certainly be easier to check when opening the file 
 than to scatter code all over the app to diagnose the problem. Is there a 
 standard exception I can expect to get when fetching or saving? 
 NSInternalInconsistencyException is the one I currently get.
 
 You should generally get an NSError with the code that is 
 NSFileReadCorruptFileError.  In gdb, what does:
 
 future-break objc_exception_throw
 future-break +[NSError errorWithDomain:code:userInfo:]
 
 ...
 
 info threads
 thread apply all bt
 
 say ?
 
 The only place you should get an exception is if you try to fault in an 
 object that is unreachable.  Either because the database was deleted or 
 corrupted, or because another thread / context deleted that object you 
 wanted before you and you only held the reference instead of getting all the 
 data at once (e.g. race on delete)
 
 - Ben
 
 


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: CoreData database sharing and migration

2010-03-18 Thread Ben Trumbull
 On 17/3/10, cocoa-dev-requ...@lists.apple.com wrote:
 
 Do you mean more than one application simultaneously on more than one 
 physical computer over NFS/AFP/SMB ?  Don't do that.
 
 When did that become the official policy, Ben?

The short answer is in 10.6.

The longer answer is that there are two classes of problems, one for NFS and 
one for AFP/SMB.  

For NFS, the protocol does not reliably allow for clients to maintain their 
local file caches coherently with the server in real time.  Only the newest NFS 
servers even respect file cache coherency around byte range file locks **at 
all**.  Unfortunately, the latest protocol doesn't mesh well with SQLite or 
most other existing incrementally updated file formats.   Many deployed NFS 
servers and clients only provide on close to open coherency.  File 
modification timestamps on NFS severs may (or may not) provide accuracy better 
than 1.0 seconds.  And so forth.  There's also no good way to perform a cache 
bypassing file read on OSX or selectively evict ranges of files from the local 
file cache by hand.  We churned on this for a while with various teams, and 
there wasn't a good solution for multiple machines simultaneously accessing an 
SQLite db file (or most other incrementally updated binary file formats).  By 
good I mean a solution that worked reliably and didn't make other more 
important things work less well.  

NFS is just not a free Oracle.  Software that wants real time distributed cache 
coherency needs to use IPC and mange the problem themselves.   It is trivial to 
write a program that writes to a file on NFS and sends the same update to its 
clone on another machine via IPC and for its clone to verify that NFS cache 
coherency indeed fails regularly (e.g. file read bytes != IPC read bytes).  
This is what I mean by real time distributed cache coherency.

For AFP  SMB, the problem is different.  These FS do not support POSIX 
advisory byte range locks at all.  They only support mandatory locks.  
Consequently, they never cache data read from files with any existing locks at 
all.  No file caching means all the I/O is slow.  Painfully slow.  AFP over 
Airport without file caching is bad.  The I/O throughput on a file free of 
locks on AFP is close to 100x better than a file with a single byte locked that 
isn't even anywhere near where you are reading.  For nearly all Mac OS X 
customers (sadly not you) achieving a near 100x performance boost when 
accessing database files on an AFP or SMB mount (like their home directory in 
educational deployments) is pretty huge. 

So we focused on making the experience that could work well work even better.  
10.6 is a significantly better network FS client as Apple applications like 
Mail don't slam the servers with byte range lock requests all the time (good 
for NFS), and on AFP also gets to use local file caching.

To address both sets of problems on all network FS, we enforce a single 
exclusive lock on the server for the duration the application has the database 
open.  Closing the database connection (or logging out) allows another machine 
to take its turn.  This behavior was supposed to be opt in for Core Data apps, 
but on 10.6.2 is not.

 I'm doing that with some success.  For the past three years, my 
 client's point of sale system has been connecting from five 
 machines to a single database on a Synology network drive over 
 afp.  I had to write some code to periodically get the latest 
 values from the database during idle time.  That was a little 
 complicated but its working well now.

It can work technically on AFP.  However, the distributed cache coherency 
problem is avoided by these network FS because they don't do any file caching 
on files with locks.  Your server set up and networking hardware is pretty 
sophisticated compared to most so the performance is adequate.  As an engineer, 
I would wish AFP over VPN over Airport was the more uncommon deployment 
scenario, but sadly not.

 There are mysterious but harmless optimistic locking errors once 
 in a while where no attributes appear have changed -- just to 
 keep me on my toes, along with an occasional real data collision 
 (two staff members carelessly editing the same object) but we've 
 had no real issues in a year or so.

Those mysterious updates are probably version numbers being bumped because the 
object's participation in a to-many relationship, either outgoing or incoming, 
changed.

 However, 10.6.2 has a bug where only one machine can connect to 
 a Core Data store (its likely a sqlite-level connection issue -- 
 but I'm not sure).

ADC did pass your bug report along to us, and it is a backward binary 
compatibility issue, and a regression from 10.6.0.  It will be fixed in a 
future update.  You'll get the 10.5 performance characteristics, however.

 So, for a while we were down to one 
 machine.  I eventually had to roll the five machines back to 
 Leopard.  That remains a PR nightmare.

I'm sorry about that.  

re: Multiple validation errors. Why?

2010-03-18 Thread Ben Trumbull
 I have a core data application. One entity is Hit. This entity typically 
 has no instances when the application starts, and gets populated during the 
 execution of the program. All of the instances appear to be OK when viewed in 
 a TableView. Some or all instances may get deleted before the application 
 quits. If any instances remain when the app quits, I get a multiple 
 validation errors occured message. The console has no error messages. In 
 debugging, I have gone so far as supplying no data at all when adding any 
 instances, so they get created with default values only. Still I get the 
 error message. Some attributes are strings, some are 16 bit integers, and 
 some are 32 bit integers. The string defaults are empty strings, and the 
 integer defaults are zero. I am creating Hit instances with this method

The NSError has an -userInfo dictionary with at least some answers to your 
questions in it.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: User-space threads and NSAutoreleasePool

2010-03-18 Thread Ben Trumbull
 The problem is that when you call swapcontext() to switch the user-thread
 running on a kernel-thread, the NSAutoreleasePool stack is not swapped out.
 It remains rooted in thread-local storage. As a result, serious problems
 result. Let me give an example.
 
 - (void)doStuff {
  NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
  // do some stuff that calls swapcontext()
  [pool drain];
 }

That doesn't work correctly with regular threads, pthreads, GCD or any other 
concurrency pattern.  The autorelease pool needs to be pushed and popped within 
the context of the asynchronous subtask.  The original thread of control needs 
its own pool, and you cannot rely upon autorelease to keep objects alive across 
asynchronous task boundaries.  You will need to be careful to ensure that the 
sending thread transfers ownership of a retain to the receiving thread which 
releases it.  Not autoreleases it.

It would need to conceptually be:

- (void)doStuff {
 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
// some stuff Before
[pool drain];

 // do some stuff that calls swapcontext(), and has it's only scoped 
autorelease pool

pool = [[NSAutoreleasePool alloc] init];
// some more stuff After
 [pool drain];
}

Object you want to keep alive across drains should be retained and later 
released.  

Autorelease pools are cheap.  Make more.  A lot more.  If you have places where 
that doesn't work with coroutines then don't leak important objects into 
autorelease pools.  Either don't create them that way, or retain them again, 
and release them after you can verify the autorelease pool was destroyed.

 Using kernel-level
 threads is, naturally, simpler, but due to the cost of kernel-level context
 switches, they don't scale well. (You just can't run 500 threads at once
 very well.) User-space threads require more programmer attention, certainly,
 but also allow certain programming models that can't be done otherwise. For
 example, they can be used for coroutines, cooperative threading, or all
 sorts of esoteric-yet-sometimes-useful effects.

That's true, but I'm not sure it's relevant for the I wish I had 500 threads 
to handle this web server communication task.  There are a lot of different 
ways to organize the tasks as inert data that can be processed cooperatively by 
a set of active worker threads.

The mental model of each task being its own little world and a thread is nice, 
but it's also artificial.  You can reorganize the relationship between active 
workers and command data.  Nothing is stopping you from that except a 
preconception that tasks and threads must have a 1:1 correspondence.

You could create a finite state machine to process a queue of the tasks as 
inert command structures and firing up 8 of those finite state machines on 
their own dedicated normal threads on your Mac Pro.  The semantic effect will 
be similar to user threads, yet you won't run into all these crazy problems.  
Destroying thread local storage and its affect on autorelease pools is just 
your first problem stuffing Cocoa into swapcontext()

This point from Mike is particularly apt:

 Since you mention in another message that this is portable,
 cross-platform code, why do you need to call Cocoa from the user-level
 threads at all? Separate your code into cross-platform code that does
 this swapcontext stuff, and Mac-specific code that doesn't, and you
 should be good.

You could use a sandboxing approach like Safari and have your cross platform 
code run in a background CLI and talk to the GUI app over IPC.  No Cocoa in the 
CLI and no user threads in the GUI app.  

Pretty sure, though, you'd get better performance conceptually restructuring 
the task / actor relationship.  The cooperative finite state machine approach 
along with a prioritized queue can provide soft real time performance with 
thousands of task objects ... every second.  That's basically what some older 
MMORPG servers did before people went wild with distributed computing.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: NSManagedObject awakeFromFetch not sent on secondary thread?

2010-03-17 Thread Ben Trumbull
 However I still don't understand why awakeFromFetch is not sent in secondary
 thread - I can't find any clue in documentation? Is this a bug or is it a
 feature? I'm running on 10.6.2.

Did you try setting the NSFetchRequest option -setReturnsObjectsAsFaults:NO ?  
The default setting will attempt to lazily copy the fetch results into the 
managed objects as much as possible (the data is still fetched eagerly from the 
database by -executeFetchRequest: as you can see with SQL logging) Perhaps you 
are always touching the objects on the main thread eagerly so there is no 
apparent difference there.

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: CoreData database sharing and migration

2010-03-17 Thread Ben Trumbull
 I am wondering whether it is possible to create a database in core  
 data that can be opened by more than one application at the same time.  
 It is currently impossible to handle one SQLite database with two  
 instances of the same app. The problem is if user1 quits the app, the  
 data is saved but user2's instance of the app doesn't recognize this  
 file system change and just overwrites its version in memory. So the  
 data from user1 is gone. Is there a way I can handle this?
 
 Second -- I am having more than two database versions now but still  
 want to support my version 1.0 but the mapping model only allows one  
 source model as well as only one target model. I would have to remove  
 one version but that makes version 1.0 users' database unusable.
 
 Has anyone gotten something like this to work?

Yes, several Apple frameworks use Core Data databases from multiple processes 
simultaneously with a single user account and single physical machine.

Do you mean more than one application simultaneously on more than one physical 
computer over NFS/AFP/SMB ?  Don't do that.

Or do you mean an NSDocument based application using Core Data  an SQLite 
store ?  NSDocuments intentionally behave like TextEdit.  Last writer wins, 
overwites everything.  If so, you should be using a non-document based Core 
Data project template.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: CoreData database sharing and migration

2010-03-17 Thread Ben Trumbull

On Mar 17, 2010, at 2:59 PM, Tobias Jordan wrote:

 Hello Ben,
 
 Thanks a lot for responding! My problem is as follows: The database which is 
 currently a non-document based core data SQLite one is normally stored in the 
 local User Library of the user. (/Users/user/Library/Application 
 Support/MyApp/database.db
 
 But there are cases in which two (or more) different physical machines must 
 have access to the database.

Don't do that.  Network file systems do not provide real time distributed cache 
coherency.  NFS is not a free version of Oracle.

 For example two designers working on a project and they both need the same 
 database so they can share their results. This means they create a new 
 database on their server and link my app to this database.

Each machine can have its own database and they can share their results with 
NSDistributedNotification or some other IPC/networking protocol.  You can hook 
into the NSManagedObjectContextDidSaveNotification to track when one of the 
peers has committed changes locally.

- Ben

 
 As you've said, is there a way the data can be always immediately written to 
 disk so there's no 'last writer wins'?
 
 I am not using NSDocument based techniques -- it is really just one core data 
 DB.
 
 Thank you!
 
 Regards,
 Tobias
 
 
 On Mar 17, 2010, at 10:29 PM, Ben Trumbull wrote:
 
 I am wondering whether it is possible to create a database in core
 data that can be opened by more than one application at the same time.
 It is currently impossible to handle one SQLite database with two
 instances of the same app. The problem is if user1 quits the app, the
 data is saved but user2's instance of the app doesn't recognize this
 file system change and just overwrites its version in memory. So the
 data from user1 is gone. Is there a way I can handle this?
 
 Second -- I am having more than two database versions now but still
 want to support my version 1.0 but the mapping model only allows one
 source model as well as only one target model. I would have to remove
 one version but that makes version 1.0 users' database unusable.
 
 Has anyone gotten something like this to work?
 
 Yes, several Apple frameworks use Core Data databases from multiple 
 processes simultaneously with a single user account and single physical 
 machine.
 
 Do you mean more than one application simultaneously on more than one 
 physical computer over NFS/AFP/SMB ?  Don't do that.
 
 Or do you mean an NSDocument based application using Core Data  an SQLite 
 store ?  NSDocuments intentionally behave like TextEdit.  Last writer wins, 
 overwites everything.  If so, you should be using a non-document based Core 
 Data project template.
 
 - Ben
 
 


- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: CoreData database sharing and migration

2010-03-17 Thread Ben Trumbull
 About the second question -- do you know how to solve the migration with more 
 than two data models?

From a specific NSPersistentStore's perspective there is only ever 1 data 
model.  When you use multiple models and merge them together, then *union* is 
the data model.  The object you pass to the NSPersistentStoreCoordinator 
initializer is the one true data model regardless of whether it only exists in 
memory or how many separate model files were used to compose it.

When you migrate a store that is built on the union of multiple models, you 
must migrate the union to a new union.  You cannot migrate things piecemeal.  
However, as you can merge models together at runtime, so too could you 
construct mapping models programmatically to handle the union.   However, 
that's probably more trouble than it's worth.  You should focus on migrating 
the union model that was used with the store as its own entity.

It might be easier to think about how you would give each schema a version 
number.  Each union of models is likely to be its own version, and you would 
migrate to a new union with a new version number.

- Ben


On Mar 17, 2010, at 3:28 PM, Tobias Jordan wrote:

 Hi Ben,
 
 Thanks so much for this brilliant suggestion, I haven't thought about 
 something like this before but it's actually really fantastic.
 About the second question -- do you know how to solve the migration with more 
 than two data models?
 
 - Tobias
 
 On Mar 17, 2010, at 11:13 PM, Ben Trumbull wrote:
 
 
 On Mar 17, 2010, at 2:59 PM, Tobias Jordan wrote:
 
 Hello Ben,
 
 Thanks a lot for responding! My problem is as follows: The database which 
 is currently a non-document based core data SQLite one is normally stored 
 in the local User Library of the user. (/Users/user/Library/Application 
 Support/MyApp/database.db
 
 But there are cases in which two (or more) different physical machines must 
 have access to the database.
 
 Don't do that.  Network file systems do not provide real time distributed 
 cache coherency.  NFS is not a free version of Oracle.
 
 For example two designers working on a project and they both need the same 
 database so they can share their results. This means they create a new 
 database on their server and link my app to this database.
 
 Each machine can have its own database and they can share their results with 
 NSDistributedNotification or some other IPC/networking protocol.  You can 
 hook into the NSManagedObjectContextDidSaveNotification to track when one of 
 the peers has committed changes locally.
 
 - Ben
 
 
 As you've said, is there a way the data can be always immediately written 
 to disk so there's no 'last writer wins'?
 
 I am not using NSDocument based techniques -- it is really just one core 
 data DB.
 
 Thank you!
 
 Regards,
 Tobias
 
 
 On Mar 17, 2010, at 10:29 PM, Ben Trumbull wrote:
 
 I am wondering whether it is possible to create a database in core
 data that can be opened by more than one application at the same time.
 It is currently impossible to handle one SQLite database with two
 instances of the same app. The problem is if user1 quits the app, the
 data is saved but user2's instance of the app doesn't recognize this
 file system change and just overwrites its version in memory. So the
 data from user1 is gone. Is there a way I can handle this?
 
 Second -- I am having more than two database versions now but still
 want to support my version 1.0 but the mapping model only allows one
 source model as well as only one target model. I would have to remove
 one version but that makes version 1.0 users' database unusable.
 
 Has anyone gotten something like this to work?
 
 Yes, several Apple frameworks use Core Data databases from multiple 
 processes simultaneously with a single user account and single physical 
 machine.
 
 Do you mean more than one application simultaneously on more than one 
 physical computer over NFS/AFP/SMB ?  Don't do that.
 
 Or do you mean an NSDocument based application using Core Data  an SQLite 
 store ?  NSDocuments intentionally behave like TextEdit.  Last writer 
 wins, overwites everything.  If so, you should be using a non-document 
 based Core Data project template.
 
 - Ben
 
 
 
 
 - Ben
 
 
 
 


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Checking integrity of a Core Data document with SQLite store

2010-03-15 Thread Ben Trumbull
 On 14 Mar 2010, at 9:47 PM, mmalc Crawford wrote:
 
 On Mar 14, 2010, at 7:21 pm, Dave Fernandes wrote:
 
 So my question is - how do you detect this before loading the file? I'm 
 aware of the sqlite3 PRAGMA integrity_check, but there does not seem to be 
 a C API for this. Any pointers?
 
 http://developer.apple.com/mac/library/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSPersistentStoreCoordinator_Class/NSPersistentStoreCoordinator.html#//apple_ref/doc/c_ref/NSSQLitePragmasOption
 
 See 
 http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdPersistentStores.html#//apple_ref/doc/uid/TP40002875
  for an example.
 
 My understanding may be incomplete, but it seems that the example shows the 
 use of pragmas (pragmata?) that set the state of the store at 
 addPersistentStore...: time, and have no significant return value. PRAGMA 
 integrity_check and PRAGMA quick_check return tables. 
 
 Is there a way to collect the results of the integrity check? Would 
 addPersistentStore...: return nil and somehow populate the error return?

Yes, if it detects corruption you'll get an error back.  There isn't much 
useful in the result tables from those pragmas.

Running an integrity check can be useful if you have previously gotten a 
corrupt db error back from fetching or saving, or your app previously crashed, 
or you have some other active indicator it might be worthwhile.  However, it's 
quiet expensive in I/O and you should not do it on every app launch / document 
open.  Customers with account home directories on AFP, NFS or SMB servers will 
be very unhappy, and if your files become large enough so will people using 
local drives.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re:NSManagedObject awakeFromFetch not sent on secondary thread?

2010-03-15 Thread Ben Trumbull
 My custom NSManagedObject subclass uses awakeFromInsert and awakeFromFetch
 to setup custom object to ivar. This works as expected, but when I fetch the
 same object on secondary thread (in NSOperation), the ivar remains nil as
 awakeFromFetch is not sent...
 
 Is NSManagedObject's awakeFromFetch supposed to be sent when fetching on
 secondary thread?

Does the secondary thread have its own private NSManagedObjectContext that you 
are using for the fetch, or are you fetching against an NSManagedObjectContext 
that was created on another thread ?  If you are using an NSOperationQueue with 
maxConcurrency  1, then each NSOperation will need to allocate, use, and 
deallocate its own NSManagedObjectContext.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Problem with save as and freed managed object context

2010-03-15 Thread Ben Trumbull
 One of the other things I had been working on must have fixed the underlying 
 problem, and my implementation of identifier and setIdentifier were actually 
 causing this issue. I completely removed those two methods (which is of 
 course going directly against the documentation at the top of the 
 NSAtomicStore class reference, but going along with the implication in 
 NSPersistentStore that you don't have to override it) and for the first time, 
 was able to save as! Yay!
 
 But my elation was short lived because I now get an intermittent error on 
 save as:
 
 Error Domain=NSCocoaErrorDomain Code=4 UserInfo=0x11e9c21c0 The document 
 „Untitled60.nm5‰ could not be saved as „Untitled60sa.nm5‰. The folder doesn‚t 
 exist. Underlying Error=(Error Domain=NSCocoaErrorDomain Code=4 
 UserInfo=0x11ef217f0 The folder „(null)‰ doesn‚t exist. Underlying 
 Error=(Error Domain=NSPOSIXErrorDomain Code=2 The operation couldn‚t be 
 completed. No such file or directory))
 
 So sometimes it works and sometimes it doesn't. My file format is a zipped 
 folder with my XML files and other resources in it, so when a file is saved, 
 I create a temporary folder and put all the bits of my file into it, zip it 
 up, and then remove the old file and move the zipped up new one into place. 
 I'm not sure if this is relevant at all, but when I get the save error, it 
 also says:
 
 AppKit called 
 rmdir(/private/var/folders/nl/nlcXN-oPHJiAXXc1Z0R5VE+++TI/TemporaryItems/(A 
 Document Being Saved By NovaMind5TP 71)), it didn't return 0, and errno was 
 set to 66.
 
 But I am collecting the error messages in my app, and it's not anywhere in 
 there, so must be from within CoreData, and the man page for rmdir just said 
 that the return on error is 0 for errors, so I can't be certain what the 
 error code means (I suspect it means that the folder is not empty).

Those are NSDocument errors.  It has two features that may be getting in your 
way (or vice versa).  First, the safe save functionality.  It tries to marshall 
all the changes into a temporary directory, and then switch the document with 
the old one wholesale.  You're removing the old file may confuse and anger the 
NSDocument gods, and your switching the new one may be duplicating its 
functionality in a way that it's not prepared for.  Pretty sure you don't want 
to delete the old file.

The second feature is document rename tracking.  NSDocument uses fs events to 
track any external changes to the document including renaming, deletion, or 
unexpected writes.  By unexpected I mean anything that happens outside of one 
of NSDocument's write methods.  So saving on a background thread directly 
against a MOC, or using FS commands to alter the document, will give NSDocument 
indigestion.

 
 Has anyone else seen that one before?
 
 
 I also have a problem where the save as only appears to save some of the data 
 in my file, but I am guessing that that must be some bug in my code.
 
 
 If I open a file and then try to save as (without making any changes), then 
 I get a Could not merge changes error message. I'm not sure if that's 
 related to the problem where it is only saving part of the file, or is 
 something completely different, but am planning to look at the data loss one 
 first and see if it resolves the merge issue.

gdb:

future-break objc_exception_throw
future-break +[NSError errorWithDomain:code:userInfo:]

...

 info threads
 thread apply all bt

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Checking integrity of a Core Data document with SQLite store

2010-03-15 Thread Ben Trumbull

On Mar 15, 2010, at 7:49 PM, Dave Fernandes wrote:

 
 On 2010-03-15, at 3:30 PM, Ben Trumbull wrote:
 
 Running an integrity check can be useful if you have previously gotten a 
 corrupt db error back from fetching or saving, or your app previously 
 crashed, or you have some other active indicator it might be worthwhile.  
 However, it's quiet expensive in I/O and you should not do it on every app 
 launch / document open.  Customers with account home directories on AFP, NFS 
 or SMB servers will be very unhappy, and if your files become large enough 
 so will people using local drives.
 
 That's a shame. It would certainly be easier to check when opening the file 
 than to scatter code all over the app to diagnose the problem. Is there a 
 standard exception I can expect to get when fetching or saving? 
 NSInternalInconsistencyException is the one I currently get.


You should generally get an NSError with the code that is 
NSFileReadCorruptFileError.  In gdb, what does:

future-break objc_exception_throw
future-break +[NSError errorWithDomain:code:userInfo:]

...

info threads
thread apply all bt

say ?

The only place you should get an exception is if you try to fault in an object 
that is unreachable.  Either because the database was deleted or corrupted, or 
because another thread / context deleted that object you wanted before you and 
you only held the reference instead of getting all the data at once (e.g. race 
on delete)

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Core Data Autoincrement?

2010-03-15 Thread Ben Trumbull
 Is there a way (in a Core Data entity) to make an attribute that's  
 like a relational DB autoincrement field? Or, failing that, does an  
 object of class (or subclass) NSManagedObject inherit a unique  
 UInt32 value that can reliably differentiate it from any other  
 instance being managed by the NSManagedObjectContext in use?

Each managed object has an objectID that is unique and automatically assigned.  
NSManagedObjectID are opaque value classes, but you can serialize the 
-URIRepresentation of an objectID.  Mutating the URI form and then reimporting 
it is unsupported with extreme prejudice.

If you must have an int32 autoincremented, you'll need to create your own.  You 
can create an entity with a single row to store the integer and update it 
transactionally.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Problem with save as and freed managed object context

2010-03-12 Thread Ben Trumbull
 Further information: I have just gone through every place in our code where 
 it makes reference to the managed object context (there's only 90 of them 
 thank goodness), and there is nothing there where we either retain or release 
 a managed object context, or use one in a notification or anything like that.
 
 I have also found out that the managed object context that is over-released 
 is not the one that I have in my persistent document, so all I can assume is 
 that it is one that is created behind the scenes programmatically during the 
 persistent store migration.
 
 I also checked our will/didTurnIntoFault and awakeFromInsert/Fetch to make 
 sure they were clean. Found a few minor problems, but it made no difference. 
 I did find that awakeFromFetch was called during the process of migration, 
 but didn't find out anything else of interest. I also checked for description 
 methods that may have caused faults to fire at the wrong time. I only found 
 one description on one of our managed object classes, and an interesting 
 thing happened when I commented that out - I could not save at all (trying to 
 send an objectID message to an NSNumber). I have not tracked that one down 
 yet.

Try running with MallocStackLoggingNoCompact=1 set in the env and using 
malloc_history to see where an NSManagedObject was allocated and then freed and 
replaced with an NSNumber.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Core Data Spotlight: Record-Level Indexing : Issues?

2010-03-12 Thread Ben Trumbull
 On Mac OS X v10.6 and later, for non-document-based programs, you can create 
 Spotlight indexes where each record is indexed individually. [1]  I 
 interpret this to mean that users can get results for my app's records in 
 their Spotlight searches, the way they get Safari bookmarks and Address Book 
 contacts.
 
 Before I get in too deep, I was hoping someone could advise on potential 
 trouble areas:  
 
 1.  My app is document-based, although in the use-case for which this 
 feature, the user has only one document.  I'd like it to index that one.  I 
 presume that by non-document-based programs, Apple is actually referring to 
 the store -- in other words, if I provide in my document-based app a 
 non-document-based store, Spotlight can index the records in that store.  So 
 I'll copy objects from the user's selected document into the new 
 non-document-based store.  Should it work?  Does anyone have a more elegant 
 suggestion?

I'm not sure what user experience you are trying to effect here.  It's sounds 
like you'd be better off if this part of your app was just not document based 
at all.

The HI guidelines are such that document based apps should not perform row 
level Spotlight indexing.  You can see that is the case empirically with the 
Spotlight menu.

 
 2.  Although you can use your custom managed object classes in the importer, 
 the Core Data External Record daemon ... canâ•˙t use custom managed object 
 classes.  All of my managed objects are *subclasses* of NSManagedObject.  Is 
 that what they mean by custom managed object classes?

It means within the importing code you'll just have NSManagedObjects 
encapsulating your data.  All your persistent properties defined in the model 
will be accessible, but any custom methods or business logic will not.

  If so, then the Core Data External Record daemon won't be working for me, 
 but it's optional and only to improve performance.  On the other hand, my 
 objects have several dozen properties, only a few of which will be indexed.  
 So if I need to implement another non-document store anyhow, maybe I should 
 copy my objects to simple NSManagedObjects, copying only the few properties 
 which I want indexed by Spotlight or are necessary to act upon a hit.
 
 3.  Project currently uses Mac OS 10.5 SDK.  If I still want to support 10.5, 
 I need to bite the bullet, read the Cross-Development Programming Guide and 
 configure the project for cross-development, but in the end, Record-Level 
 Indexing should work for my 10.6 users.  10.5 users simply won't get any of 
 my results in their Spotlight searches.Any known gotchas in there?

In theory, but since your app is document based, the preferred approach would 
be to use the whole document spotlight importer.

 4.  Can't find any sample code.  It would be nice to see that Record-Level 
 Indexing has been done?

You can create a new project with the template and it should be a functional 
sample.  Both document based and non-document based Core Data projects have 
templates with spotlight importers.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Trouble with core data and Save As

2010-03-02 Thread Ben Trumbull
 I'm having another look at an issue I posted about a couple of weeks ago, 
 where Save As was causing an error. At the time, I was using a custom managed 
 object context. I have now reverted to a standard managed object context. I 
 do not create or release this managed object context anywhere - it gets 
 automatically created when I first access it from my persistent 
 document...but this context is not where the problem occurs.
 
 When I do a Save As, it migrates to a new store behind the scenes, it appears 
 to load my objects into the new store OK, and accesses the attributes OK, but 
 then I get a crash where it tries to send a message to a deallocated 
 NSManagedObjectContext. This context is created by core data internally as 
 Instruments shows:
 
 # CategoryEvent Type  RefCt   Timestamp   Address Size
 Responsible Library Responsible Caller
 0 NSManagedObjectContext  Malloc  1   00:28.911   0x11d0d58a0 
 240 CoreData-[NSPersistentStoreCoordinator(_NSInternalMethods) 
 _retainedAllMigratedObjectsInStore:toStore:]
 1 NSManagedObjectContext  Autorelease 00:28.953   
 0x11d0d58a0 0   CoreData
 -[NSPersistentStoreCoordinator(_NSInternalMethods) 
 _retainedAllMigratedObjectsInStore:toStore:]
 2 NSManagedObjectContext  Zombie  -1  00:28.955   0x11d0d58a0 
 0   CoreData-[NSManagedObjectContext(_NSInternalAdditions) 
 _dispose:]
 
 As far as I can see, I never get a look in. It all appears to be triggered by 
 [NSPersistentStoreCoordinator 
 migratePersistentStore:toURL:options:withType:error:]. 

Instruments can get confused by custom -retain / -release methods, so those may 
not be all the events.

 But obviously there must be something somewhere in my code causing this 
 problem. 
 
 I am just totally clueless as to where to look, and would appreciate any 
 suggestions.
 
 I thought there might be something happening in one of my awake... methods or 
 a dealloc or willTurnIntoFault or didTurnIntoFault, but I didn't find 
 anything that looked suspicious. The store is an NSAtomicStore subclass, and 
 I read that there could be problems with Save As if 
 newReferenceObjectForManagedObject: did not return a constant value, but that 
 isn't called before it crashes...so I'm stuck.
 
 Any ideas?

The custom store seems like the most probable source of issues.  One source of 
problems I've seen is when a custom store doesn't handle either the metadata or 
the objectIDs correctly.  The store UUID and the object's IDs need to be stable 
(e.g. if we ask your store for its UUID, it doesn't make up a new answer for 
every question).  If you give us an objectID to assign to an object, you cannot 
later change your mind.  And then there's just not preserving the contents of 
the metadata.

If you can create a stripped down sample project that reproduces the issue, you 
could file a bug.

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: NSNull vs nil in NSManagedObject setValue: v forKey: k

2010-03-01 Thread Ben Trumbull

 NSManagedObject* obj; // gets created somehow
 
 [obj setValue: nil forKey: @bar]; // succeeds where NSDictionary fails
 [obj setValue: [NSNull null] forKey: @bar]; // fails where NSDictionary 
 succeeds
 
 so - this is conceptually buggy thinking and the thoughtful developer could 
 be forgiven for being VERY SURPRISED by this behavior that is NOT DOCUMENTED.

A review of 
http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSNull_Class/Reference/Reference.html
 clearly documents the behavior.  Additional inferences beyond the 
documentation are unsupported.  The NSNull class defines a singleton object 
used to represent null values in collection objects (which don’t allow nil 
values)  None of the examples involve KVC.  There are no references to KVC in 
the related documentation.   NSNull isn't a Key Value Coding thing, this is an 
NSArray, NSSet, NSDictionary thing.  Nothing in the documentation implies 
otherwise.

Secondly, NSDictionary is untyped.  NSNull is valid for any key.  
NSManagedObject properties have an explicit type.  Values are expected to 
conform to the type specified for the property named by the key.  NSNull is not 
an NSString.  Your attempts otherwise are a basic violation of OOP. 

Thirdly, nil and NSNull are both valid values for typed NSManagedObject 
properties but they are not for NSDictionary.  In an NSDictionary, NSNull and 
nil must be equivalent because there are no other legal possibilities.  nil is 
never a valid value.  But for either transformable or transient NSManagedObject 
properties, both NSNull and nil are legal values.  Should we make it illegal to 
have optional properties that use NSNull ?  

In general, NSManagedObject does not perform value type coercion.  We chose 
this to balance several design criteria including detection of developer error 
(e.g. masking bad values), performance, and convenience (doing this yourself is 
trivial).  If enough developers feel another balancing would be more 
productive, we'd be happy to reevaluate that.  You should contribute by filing 
bugs.

- Ben

p.s. On an ancillary note, gratuitous use of NSNull outside of collections gets 
tedious  problematic.  Since NSNull != nil, all the client code then has to 
check multiple conditions, which this is easily forgotten, and then selector 
not recognized bugs crash apps because NSNull isn't the right class.

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Core Data 10.5 Mapping error 134140. Troubleshooting, Value Expressions?

2010-02-28 Thread Ben Trumbull
 In my latest model revision, I added a relationship between existing 
 entities.  The value of nil would be fine, so I typed 'nil' in for Value 
 Expression on each end.  The compiler swallowed it OK.  Also, I added a Date 
 attribute, which I would like to default to NSDistantFuture, but since I 
 didn't know how to enter that, I entered 'nil' there also.
 
 Should these entries work?

You don't need to set optional property values to nil.  For relationships, you 
probably want to use the default expression.

 Is there any documentation which defines the syntax to be used for Value 
 Expression?  The two paragraphs at the bottom of this page [1] show a simple 
 example but not much detail.

The value expressions are the same as NSPredicate expressions.

Also,

NSMigrationMissingMappingModelError  = 134140

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Core Data design question: receiving KVO notifications of partially mutated objects

2009-11-02 Thread Ben Trumbull
 What is considered best practice when it comes to mutating many
 properties of a managed object, specifically with regard to KVO
 observers getting notified before all mutations are finished?

This is a problem intrinsic to the design of KVO.  KVO is all about fine 
grained per property notifications.  It's very well suited to that.  However, 
it's common for complex objects to be in an intermediate state during a KVO 
notification.

There's no better notion of cross-property coherence than refactoring into a 
different property object that encapsulates everything.

 Let's say I have an Rectangle object.  It has properties: colour, width,
 height.  Imagine some controller observing all these properties, perhaps
 to trigger a redraw.
 
 If I do:
 
 [rect setColour:...];
 [rect setWidth:...];
 [rect setHeight:...];

In this example, the best KVO can do is work with a colored rectangle object 
that in turn is the 1 property you work with here.  So, this would be an 
example of a granularity of notification that works better with 
NSNotificationCenter

 This is short and readable.  But observers will be notified after each
 setter.  

yup

 This could be a problem if intermediate states are not self-
 consistent and could also lead to unnecessary redrawing.  

And many other performance issues if observers recalculate things too 
aggressively.

 In the general case, I might not even know who is observing.

Well, that's the point of the notification pattern.

 
 I guess it's safer to create a setColour:width:height: method in my
 NSManagedObject subclass that does:
 
   [self willAccessValueForKey:@colour];
   [self willAccessValueForKey:@width];
 
   [self setPrimitiveColour:...];
   [self setPrimitiveWidth:...];
 
   [self didAccessValueForKey:@width];
   [self didAccessValueForKey:@colour];
 
 Is this what I should be doing?

Generally, no.  (setting aside, the calls should be to willChangeValueForKey:, 
btw)

If your issue is that drawing or recalculation is occurring too frequently 
after KVO changes, you can consider coalescing and deferring the observers' 
actions instead of performing them synchronously.  This can be valuable even 
for less complex KVO issues.

You could also refactor the 3 properties into 1 object.  Or use an 
NSNotification instead of KVO to adjust the granularity of notifications to 
better suit your drawing code.

This doesn't really have anything to do with Core Data.  However, for 
NSManagedObject, Core Data already provides the change coalescing and 
NSNotifications for you.  You can respond within 
NSManagedObjectContextObjectsDidChangeNotification instead.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Unable to open Core Data documents

2009-11-02 Thread Ben Trumbull
 I recently recompiled an existing project for 10.6.  I made no changes  
 to the code.  However, the resulting binary is no longer able to open  
 older files created by this program.  The error message is:
 
 The document „Budget.drachma‰ could not be opened. drachma cannot  
 open files of this type.

Hard to say with the information you've provided.  You should try in gdb

future-break +[NSError errorWithDomain:code:userInfo:]

and getting both a stack trace that's generating the error as well as the 
actual NSError object and its userInfo dictionary.

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Could not merge data-error on save in a single moc app

2009-11-02 Thread Ben Trumbull
 On 29.10.2009, at 20:05, Ben Trumbull wrote:
 
 I get a Could not merge changes-error on save in a single moc app
 (*). The docs state this is a problem of a multi-moc setup:
 
 http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdTroubleshooting.html
 
 
 Yes, the MOC you are saving refers to data that has changed out from  
 underneath it in either the PSC or the database file itself.  This  
 is an optimistic concurrency control failure.
 
 The error does not appear on every system and seems to be related to
 when save is called. (race condition?) So far I only have users
 complaining that run Mac OS 10.6. I can rarely reproduce the error
 myself.
 
 Any pointers where to look?
 
 Well, you can break on -[NSManagedObjectContext init], and -save: to  
 see if you really only have 1 MOC.  Other than that, breaking on + 
 [NSError errorWithDomain:code:userInfo:] and doing thread apply all  
 bt in gdb is usually helpful.
 
 
 I use garbage collection.
 
 regards
 Ruotger
 
 (*) the context is handed out by a singleton method. I NSAssert()  
 this
 method is only called by the main thread.
 
 Well, it's still possible for code to leak it to another thread if,  
 you say, pass NSManagedObjects around, and then ask them for their  
 MOC.
 
 - Ben
 
 Hi,
 
 I've checked all accesses to the moc and by using mogenerator I  
 generated files that assert that every single access of a managed  
 object is on the main thread. I still get the Could not merge data- 
 error or sometimes this one:

Which is neither here nor there.  This is a version conflict error not a 
multi-threading error (though MT errors can lead to versioning errors)

 Printing description of error:
 Error Domain=NSCocoaErrorDomain Code=1550 UserInfo=0x5d45490 balances  
 is not valid.
 
 balances is a one-way to multiple relation.
 
 Any more ideas?


Same as last time, break on the error, get it's userInfo, and a stack trace of 
all the threads in the app.

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Help debugging Dangling reference to an invalid object. Core Data error

2009-11-02 Thread Ben Trumbull
 On 10/29/09 5:23 PM, Ben Trumbull said:
 
 Even if I do [scene addTargetsWeak:[scene targetsWeak]] I get the error.
 
 Does this make any sense to anyone?
 
 The only caveat is you cannot change relationships from within -
 awakeFromFetch.  This is documented:
 
 Ben,
 
 This is something I know and avoid, but it turns out this is what's
 happening afterall!  Thanks!
 
 Is there some way to catch such violations?  I suppose I could implement
 all relationship mutating methods, call backtrace(), and look for
 awakeFromFetch. :)

Not really.  But you can file a bug, and we can add an assertion to the debug 
library easily enough.  Or we can enable change tracking in -awakeFromFetch.  
But that would mean generic setters will dirty newly fetched objects, and their 
containing documents, which people objected to, and resulted in the current 
behavior.

 Basically, I have a controller class that uses KVO to observe all kinds
 of things.  And I'm suffering from a kind of spaghetti chain of KVO and
 faulting.  In my observeValueForKeyPath:ofObject:change:context: I
 sometimes end up firing a fault of some object, which causes me to
 reenter my observeValueForKeyPath: for some other 'context', which ends
 up firing a fault of some other object, etc.  At some point
 awakeFromFetch is in the backtrace and at some later point I mutate a
 relationship.  Ick.

Well, you can use prefetching to disentangle dependent controllers from firing 
too much stuff too lazily, or custom controller classes that override 

- (BOOL)fetchWithRequest:(NSFetchRequest *)fetchRequest merge:(BOOL)merge 
error:(NSError **)error; 

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data design question: receiving KVO notifications of partially mutated objects

2009-11-02 Thread Ben Trumbull
 If your issue is that drawing or recalculation is occurring too
 frequently after KVO changes, you can consider coalescing and deferring
 the observers' actions instead of performing them synchronously.  This
 can be valuable even for less complex KVO issues.
 
 You could also refactor the 3 properties into 1 object.
 
 Alas, that would require 1) persistent store migration (painful on 10.5)
 and 2) I find it very handy to be able to bind 'colour' to a colourwell
 and 'width' and 'height' to text fields.  Perhaps I have bent my model
 too much in favour of my UI also. :)  But anyway, this 'Rectangle'
 object was just an example.  My real app is a bit harder to explain.
 
 Or use an
 NSNotification instead of KVO to adjust the granularity of notifications
 to better suit your drawing code.
 
 This doesn't really have anything to do with Core Data.  However, for
 NSManagedObject, Core Data already provides the change coalescing and
 NSNotifications for you.  You can respond within
 NSManagedObjectContextObjectsDidChangeNotification instead.
 
 Perhaps NSManagedObjectContextObjectsDidChangeNotification is the thing
 I have overlooked!  I currently use it almost nowhere but have tonnes
 and tonnes of KVO observing going on.
 
 I'll have to RTFM on NSManagedObjectC
 ontextObjectsDidChangeNotification.  Questions that pop to mind though:
 is it safe for me to fetch? to create/delete/mutate ManagedObjects?

I'd recommend performing a selector after delay 0.  You can inspect the objects 
and decide what you want to do with them.  The notification is posted from 
within the change tracking code, so making changes could possibly result in 
them getting caught in between 1 user event and the next.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: EXC_BAD_ACCESS when migrating a store, but only sometimes...

2009-10-29 Thread Ben Trumbull
 I've come across a rather perplexing problem which is driving me nuts.  
 I'm attempting to migrate a core data SQLite store to the current  
 model version, and most of the time it works fine. However, sometimes  
 I get an EXC_BAD_ACCESS in the following stack:
 
 objc_assign_strongCast + 19
 -[NSMigrationManager  
 migrateStoreFromURL:type:options:withMappingModel:toDestinationURL:destinationType:destinationOptions:error
  
 :] + 2750
 (My methods...)

If you can reproduce it in a small sample project (with your models, etc, but 
the least amount of custom code), then please file a bug.

One thing you might try is, before creating the NSMigrationManager with 
-[NSMigrationManager  initWithSourceModel:destinationModel:] is creating 2 
empty throw away PSCs, one that uses the source model and one that uses the 
destination model.  Then just release the PSCs and use those models to 
construct the NSMigrationManager.  That should work around the one known GC 
issue here.  

If you're not using GC, than try breaking out Instruments' ObjectAlloc with 
NSZombie detection.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Could not merge data-error on save in a single moc app

2009-10-29 Thread Ben Trumbull
 I get a Could not merge changes-error on save in a single moc app 
 (*). The docs state this is a problem of a multi-moc setup:
 
 http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdTroubleshooting.html
 

Yes, the MOC you are saving refers to data that has changed out from underneath 
it in either the PSC or the database file itself.  This is an optimistic 
concurrency control failure.

 The error does not appear on every system and seems to be related to  
 when save is called. (race condition?) So far I only have users  
 complaining that run Mac OS 10.6. I can rarely reproduce the error  
 myself.
 
 Any pointers where to look?

Well, you can break on -[NSManagedObjectContext init], and -save: to see if you 
really only have 1 MOC.  Other than that, breaking on +[NSError 
errorWithDomain:code:userInfo:] and doing thread apply all bt in gdb is 
usually helpful.

 
 I use garbage collection.
 
 regards
   Ruotger
 
 (*) the context is handed out by a singleton method. I NSAssert() this  
 method is only called by the main thread.  

Well, it's still possible for code to leak it to another thread if, you say, 
pass NSManagedObjects around, and then ask them for their MOC.

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Help debugging Dangling reference to an invalid object. Core Data error

2009-10-29 Thread Ben Trumbull

On Oct 29, 2009, at 16:55 , Sean McBride wrote:

 On 10/22/09 4:59 PM, Melissa J. Turner said:
 
 I have an entity 'Scene' with a to-many relationship to an entity
 'Target'.  The inverse relationship is also to-many.  Both relationships
 are optional and the delete rule for both sides is nullify.
 
 To repro, I delete all Scenes then try to save.  It gives:
 
 Dangling reference to an invalid object. = null;
 NSAffectedObjectsErrorKey = (
 BSScene: 0x2004ff940 (entity: Scene; id: 0x2004f32a0 x-coredata://
 FCE3E0E3-F187-4C44-BFC3-60D7AF3E579F/Scene/p343 ; ...
 
 This error gives only 4 hits with Google. :(
 
 The problem is that some Targets still have relationships to some
 Scenes!  How can that happen?  It seems like the delete rule is not
 doing its job.
 
 Does the object with the ID x-coredata://FCE3E0E3-F187-4C44-
 BFC3-60D7AF3E579F/Scene/p343 exist in the affected store? What happens
 when you call existingObjectWithID:error:?
 
 Do you know what version of the OS the bad documents were created on? A
 lot changed in the relationship handling area in 10.6 (for the better,
 really and truly ;-), so knowing whether your customers created them on
 10.5.x or 10.6.x would help narrow down the possibilities.
 
 Thanks Melissa and Ben for your replies!
 
 I have been working on this issue for days now and am getting
 increasingly confused. :)
 
 My coworker found a way to create a document (in 10.6.1) with almost the
 same problem as originally described (it complains about the inverse
 relationship instead).
 
 Examination of the XML document (as text) suggests that the object graph
 is ok.
 
 To repro: 1) open said document 2) delete a particular managed object 3)
 attempt to save - receive dangling reference error.  Repros 100%.
 
 I've also found that changing a particular line of my code prevents
 (100%) the error from occurring.  Said line only runs when the document
 is opened (as a result of a controller getting a KVO notification).
 
 The entities in question are Scene and Target.  Scene has a to-many
 'targetsWeak' relationship.  Target has a to-many 'scenesWeak'
 relationship.  They are inverses.  They are optional and nullify.
 
 The code snippet in question:
 
 NSSet* currentTargets = [scene targetsWeak];
 NSSet* additionallyDesiredTargets = some fetch result;
 BOOL isEqual = [currentTargets isEqualToSet:
additionallyDesiredTargets];
 assert (isEqual);
 //if (!equal)
 {
   [scene addTargetsWeak:additionallyDesiredTargets];
 }
 
 It turns out that isEqual is always YES in this limited repro case.
 Therefore, I don't really need to change 'targetsWeak' (the 'if' body).
 But if I do anyway (the commented 'if'), I get the 'dangling reference'
 error.  If I don't, I don't.
 
 Even if I do [scene addTargetsWeak:[scene targetsWeak]] I get the error.
 
 Does this make any sense to anyone?


The only caveat is you cannot change relationships from within -awakeFromFetch. 
 This is documented:
http://developer.apple.com/mac/library/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObject_Class/Reference/NSManagedObject.html#//apple_ref/occ/instm/NSManagedObject/awakeFromFetch

Otherwise, if this repros 100% of the time, file a bug and we'll take a look at 
it.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Core Data: Undoing Cut-Paste, Drag-Drop between documents

2009-10-27 Thread Ben Trumbull
 Although some users might expect that the employee moves from Document  
 2 back to Document 1, that does not happen.  Because each document has  
 its own managed object context and own undo manager, because Document  
 2 is active, the employee disappears from there.  But order to make it  
 reappear in Document 1, user also needs to activate Document 1 and  
 click Edit  Undo *again*.
 
 One could argue that there is no problem.  Mac Users understand that  
 Undo is per-document.  They will instantly realize that they did two  
 *do* operations in two different documents (Cut in Document 1, Paste  
 in Document 2) to get where they are at, so they expect that two  
 *undo* operations, one in each document, will be required to get  
 back.  A highly-skilled Core Data developer might even be able to set  
 the correct undo actions, Undo Paste Employee and Undo Cut  
 Employee, which will help cue in those users with unrealistic  
 expectations.
 
 But this answer is not as plausible if the user makes the move using  
 drag-drop instead of cut-paste.  (Drag-drop is not implemented in  
 DepartmentAndEmployees, but it is common in real apps.)  Clearly, the  
 user has now performed only one operation, and might rightfully expect  
 it to be undoable with a single Undo.
 
 I suppose that the developer of such an app could replace the undo  
 manager in each document, upon creation or loading, with a single,  
 common undo manager.  But I fear that this would cause hundreds of  
 unintended under-the-hood consequences in Core Data, and am loathe to  
 think about it.  Has anyone ever done this?
 
 Another alternative:  In the drag-drop implementation, before doing  
 the *delete* operation, temporarily disable undo registration in the  
 source document.  Then, explicitly register with the undo manager of  
 the destination document an action which would insert an object with  
 the old object's attributes into the source document's moc.  An  
 equivalent trick would probably work in a non-Core-Data document, but  
 I suspect that Core Data's under-hood magic wouldn't be too pleased  
 with this.
 
 In either case, there's the little issue of what if the source  
 document is closed, then later this Undo action gets invoked.  Setting  
 a flag to say that you've got Document 1's stuff on your undo stack,  
 and removing all undo actions when Document 1 is closed would probably  
 be a good idea, but this is starting to get messy.

You can queue up and control the undo actions in each document's undo manager.  
But you're still left with the problem that undo will be wired to the front 
most document, and there's no meta-undo manager for cross-document undo 
operations.

I don't see how this is a Core Data issue.  Either you can coordinator undos 
across multiple different undo managers, or you can't.  Well, I suppose unless 
you want to have all your documents share an undo manager, which Core Data 
won't like.  But that's crazy talk :-)

As a user, I would never expect undo to go modifying the contents of other 
windows in a document based app.  Take TextEdit for example.  The behavior you 
suggest is completely inappropriate for TextEdit.  I have separate documents 
because I'm working on separate things.  I'd be pretty frustrated if I couldn't 
move things between documents without borking undo.

The behavior you describe is more commonly associated with non-document apps 
like iCal or Address Book.  They use a single undo manager for the user edits.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Search on Core data Table issue?

2009-10-22 Thread Ben Trumbull

Not sure if this is the right place (I am sure someone will let me
know if it is not)  I have a iPhone application that has a UITable
view that is backed by core data.  I want to perform a reducing search
so that only the items starting with the characters entered into the
search bar are shown.  This is normally done with delegate - (void)
searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)
searchText no problem.  I am a little confused as I am new to Core
Data how to do this.  One of the big problems as I see it is going to
be updating the interface to let it know what to present.  I assume an
alternative NSFetchedResultsController needs to be sent to the
UITableView.


You're basically on the right track.


So here are my issues:
1) I assume I need to create a  NSFetchedResultsController with only
the correct items in it then tell the UITableView to use this as the
dataSource and reload the table?


Yes.  Most of the Apple apps use an overlay, so it's also a different  
UITableView entirely.  See search in the Contacts app, for example.



2) is there a better way than executing a full sorted fetch and
removing those objects that do not conform.  ie is there a way of
doing a select where type fetch?


I'm not sure exactly what you mean by select where type fetch.  What  
type ?


The typical pattern is if the user typing has gone from a 0 length  
string to a 1 character string, you'll need to do a fetch.  (that  
includes the user deleting a character and starting over).  If the  
string already has 1 or more characters, you can choose between a new  
fetch, or simply an in memory filter of the previous results.  The  
results should always be sorted, so you can binary search the range to  
filter, instead of filtering all the strings.


The balance of when to fetch and when to filter is complicated, and  
depends on your data set, as well as your UI.  If you have an  
extremely large data set, you should use a fetch limit, so that the  
user cannot get back all the results until they've entered a  
sufficiently discriminating search string.  If the number of results  
you get back is equal to the fetch limit, you can consider executing a  
count request or just saying and more


If the number of results is small, then it's much faster to filter the  
old results in memory.  Fetching will save you a lot of memory, but it  
is I/O so it has a high fixed cost (like ~2ms on a desktop).  You'll  
want to balance the two.  You might start out with a threshold of 100  
and tune from there.



Thanks in advance and sorry if this is a dumb question.


It's not.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Help debugging Dangling reference to an invalid object. Core Data error

2009-10-22 Thread Ben Trumbull
 Core Data is giving me a validation error when I try to save a document
 after making a simple change.
 
 I have an entity 'Scene' with a to-many relationship to an entity
 'Target'.  The inverse relationship is also to-many.  Both relationships
 are optional and the delete rule for both sides is nullify.
 
 To repro, I delete all Scenes then try to save.  It gives:
 
 Dangling reference to an invalid object. = null;
 NSAffectedObjectsErrorKey = (
  BSScene: 0x2004ff940 (entity: Scene; id: 0x2004f32a0 x-coredata://
 FCE3E0E3-F187-4C44-BFC3-60D7AF3E579F/Scene/p343 ; ...
 
 This error gives only 4 hits with Google. :(
 
 The problem is that some Targets still have relationships to some
 Scenes!  How can that happen?  It seems like the delete rule is not
 doing its job.

This error happens when the MOC for a destination object is nil, the object is 
in a relationship but marked deleted, or the object in a relationship has a 
temporary objectID but is not marked inserted.  Using 
refreshObject:mergeChanges:NO on an object with pending changes can do some of 
that, as can assigning a deleted object to new relationships after delete 
propagation has run.

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: odd behavior with NSError?

2009-10-16 Thread Ben Trumbull

(response is pedantic for the purposes of the archive :)


even more better flaming pedanticism!


On Oct 15, 2009, at 10:41 PM, Nathan Vander Wilt wrote:


Ouch. So the following pattern is incorrect?


Yes;  it is incorrect.


NSError* internalError = nil;
(void)[foo somethingReturningBool:bar error:internalError];
if (internalError) {
  // ...
}


Specifically, assuming anything about the value of 'internalError'
without first determining the return value of -
somethingReturningBool:error: returned a value indicating an error
(typically NO/0/nil/NULL) is an error.


The specific issue is failing to check the return value of the method  
before touching the internalError value.  You MUST check it.


However, the documentation also encourages not assigning nil to local  
NSError* declarations.  Not initializing locals is imho,  
professionally, realistically, and morally wrong.  It's just a bug  
waiting to happen.  And you have to know it is, just looking at it.   
Whatever might have been saved / gained by not initializing them was  
wasted, for all of time, the first time I had to debug the segfault.   
Which I did, like an idiot, a long time ago.


Let me just say I really especially appreciated the time spent  
debugging other people not initializing their locals.  It wasn't  
visions of sugar plums.


Other people have different perspectives on local variable  
initialization.  Wrong perspectives, but different.  Fortunately now,  
they waste their arguments upon the merciless http://llvm.org/img/DragonFull.png 



- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Default Core Data errors

2009-10-14 Thread Ben Trumbull
Do you check, and at least assert, if any API that has an NSError**  
parameter returns one ?  (typically a return value of NO or nil).  For  
Core Data, you'll always want to check adding a store to the  
coordinator, saving, and fetching.  For your documented based app, the  
NSDocument APIs can also return errors.


When you get an NSError, you'll want to also log its userInfo  
dictionary.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: CoreData could not fulfill a fault after Save As

2009-10-14 Thread Ben Trumbull

The short description is this - I have a document based CoreData app.
I can carefully craft a set of data. I then open the document, select
a particular record, and do a Save As. This works fine. But when I
select a second record, I get errors that CoreData could not fulfill a
fault. If I quit the app and re-launch it, I can operate on the copy I
just saved w/o issue, so apparently the data is there. I haven't a
clue what the problem is.


Does your app run correctly on 10.5.* ?  There's a known regression  
similar to this in 10.6.0 and 10.6.1.


If this reproduces on a system other than 10.6.0 or 10.6.1, please  
file a bug.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Default Core Data errors

2009-10-14 Thread Ben Trumbull


On Oct 14, 2009, at 12:21 PM, Rick Mann wrote:

In the simplest case, I don't create any entities. I don't override  
any of NSPersistentDocument's persistence-related methods. I just  
save the new untitled document, then try to re-open it.



You can override the methods declared in NSPersistentDocument.h  
particularly configurePersistentStoreCoordinatorForURL and  
readFromURL, and just call super.  But look at the BOOL result and if  
NO, the NSError.


You can also grab the error in the debugger as others have suggested.

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: More Core Data Questions

2009-10-13 Thread Ben Trumbull


On Oct 13, 2009, at 3:17 AM, Jon Hull wrote:

You don't need proxies or NSProxy for this.  You can just use a  
delegate.  Off the cuff, I might consider implementing a protocol  
on your immutable objects for methods like currentLocation and  
currentPlayer which vector through a semi-global context object  
not unlike the app delegate.  Then you can use keypaths to  
naturally write currentPlayer.name and so forth.  NSProxy is  
unnecessarily heavy weight for simple delegation.  They use memory  
too, ja know.  And the semi-global context allows you to avoid  
making all your objects larger.  You might even model the current  
state as a formal entity.  That buys you change tracking, undo,  
multi-writer conflict resolutions and the ability to easily  
persistent and search for it.  It also allows other managed objects  
to work with it naturally.
Hmm... something to consider.  The proxies do allow some powerful  
runtime state effects.  The currentLocation was just a simple (and  
often used) example, but it is easy to have proxies which represent  
The sister of the person I am currently talking to or the location  
of that person or the item which that person holds in their hand.   
They can also be used to represent groups of characters.  This is  
very powerful, and has come in very useful.  Still, it might be  
possible to get the same functionality in another way.


Okay.  Typically the Cocoa way of doing that is by name and using  
keypaths instead of by pointer value and NSProxy.


and then call off  to the manager with the id whenever they need  
to run an event.  Inside
the manager I would either call off to a small sql database with  
blobs

holding freeze-dried (keyedArchiving) objects  an id column,


not a great plan.  No searching into blobs, no partially loading or  
saving the larger freeze dried objects.
hmm...  The largest blob would probably be an object with an array  
of 20 or so pointers/ids.  Not sure I need to search into them...  
mostly I just need to grab them by id.


I had considered just using core data for everything, but as I  
mentioned in a previous post, I *need* to have consistently ordered  
arrays of these immutable objects (which can be in multiple places  
in a single array, and can be in multiple arrays).  This is  
apparently difficult using core data :-(


It's not difficult, although it is a bit tedious.  Ordered  
relationships require you model the join table between two entities  
yourself (for many-to-manys), and add an ordering attribute.  For one- 
to-many, you can put the ordering attribute on the destination entity  
(no join table necessary).


Although, now that I think about it, perhaps I can store *just* the  
array of ids as a binary property, and have everything else defined  
in the entity.  I will have to do some experiments.


Yes, you could do that.


Also, you could do that trivially with Core Data and just be done.
Do you mean store the blobs in a core data managedObject instead of  
a SQL database?


yes


or avoid the blobs entirely using core data?


Probably

Unfortunately, it sounds like you don't have a ready alternative  
besides to spend a considerable amount of your own engineering  
resources.  You'll have to decide if learning Core Data, and tuning  
your app performance fits within your schedule requirements, and  
whether implementing, debugging, and tuning all this yourself will  
really take any less time.


You might consider mocking up a Core Data version over a few days  
and seeing how far you get.


Yes, I think I will try that.

Any advice on how to handle the 2 different types of graphs  
mentioned in my earlier post?  Ideally I should have 2 files. One  
holding the event tree and one holding the rest (i.e. the stuff that  
changes).  They main problem there is that they have connections  
between each other (e.g. an event might take a location or character  
as a parameter)



Just create two stores and add them to the same  
NSPersistentStoreCoordinator.  The connections between them can be  
represented via keypaths (bound dynamically) or persistently by  
stashing the objectID's URI away and materializing it in a transient  
relationship in -awakeFromFetch


- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Saving for iPhone - Can core data handle this?

2009-10-12 Thread Ben Trumbull

Jon,

Your question is a bit amorphous.  Can Core Data do something like  
this ?  Sure.  May it require adjusting things to fit into its  
architecture ?  Possibly.



I have a game project for the iPhone which has a rather complicated
object graph


Well, it would probably only take a few minutes to mock something up  
in the model editor in Xcode.  That would help make your question more  
concrete.



There is a large graph of tiny immutable objects which represent the
story (including different branches of the storyline).


How tiny is tiny ?  People have widely different ideas about tiny  
and huge and the difficulties of various problems.



This graph is
large enough that I only want to keep the nodes that are actually
being used in memory.


100 objects ?  1,000 ?  100,000,000 ?  The largest db in a deployed  
iPhone app using Core Data that I know of is about 450,000 rows.  (FDA  
warning: results not typical)



There is also a separate graph of game objects
(characters, etc...) that change state over time and will need to be
saved as part of a saved game.  These seem like they should be stored
separately since one never changes and will be common for all players,
while the other is different for each player.  I also want to be able
to get a fresh copy of the changing objects for new games.


Is this for local or remote data ?


The final complication is that I have several proxies being used in an
important way, and I don't think there is any NSProxy equivalent for
NSManagedObject.  I guess I would just have to hope that
NSManagedObject doesn't have any methods that the targets of the proxy
override.


Uhm...  Why ?  I don't think NSManagedObject will be happy with  
NSProxy and vice versa.  I'd recommend against this.  If you need to  
use NSProxy for something else, then I'd recommend adding an observer  
to the NSManagedObjectContext and proxying your custom observer.  Or,  
you can use composition to create your own object that has an  
NSManagedObject || NSManagedObjectID ivar and then proxy that.



I have been reading the docs for Core Data, and have a rough idea on
how I might accomplish all of this, but I wanted to see if someone had
experience with this and could keep me from spending time going down
the wrong path if it isn't going to work.

So, do you think core data can handle this?  What approach (roughly)
should I use?


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: CoreData Bug? (SQLite vs XML) + isolated reproducible case

2009-10-12 Thread Ben Trumbull
Thanks for the test project.  However, reviewing and fixing all  
compiler warnings is likely to make development a significantly less  
frustrating experience.  We've taken to fixing (nearly) all compiler  
warnings, even ones we know are harmless, so we can easily find the  
new ones that likely aren't.  A lot of people like -Werror for exactly  
this reason, but that's a bit too draconian for my taste.



CoreDataBug_DataModel.xcdatamodel:SmartFolder.sources: warning:  
SmartFolder.sources -- to-many relationship does not have an inverse:   
this is an advanced setting (no object can be in multiple destinations  
for a specific relationship)


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: More Core Data Questions

2009-10-12 Thread Ben Trumbull

Ok, let me ask some more specific questions and see if that gets a
response...  Feel free to respond if you only know the answer to 1 or
2 of these.

1) Can I count on a to-many relationship keeping the order of the
managedObjects it points to?  The order is very important in this
case, and I need a way to ensure that the order does not change when
the object is saved and reloaded.


No.  You'll have to model order as an attribute yourself.


2) Does core data require a run-loop to work?


No.


3) What is the best way of connecting objects from different stores?
I am considering giving them UUIDs and then storing that as a
reference.  Then setting a transient property based on that in -
awakeFromFetch.  Alternatively, I could store it as a fetched
property, but I want it to be a 1:1 correspondence.


That's fine, although you can just use the URI representation of the  
destination object instead of creating your own separate UUID.  You  
might look at /Developer/Examples/CoreData/iClass



4) Is there a better way to get this lazy loading?


What was the first way ?


 My main goal is to
keep only those objects from this large (1000) object graph in memory
that are needed (since the iPhone has limited memory).


You may find the NSFetchedResultsController useful, as well as the  
options on NSFetchRequest like -setFetchBatchSize:  They are very  
aggressive about memory optimizations.



Basically, I
want the behavior of the old resource manager from the olden days
(that is I can act as if my full object graph is in memory, but only
those that are needed actually are... and they are fetched just in
time).


Core Data always does that.  That's the default with its SQLite  
persistent store.


Are you making this more complicated than it needs to be for  
performance issues you have yet to measure ?  I wouldn't add multiple  
stores to work around a performance issue before actually trying it.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: More Core Data Questions

2009-10-12 Thread Ben Trumbull




The project is a game engine which has 2 graphs.  The first is a tree
of events that represent the story.  Each event in the story is an
immutable object, and there is a special event which represents a
series of events to run in order and one which represents branches
that the player has to choose from.  All of these are immutable, and
the main goal is to avoid loading the whole graph which will consist
of 10k-50k events.  This graph will be the same for every player.


Okay.  If you build this immutable store on your dev machine and  
include it in your project resources, you should see excellent  
performance.  Creating a store this size on the device would take a  
while.  Just don't go crazy with to-many relationships or database  
normalization (for this many objects, on a phone).


Of course, you don't want to search across all the events all the  
time.  You'll want some criteria (NSPredicate) to evaluate just the  
subset of relevant elements.



I also use proxies as context switches to objects in this
graph.  A concrete example is the current location, which is a proxy
that pretends to be a location, and forwards all the messages it
receives to the location object where the player is currently
located.  This allows events which reference locations/players/etc
that change depending on state to remain immutable.


You don't need proxies or NSProxy for this.  You can just use a  
delegate.  Off the cuff, I might consider implementing a protocol on  
your immutable objects for methods like currentLocation and  
currentPlayer which vector through a semi-global context object not  
unlike the app delegate.  Then you can use keypaths to naturally write currentPlayer.name 
 and so forth.  NSProxy is unnecessarily heavy weight for simple  
delegation.  They use memory too, ja know.  And the semi-global  
context allows you to avoid making all your objects larger.  You might  
even model the current state as a formal entity.  That buys you  
change tracking, undo, multi-writer conflict resolutions and the  
ability to easily persistent and search for it.  It also allows other  
managed objects to work with it naturally.



The event graph is traversed from a background thread which basically
runs through events in order until it needs a user response.


Surely most of the events are not relevant most of the time, no ?  By  
location, if nothing else like pre-requisiste events.  If you can keep  
a cookie into the player's choices tree, then you can do an indexed  
query on eligible events and only evaluate those in memory.



 I have a
controller set up which communicates with the main thread, and the
background thread blocks until the controller gets a valid response,
at which point it starts unwinding again until it needs another
response or reaches the end.  There is no run loop for this thread.


sure.  don't forget an autorelease pool.


All of this works fantastically for the game, but now I have reached
the point where I can no longer put off save  load.  When I started
the project Core Data was not yet available on the iPhone, so the
design did not take it into account.  I was thinking that core data
might be able to help me save  load these graphs, but now I am not so
sure.  My new plan is as follows:

Create a manager singleton for events which returns an event object
for a given id, and then modify the special events mentioned above to
hold an event's id instead of actual event objects,


You could do that.  Probably easier to just use an  
NSManagedObjectContext and the delegate I mentioned above.


and then call off  to the manager with the id whenever they need to  
run an event.  Inside

the manager I would either call off to a small sql database with blobs
holding freeze-dried (keyedArchiving) objects  an id column,


not a great plan.  No searching into blobs, no partially loading or  
saving the larger freeze dried objects.


Also, you could do that trivially with Core Data and just be done.


or save each event as a file with the id in the filename.


Each event file would have to be  8K before this even begins its  
distant journey to approach making any sense at all from a performance  
perspective.


I would also have a  cache in the manager to avoid reallocating  
objects unnecessarily.


I wouldn't worry about caching just yet.  Bigger fish.

I  would prefer to have something like core data do this lazy  
loading for

me, but it may not work in this case.

For the objects that store state, I will just archive them into a save
file.


still no lazy loading or incremental saving.


Thoughts?  Does this sound like a reasonable approach,


Not really, no.  Maybe you need to do something quick  very dirty for  
deadlines.  c'est la vi



or will core data actually work for me?


It's not clear to me why you think it wouldn't.So far, all I get  
is that you haven't used Core Data before and don't know it.  Which,  
btw, is a perfectly valid issue to be having as you consider 

re: [iPhone} Exception After Creating First Object

2009-10-10 Thread Ben Trumbull

I got a couple of private messages about breakpoints and
stacktraces, which, of course, I had done before I posted my
question.  That's how I discovered that [mod
processPendingChanges] led to an exception when adding to an
empty database table.

I learned a little more about the exception.  It occurs in
[self.tableView endUpdates] which is  invoked, I think, as a
result of [moc processPendingChanges].

I have had problems in the past with [self.tableView endUpdates]
with empty database tables but thought that this time was
different.  Previously, I had tried preventing [self.tableView
endUpdates] being called when the database tables was empty but
that caused other problems (e.g. my Add Entity Name button
didn't appear when the database table was empty).

I've seen others mention problems with [self.tableView
endUpdates].  Does anyone know how to make [self.tableView
endUpdates] less vulnerable when the associated database table
is empty?


Steve,

Which version of iPhoneOS SDK are you building for ?  This sounds like  
an issue that was fixed in 3.1.  There has been more discussion of  
known issues and work arounds for the NSFetchedResultsController on  
the devforums.  You might try searching them, or looking at  https://devforums.apple.com/message/100783#100783 



- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: CoreData async fetch request

2009-10-08 Thread Ben Trumbull


On Oct 7, 2009, at 10:12 PM, David Melgar wrote:


Hello,
I didn't mean to state threads as a requirement when I said async,  
I just meant some way to get partial results, such as a call to a  
delegate I referenced in the previous note. And I'm certainly not  
seeking complexity of threads if I don't need it.


There isn't a simple way to do this.  There is, however, a simple way  
to make your queries (in both Core Data, and direct SQLite) 100x faster.


In my case, == is not the query I need. I really want case  
insensitive match as I presumed LIKE would do, or better yet, 'LIKE  
foo%'.


Great.  The Derived Property sample project on ADC shows you exactly  
what you need to do for replacing LIKE foo or LIKE foo%



In the meantime, I've just completed a test using SQLite.
The query in Coredata using 'LIKE foo%bar' across roughly 8 million  
records didn't return anything until the query was done, and the  
query took 2min 14sec,


This runs through ICU, and cannot use an index.  It can trivially be  
made 100x faster, at least for equality, prefix, and suffix matching.


What's the actual SQL Core Data logs ?

Doing what I interpreted to be equivalent using SQLite across 20  
million records returned in 11 seconds


What was the actual SQL you believed equivalent ?

and I was able to get my first result almost immediately without  
needing threads. They provide a callback scheme, analogous to  
calling a delegate in Cocoa. FYI, this is across 20 different  
databases, otherwise it may have been faster.


For what I'm doing, SQLite seems much faster, smaller footprint and  
easier to comprehend. I don't understand what I'm losing.


In your note you mention the cost of doing unicode aware regex and  
sorting. As far as I know, I don't need any of those, at least not  
yet.


All of your data is 100% 7 bit ASCII ?  None of your customers will be  
Asian, European, or Hispanic ?  None of your English customers will  
expect Unicode data that they copy and paste into your application  
from Safari to be preserved correctly ?


If your answer is no, then you'll need to implement your own string  
matching operations for SQLite using either CFString or ICU.  SQLite's  
built in operators use memcmp().  Once you've done that, I'd love to  
see the performance results.



I took a brief look at the derived property example. Seems complex.


What about the example seems complex ?  Everything you need is in 1  
file, that's got 107 lines of code.  You can just copy and paste that  
code.  Make a searchText column that has preprocessed the text data  
into a simpler form that can be used with an index and a simpler query.


You say you want to do a case insensitive search across 20 million  
rows.  You could absorb the cost of that, relative to a simple binary  
bitwise compare, for each of the 20 million rows.  And pay it again  
every time you execute a query.   Or, you could store a preprocessed  
column, and absorb that cost for just 1 string, the current search  
term foo


Perhaps for ASCII case insensitivity, that doesn't seem particularly  
interesting.  But once you start dealing with real world text  
encodings, which every Mac OS X and iPhone OS customer expects from  
every app, this becomes a big deal.  Unicode is complex and difficult  
to work with.


Something the framework should give me an option to handle rather  
than me having to generate such complex code. Does it advocate  
creating another field in the database as a normalized version of  
the field I really want to search on?


Yes.


Why would this be better than using SQLite directly?



Doing this in SQLite directly will also be 100x faster than what  
you're doing now.  Regardless of whether or not you decide to use Core  
Data, this would be better.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data KVO with To-Many Relationships

2009-10-08 Thread Ben Trumbull

Since my previous post, I have been able to get the functionality I
was hoping for with the following code in my Department subclass. I
would greatly appreciate some feedback as to whether this is an
appropriate way to implement the functionality or if there is a more
efficient or cleaner way.


KVO doesn't have an easy way to observe a collection's contents, so  
the NSNotification approach is your best bet.



- (void)awakeFromFetch {
   [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(managedObjectContextDidChange:) name:
NSManagedObjectContextObjectsDidChangeNotification object:[self
managedObjectContext]];
}

- (void)awakeFromInsert {
   [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(managedObjectContextDidChange:) name:
NSManagedObjectContextObjectsDidChangeNotification object:[self
managedObjectContext]];
}


Most people use a 3rd object to do this instead of having the  
individual managed objects.  You can have an innocent bystander  
observe the NSManagedObjectContextObjectsDidChangeNotification, see if  
any interesting objects have changed, and then ping them to recompute  
whatever you need.  Much easier to manage registering and  
unregistering observers.



- (void)managedObjectContextDidChange:(NSNotification *)notification {
   // Get a set containing ALL objects which have been changed
   NSSet *insertedObjects = [[notification userInfo]
objectForKey:NSInsertedObjectsKey];
   NSSet *updatedObjects = [[notification userInfo]
objectForKey:NSUpdatedObjectsKey];
   NSSet *deletedObjects = [[notification userInfo]
objectForKey:NSDeletedObjectsKey];

//this method of gathering changed objects is because the final set
was always null if the first set was null
   NSSet *changedObjects;
if([insertedObjects count]  0){
		changedObjects = [insertedObjects  
setByAddingObjectsFromSet:updatedObjects];
		changedObjects = [changedObjects  
setByAddingObjectsFromSet:deletedObjects];

}else{
if([updatedObjects count]  0){
			changedObjects = [updatedObjects  
setByAddingObjectsFromSet:deletedObjects];

}else{
changedObjects = [NSSet setWithSet:deletedObjects];
}
}

if([changedObjects intersectsSet:[self employees]]){
   //if an employee in this department changed, indicate
that the totalSalary attribute should be refreshed
[self willChangeValueForKey:@totalSalary];
[self didChangeValueForKey:@totalSalary];
}   
}


That's the basic idea, but it's easier and faster to do that once, in  
one master observer, than in each managed object.


- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: CoreData async fetch request

2009-10-08 Thread Ben Trumbull


On Oct 8, 2009, at 8:28 PM, David Melgar wrote:

I read a little on ICU and now understand that sqlite by default  
does not handle case insensitive unicode.
Is there an easy way to make sqlite use ICU on the Mac, or do I have  
to build it myself with ICU enabled?


Probably the easiest thing to do (besides just using Core Data) is  
register custom functions with the SQLite API that go through  
CFString.  The SQLite APIs for this are fairly straight forward.  The  
ICU dylib on Mac OS X is not public API.  There are a variety of  
references to building ICU or otherwise addressing this issue on the  
web.  Should you do that, you can register custom functions leveraging  
ICU with SQLite as one would using CFString.  I'd strongly recommend  
against building and statically linking SQLite yourself.


Based on the derived property example, it seems that I would need to  
duplicate any text fields I commonly search on where I want to  
support case insensitive queries.


Yes, for data sets of this size.  For smaller data sets, in the 10^2  
or 10^3 range, you might decide to skip this and accept slower  
queries since they'll probably be around 5ms - 20ms.


How does spotlight manage to index so much text and respond quickly?  
Are those queries can insensitive?


Spotlight supports insensitive queries.  Spotlight also duplicates  
much of the material for its index.  The importing process is not  
free.  You're certainly welcome to put all your data into Spotlight  
and test its query performance for your purposes.  Spotlight is  
fundamentally a full text search index.  It's optimized heavily for  
prefix and word searching across very large numbers of documents.   
It's very good for its intended usage pattern, but that pattern is not  
the same as the usage of relational databases.  The technologies are  
complementary.


I've done a bunch more performance tests. I don't understand some of  
the differences.
I hadn't realized that coredata in the data model has a flag to  
index a field. When I did that for Coredata, it dramatically sped it  
up. Although adding an index to my sqlite test slowed it down.


Your test results are very odd, in that they are still 50x to 100x  
slower than I would expect.  These tests have not yet applied the  
derived property optimization I suggested, correct ?


As literally noted here, none of those queries are eligible for an  
index, so I assume your actual code is doing something slightly  
different, or the timing difference are due to configuration issues.
Hot I/O and cold I/O will be very different.  For example:


search, without an index (cold I/O)
add an index (page everything into the UBC cache)
search, with an index, but a query that doesn't use the index (hot I/O)

The difference between hot and cold I/O for query performance will be  
huge.  As much as 100x.  You can use /usr/bin/purge to force  
everything to be cold I/O.  Not necessary representative of real world  
performance, as the whole disk cache will be flushed, including  
material relevant to the system that would normally exist when you run  
your app.


Coredata, without an index, predicate name like foo, 20 databases  
400k records each. 2m17s.
Coredata with an index, predicate name like foo, 20 databases 1mil  
records each, 25 seconds.
SQLite no index, sql where name like foo%bar, 20 databases 1mil  
records each 11 seconds.
SQLite index, sql where name like foo%bar, 20 databases 1 mil  
records each 30 seconds.


Why the 20 database files ?  These queries will be faster with a  
single database file and its unified index.


In any event, the derived property optimization should make all the  
prefix/equality queries subsecond.  On my laptop, for 20 million  
records, that should be in the 500ms ballpark (hot I/O)


As you said, with an index, and testing for equality, both coredata  
and sqlite queries responded in 1 sec. SQLite without an index was  
9 seconds for same query.


That sounds about right.  It'll be faster if you use a single database  
with 20 million rows and a unified index table.


I can only presume SQLite slowed down with an index because the  
database file was physically much larger and took longer to read  
from disk.


I suspect its a flaw in the testing methodology, actually.  Do you run  
the queries multiple times, throw out the best  worst and average the  
rest ?  Are you running other apps at the same time you do performance  
tests ?


It is possible for the presence of an index to negatively impact a non- 
indexed query, but that would be a few %, not 3x slower  An indexed  
query would read many fewer pages from disk than a non-indexed query,  
regardless of the file size.  O(lg(N)) instead of O(N) and at 20  
million that's a big difference.  There are other possible issues in  
play, but you said the result set is small, so they seem unlikely.


- Ben

___

Cocoa-dev mailing list 

Re: CoreData async fetch request

2009-10-07 Thread Ben Trumbull


On Oct 6, 2009, at 8:29 PM, David Melgar wrote:


Hello,
Thanks for the response. Seems that its straying somewhat from my  
original question.


Sure, your original question is that you have a serious performance  
issue, and you'd like to hide it from the user by adding threads.  I'm  
proposing fixing the performance issue instead, and not bothering with  
the additional complexity of threads, at least until you have 100  
million rows or so.


For the 1.4 million row db I have handy, the indexed == query runs  
over 100x faster than the LIKE query.   == returns 4 rows out of 1.4M  
in 4ms and LIKE returns 4 rows in 450ms.  So, on my 2007 Mac Pro, your  
10 million row database would run in its query in less than 100ms.   
Too fast for meaningful human perception.  Do we really need to add  
threads for this ?  The code to incrementally and asynchronously  
display the results will probably take longer than Just Do It.


Searching based on prefix matching is fine.  The predicate I'm using  
really is of the form SELF like foo, no wildcard, so it doesn't  
seem that it should be that expensive.


Locale aware Unicode regex is very expensive.  Unicode is the worst  
possible text encoding system ever conceived, except for the others.   
Core Data insulates you from this so that your searches behave like OS  
X customers around the world expect.  You're welcome to learn all  
about Unicode and ICU, and work with it directly in SQLite if you  
prefer.  It'll take a lot of code to make searching and sorting work  
for every locale.


You say its possible to structure this to use a binary index. How? I  
don't see any mention of indices in the Coredata documentation.


See the Derived Property example on the ADC web site that I've  
referenced repeatedly.  However, if you're not using any wildcards,  
and your search is case sensitive, then you might as well just use ==  
and be done.  Be sure to add an index to the attribute in your model.


If I use SQLite directory, presumably I can set indices on the  
fields I want and more closely manage the data model.


You would presume incorrectly.  Generally, LIKE queries are not  
eligible for indices.  There are some special circumstances where they  
can be, but that won't work with Unicode.  You're welcome to verify  
that for yourself.


I don't see how setBatchFetchSize helps. Doesn't it just limit the  
number of results returned?


No.  It's more closely an in memory cursor.  It will require the  
entire WHERE clause execute, which unfortunately is your primary  
problem, but it will not restart the query as you stream through the  
results.


I have no idea how quickly the results will come in. Setting a size  
1 is therefore indeterminate and may take the full 3 minutes. If I  
set it to one, and I want to try and get the second row as well, it  
appears that it starts the query all over again, worst case  
resulting in 6 minutes before the 2nd result shows up. Doesn't seem  
that it scales reasonably if I want to display the first 10-20  
entries.


No, -setFetchBatchSize does not restart the query.  That's what using  
fetchOffset does (in the database, not Core Data, which is why we  
wrote fetchBatchSize ourselves)


My issue with Coredata is that it NSFetchRequest always returns ALL  
the results of the particular query at one time. If I use SQLite  
directly... assuming it supports cursors, I can get each result one  
at a time as they show up, display it to the user without slowing  
down the query as it continues to find other results.


If you try using -com.apple.CoreData.SQLDebug you will see both the  
SQL we pass to SQLite, and some performance annotations like:


2009-10-07 17:52:15.107 Address Book[13949:5403] CoreData: annotation:  
sql connection fetch time: 0.0013s
2009-10-07 17:52:15.108 Address Book[13949:5403] CoreData: annotation:  
total fetch execution time: 0.0020s for 14 rows.


The first line is how much time was spent in SQLite.  If you run this  
with your text queries, you'll see most of your time spent there.   
Switching to use SQLite directly is not going to change that.  Again,  
you should verify that for yourself.


NSFetchRequest could support a delegate to invoke some method when  
for each item that has been found, rather than blocking until all  
the results are received.
It also could have been implemented as a virtual queue, an object  
which could be read from while being written to in another thread.


That would make an excellent feature request.  Please file it with 
bugreport.apple.com

But if you take my advice and make the query run in 1.8s instead of  
180s, how important is this to you ?


- Ben


On Oct 6, 2009, at 4:08 AM, Ben Trumbull wrote:



On Oct 5, 2009, at 7:00 PM, enki1...@gmail.com wrote:

I am doing a simple query search for a text string pattern (ie  
'SELF like foo') on ~10 million small records stored persistently  
using sqlite. This is a performance test to make sure I get

Re: CoreData async fetch request

2009-10-06 Thread Ben Trumbull


On Oct 5, 2009, at 7:00 PM, enki1...@gmail.com wrote:

I am doing a simple query search for a text string pattern (ie 'SELF  
like foo') on ~10 million small records stored persistently using  
sqlite. This is a performance test to make sure I get reasonable  
performance from my database engine before I commit too much code to  
it.


Well, @self like 'foo' is a different problem than @self like  
'*foo*'.  LIKE queries require Unicode compliant regex and are  
intrinsically expensive.  If you do not have a wildcard, you are  
better off use an == query.  The DerivedProperty ADC example shows how  
to transform the text to make it much faster to search.


If you do need to use a wildcard, you'll really want to stick with 1,  
either prefix matching or suffix matching.  The DerivedProperty  
example shows prefix matching.  It's possible to structure this to use  
a binary index, and make the query extremely fast even for millions of  
records.  There is a huge difference in computational complexity.   
Prefix matching can use an index, and therefore can run O(lg(N)).


*foo* (contains) searches are slow, and cannot use an index.  You  
really want to avoid these.  Even Spotlight does not do arbitrary  
substring matching.  Compare help with elp in your Spotlight  
results.  If you want word matching, you can use Spotlight or  
SearchKit to build a supplemental FTS index.


The query is taking over 3 minutes with a small result set. This is  
on a new 13 macbook pro w 4gb memory.


... a full table scan executing a regex on each of 10 million rows on  
a 5400 rpm drive ?  Well, for doing all that, 3 minutes sounds pretty  
fast.


Just as a reference point, if you grab the objectIDs from the result  
set, and execute an IN query selecting those objects, how long does it  
take ?  50ms ?  100ms ?


The query is taking too long for a user to sit and wait for it. Is  
there a way to speed it up? Can indexing be applied to it?


I had thought if I could display results as they are found that  
might be reasonable. In my tests, if I use setFetchBatchSize and  
setOffset to restart it, then it ends up repeating the query taking  
that many times longer to get a result. Not reasonable. It does not  
seem to start the query where it left off, as a database cursor  
would do.


You can use -com.apple.CoreData.SQLDebug 1 to see the SQL we pass to  
the database.  This also has nothing to do with Core Data.  This is  
how offset queries behave.  I realize it's not what you expected,  
which is why I recommended using -setFetchBatchSize: instead.


My impression is that my usage scenario is not an appropriate use of  
core data.


Core Data is just passing the query off to the database.  I'm not sure  
why you think going to the database directly will do anything for the  
179.9 / 180.0 seconds it takes to evaluate the query in the database.



I was planning to try SQLite directly. Would it be more appropriate?


You can try it directly, but it won't have any meaningful effect on  
your performance results except that SQLite's built in LIKE operator  
doesn't support Unicode.  It'll be a tiny bit faster for that, but  
still the same order of magnitude.  And then, either you'll have to  
integrate ICU support as Core Data does, and it'll be exactly the  
same, or be stuck with ASCII.


Regardless, you'll need to make your searches eligible for an index.   
The DerivedProperty example shows how to do that.


- Ben



Thanks

On Oct 5, 2009 7:14pm, Ben Trumbull trumb...@apple.com wrote:
 Is there a way to do an asynchronous fetch request against Core data
 returning partial results?

 That depends on whether it's the query part that's expensive (e.g.  
WHERE clause with complex text searching and table scans) or simply  
the quantity of the row data that's your problem.  For the latter,  
you can just use -setFetchBatchSize: and be done.



 You can use a separate MOC on a background thread to perform  
asynchronous work.  You can then pass over results to the main  
thread to display to the user.  However, unless your search terms  
are very expensive, it's usually easier and faster to use - 
setFetchBatchSize: synchronously.  For well indexed queries, it can  
handle a million or two rows per second.  Not sure why you'd subject  
your users to that kind of experience.  It's common to use fetch  
limits, count requests, and only show the top N results.  What's  
your user going to do with a hundred thousand results anyway ?



 If you need to attack the computational expense of your query  
terms, that's more complicated.  Obviously it would be best to  
optimize the queries and ensure they are using an index.  But if  
that's not enough, you can execute the queries in a background MOC,  
fetching objectIDs + row data (put in the the row cache) and then  
have the other MOC materialize the objects by ID from the row  
cache.  There's a BackgroundFetching example in /Developer/Examples/ 
CoreData.  It shows how to do

re: CoreData async fetch request

2009-10-05 Thread Ben Trumbull

Is there a way to do an asynchronous fetch request against Core data
returning partial results?


That depends on whether it's the query part that's expensive (e.g.  
WHERE clause with complex text searching and table scans) or simply  
the quantity of the row data that's your problem.  For the latter, you  
can just use -setFetchBatchSize: and be done.


You can use a separate MOC on a background thread to perform  
asynchronous work.  You can then pass over results to the main thread  
to display to the user.  However, unless your search terms are very  
expensive, it's usually easier and faster to use -setFetchBatchSize:  
synchronously.  For well indexed queries, it can handle a million or  
two rows per second.  Not sure why you'd subject your users to that  
kind of experience.  It's common to use fetch limits, count requests,  
and only show the top N results.  What's your user going to do with a  
hundred thousand results anyway ?


If you need to attack the computational expense of your query terms,  
that's more complicated.  Obviously it would be best to optimize the  
queries and ensure they are using an index.  But if that's not enough,  
you can execute the queries in a background MOC, fetching objectIDs +  
row data (put in the the row cache) and then have the other MOC  
materialize the objects by ID from the row cache.  There's a  
BackgroundFetching example in /Developer/Examples/CoreData.  It shows  
how to do this.  Returning partial results incrementally would require  
some creativity on your part to subdivide the query into several.   
Since most expensive queries are text searches, it's usually possible  
to subdivide the result set naturally.  Like the first letter of  
'title'.  Similar to the thumb bar index on the side of the Contacts  
app on the iPhone.


There's also a DerivedProperty example on ADC for optimizing text  
queries.



Obviously, Apple's own Spotlight could not use something like
Coredata, since it heavily relies on returning asynchronous partial
results.


Which is neither here nor there.  Most Cocoa applications wouldn't  
want Spotlight to be the sole persistence back end of their data.  The  
latency of putting all your data in a full text index instead of a  
relational database or keyed archive would be pretty absurd.  Now, if  
you're writing an app that's primarily structured around full text  
searching, you might instead prefer to focus on putting your data in  
Spotlight via small files, and using the Spotlight APIs.  But it's not  
suitable for apps interested in an OOP view of their data.



Frankly, this is my second application I've attempted to use Coredata
to find it come up surprisingly short. The first time the issue was
core data not being thread safe.


Core Data can be used efficiently with multiple threads.  It might  
help to think of each MOC as a separate writeable view.  If you'd like  
to know more, you can search the archives for my posts.



What is the target market for Core Data? Why sort of application is
ideal for its use? What size data store? Right now it escapes me.


Cocoa and Cocoa Touch applications, particularly done in an MVC style  
with an OO perspective on their data.  Some people also use it as a  
persistent cache for data stored in another canonical format, such as  
XML files.  On the Mac side, we've had customers with 3+ million rows  
(multi GB) databases, and on the embedded side, roughly 400,000 rows  
(100s MB).  However, it does take some care and feeding to handle data  
sets like that, and most developers find it straight forward up to  
about 10% those numbers.


It sounds like you're having performance issues.  What kinds of  
queries are you trying to accomplish ?  How much data are you working  
with ?  How have you modeled your primary entities?


You can fetch back just NSManagedObjectIDs, and - 
setIncludesPropertyValues: to NO to effectively create your own  
cursors if you prefer.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: whether to use core data...

2009-10-05 Thread Ben Trumbull

But the Core Data documentation starts like this:

...
Core Data is not an entry-level technology.
...
You should not simply try to read [The Core Data Programming Guide]
straight through to understand Core Data.
...
Do not attempt the NSPersistentDocument Core Data Tutorial unless or
until you also understand Cocoa bindings.
...
Although Cocoa bindings and Core Data are independent and address
different issues, both provide abstraction layers that˜while
individually they are reasonably straightforward to grasp˜can be
challenging to master simultaneously.


Bloody hell!

WARNING! Do not even ATTEMPT the NSPersistentDocument Core Data
Tutorial! Your very MIND is in MORTAL DANDER!


Ironically, the Low level Persistent Store tutorial was a lot easier  
for people new to Cocoa.  I believe it's been replaced by http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreDataUtilityTutorial/Articles/00_introduction.html 



The warning is a touch harsh.  Still, it's there because the Core Data  
abstractions are built on top of the other foundational Cocoa  
elements.  If you don't get KeyValueCoding, you're going to be lost.   
It wouldn't be doing you any favors to suggest otherwise.  Ditto for  
Cocoa collection classes, KVO, and NSNotificationCenter.


The NSPersistentDocument tutorial is more difficult because it's at  
the intersection of several different technologies.  NSDocument from  
AppKit, Cocoa Bindings, and Core Data.  So that's learning 3 separate  
things at once, and it's rarely clear to people new to Cocoa where  
those technologies intersect, and where they are distinct.  It'd be  
like learning how to whistle, juggle, and snap all at  once.  Could  
you ?  Sure.  But experience has demonstrated it's easier and  
significantly less frustrating to learn them separately.


Or put another way, some of the tutorials are intended for advanced  
Cocoa developers new to Core Data, not developers new to Cocoa.  Try  
the Core Data Utility Tutorial.  It's a CLI, so you don't have to get  
wrapped up in NSViews or Cocoa Bindings as you experiment with Core  
Data.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Strange Core Data save behaviour (required relationship nil... when it is set the line before saving)

2009-09-30 Thread Ben Trumbull


On Sep 30, 2009, at 12:56 AM, Luke Evans wrote:

Well, I'm more than happy to file a bug, as it has been tricky to  
figure out (and I would probably still be at it without your  
interjection).
There are several ways to frame the problem of course: it could be a  
documentation bug... things aren't as simple as might first appear  
in the docs/guide, or maybe something can be done to have deleted  
object behave in a 'friendlier' manner w.r.t. their defunct  
relationships.  I suppose I can just find a general form of words  
and let you good folks figure out what it really means in practice :-)


Probably some of both.

I still think I might have something more to figure out here too.   
At the end of my testing, as an experiment I had a main thread timer  
fire periodically to perform a save on the main thread's MOC  
(without performing any changes on the main thread's MOC at all).   
This induced the same problem, and I'm still curious as to how the  
main thread's copy of the graph might have the nil in the  
relationship under these conditions.  AFAICS there shouldn't have  
been any chance for either MOC to be in this condition at any time.   
I assume the merge operation from the other thread is 'atomic'  
somehow and activity on another thread (like a save) should not be  
able to catch that MOC in some kind of in-between state?


merge ?  I'm not sure I have a full grasp on your work flow here.  If  
you call mergeChangesFromContextDidSaveNotification, then that can  
obviously make changes to the object graph.


There are two other issues in play.  First, if you've set a merge  
policy, then the MOC may pull in changes necessary to make the save  
correct (e.g. implement and correct an optimistic locking failure).   
Second, firing a timer on the main thread is totally non-deterministic  
with respect to anything else on the main thread.  The application  
event loop is rather amorphously defined, so timers can fire either  
inside or outside the main thread's current event's undo grouping.   
Timers are intrinsically very unpredictable.


Aside from this 'stress' test though, I haven't (yet) got it to fall  
over - essentially under the conditions where only one thread  
(albeit one of several threads on any occasion) is making changes  
and saving at a time.



I'm not sure I understand this last comment.  Do you have threads  
sharing a MOC ?  Because threads with their own MOCs can make their  
own changes and own saves simultaneously.


- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Strange Core Data save behaviour (required relationship nil... when it is set the line before saving)

2009-09-30 Thread Ben Trumbull



I don't think anyone has cared enough to file a bug on this.


I don't get it. There's an open manhole in the street with the manhole
cover lying right next to it, and the problem is that no one cared
enough to call the Department of Works to complain?



This has come up 3 or 4 times in about 6 years.  So, is it an open  
manhole in the middle of the street, or is it that the unpaved road  
behind your house that nobody uses is missing a street sign ?


A quick glance suggests this should be pretty easy to fix, but that  
the obvious fix will be slower.  Should everyone's deletes get slower  
just to spare Luke ?  Maybe.  Hard to say without quantifying it.  So,  
now some performance tests need to get written, and the results  
measured.  Also, there's no bug report, and no developer provided test  
case to verify the fix.  So that needs to get written too.


Should we spend our time on this or, judging by complaints, something  
more important ?


cocoa-dev is not a bug reporting forum.

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Strange Core Data save behaviour (required relationship nil... when it is set the line before saving)

2009-09-29 Thread Ben Trumbull

Now, I have some code that changes the value of the 'B enumeration
value' that A is using.  This does the following:
1. Create a new instance of the B subentity that represents the value
we want (in the same MOC as A)
2. Delete the old B object that A was pointing to, i.e. [moc
deleteObject:B];
3. Set A's to-one relationship to point to the new B object (and for
good measure, set B's inverse relationship - though this should be
done automagically).
4. Save the moc

4. is where badness happens (failed to save).  The error tells me that
A's relationship property to B is nil... but just before I do the save
I log the value of the object referenced by this relationship and it's
the new 'B' object!
I have no idea what I've done to upset Core Data such that it claims a
relationship is nil when I save, but the line before the [moc
save:err], the relationship shows as referencing a perfectly good
object.


So you delete B, which has an inverse relationship to A.  Then you set  
a new B on A.  Then you save, and delete propagation cleans up the  
graph, nullifying the old B's inverse relationship ?


What happens if you add a call to -processPendingChanges in between #2  
and #3 ?


- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Strange Core Data save behaviour (required relationship nil... when it is set the line before saving)

2009-09-29 Thread Ben Trumbull


On Sep 29, 2009, at 8:22 PM, Luke Evans wrote:


Hello Ben.

What happens if you add a call to -processPendingChanges in between  
#2 and #3 ?


... well then everything works wonderfully (oh joy!!) :-)

OK.  I need to get a proper mental picture of why this is needed in  
this case.
I guess I was vaguely aware of this method from previous passes  
though the Core Data docs, but...


- The method documentation itself doesn't _really_ suggest it may be  
essential in some cases.   Rather, the talk is about getting the  
undo manager into step, and even then the statement is made that  
this is done by default at the end of the run loop.
- deleteObject docs, or indeed the guide section on deleting  
(Creating and Deleting Managed Objects) makes no mention of a need  
to call this method
- I had tried manually setting the old deleted objects 'back  
relationship' to nil, before deleting it, and before setting A's  
relationship to the new B.  This hadn't worked, but was my attempt  
to keep the relationships consistent - at least in in the MOC that  
induced the change.


It's tempting to just think that you should _always_ do a - 
processPendingChanges before a -save:, but I'd prefer to understand  
what's really happening here.


It's not before the save.  It's in between the deletion and the re- 
assignment of the relationship of the surviving object to a new  
object.  The problem is reassigning the relationship before delete  
propagation runs.  Delete propagation, as well as the change  
notifications and several other aspects of object graph change  
tracking are coalesced and run later.   Calling processPendingChanges  
is one of those later times.  The application event loop also calls  
it, which is the default timing.  Executing a fetch, or a save will  
also call it.


Manually setting the deleted object's relationship instead of calling  
processPendingChanges between steps #2  #3 should also work.


I don't think anyone has cared enough to file a bug on this.

- Ben



If you have insights on the above, then that would be great.   
Regardless, you've just improved my humour by several degrees ;-)


-- Luke


On 2009-09-29, at 3:59 PM, Ben Trumbull wrote:


Now, I have some code that changes the value of the 'B enumeration
value' that A is using.  This does the following:
1. Create a new instance of the B subentity that represents the  
value

we want (in the same MOC as A)
2. Delete the old B object that A was pointing to, i.e. [moc
deleteObject:B];
3. Set A's to-one relationship to point to the new B object (and for
good measure, set B's inverse relationship - though this should be
done automagically).
4. Save the moc

4. is where badness happens (failed to save).  The error tells me  
that
A's relationship property to B is nil... but just before I do the  
save
I log the value of the object referenced by this relationship and  
it's

the new 'B' object!
I have no idea what I've done to upset Core Data such that it  
claims a

relationship is nil when I save, but the line before the [moc
save:err], the relationship shows as referencing a perfectly good
object.


So you delete B, which has an inverse relationship to A.  Then you  
set a new B on A.  Then you save, and delete propagation cleans up  
the graph, nullifying the old B's inverse relationship ?


What happens if you add a call to -processPendingChanges in between  
#2 and #3 ?


- Ben


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Snow Leopard, core data, read only and multiple threads

2009-09-27 Thread Ben Trumbull
I've got an app that worked on Leopard. I ported it to Snow Leopard  
SDK 10.6, and now it works on Snow Leopard, but it doesn't work  
correctly on Leopard anymore. I haven't changed anything that ought  
to affect this.


What doesn't work ?

It's an app with a foreground gui that writes an XML coredata store.  
A background thread reads the repository and takes action. Both  
threads have the full core data stack with their own coordinators.  
As soon as I activate the background thread, the XML store gets set  
to zero bytes.


The XML store is an atomic store.  Everything is loaded at once, and  
everything is written out for each save.  Very NSDocument like.  Like  
TextEdit.  Two people open up Text Edit, pointed to the same path  
mounted over a shared volume.  What happens ?


You almost certainly want to use the SQLite store, or have the stacks  
work with different XML files.


When I encountered the problem I read the doco and I added the  
NSReadOnlyPersistentStoreOption when calling  
addPersistentStoreWithType in the background thread, but that hasn't  
helped. It wasn't necessary before.


NSReadOnlyPersistentStoreOption doesn't have anything to do with multi- 
threading.


You sure you're not saving a MOC ?

- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Re: [__NSFastEnumerationEnumerator nextObject] unexpectedly not very fast!

2009-09-25 Thread Ben Trumbull

In summary, the existence of fast enumeration does nothing for
existing enumeration technologies and if you have to support
10.4 (as I do) you simply can't use it unless you fork your code.

My solution, in the few cases where performance is paramount,
has been to essentially roll my own fast enumeration. For very
large arrays (thousands of objects) I'll get blocks of objects
in batching using [NSArray getObjects:range:], process those in
a tight C loop, and then get another batch.


The for (in) construct is by far the most optimized general purpose  
way to work with any of the collections in Cocoa on 10.5, 10.6, and  
iPhone OS.  It's also polymorphic, so custom collection subclasses can  
fine tune the behavior.


If you have to hand roll your own, either for 10.4, or some  
specialized case, your best bet is to use -getObjects: into a local  
buffer.  gcc supports variable length arrays, and that's the fastest  
way to marshall these batches temporarily.  You'll want to be very  
careful to do length checks to not overrun your stack, and limit the  
size.  If you have somewhere between 256  512 objects, give or take,  
you'll have to malloc a temporary id*  Overflowing the stack is not  
pretty.


- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Core Data: relationship 'too large' when saving

2009-09-24 Thread Ben Trumbull

I am encountering an error that I have not seen before.

While saving in a NSManagedObjectContext I am encountering an error
that reports a to-many relationship as 'too large'.
This relationship has ~10,000 members but each member is relatively
simple consisting of a few short strings and numbers.
I have no problems operating on this relation; the error only occurs
while saving.
Many GB of disk space are available. Error occurs independent of store
type, SQLite, binary, or xml.
Smaller (different) relations of ~1000 members are correctly saved.

1) Is this really a size problem?


No.  I suppose it's possible there's a 16 bit overflow bug somewhere,  
but there shouldn't be (obviously), and I can't imagine any issue with  
10,000.  It is possible for you to set the maximum size of a to-many  
relationship in your model.  Did you check the property validation  
rules for this relationship ?



2) can someone point me to relevant documentation?


You sure it's not NSValidationNumberTooLargeError for one of the  
numbers being outside the range you specified acceptable in the model ?


- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data memory not freed after reset

2009-09-22 Thread Ben Trumbull


On Sep 22, 2009, at 8:54 AM, Sean McBride wrote:


On 9/21/09 4:21 PM, Ben Trumbull said:


If you're using an NSArrayController in Entity mode, you can turn on
Use Lazy Fetching.  You'll want to disable auto-rearrange content.


Ben,

May I ask, why turn off 'auto-rearrange content'?  Is it not  
compatible

with 'use lazy fetching'?  Or does
'auto-rearrange content' on its own degrade performance somehow?



auto-rearrange content is very expensive.  Preserve selection can also  
be expensive, although not nearly as bad.  But if we're talking about  
a million object table view (which is a little odd, btw, most UIs have  
... and more instead) then extraneous layout options will add up fast.


I have a vague and hazy memory that auto-rearrange content is not  
compatible with use lazy fetching.  If you run into trouble, file a  
bug, and disable auto-rearrange content as a workaround.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Core Data memory not freed after reset

2009-09-21 Thread Ben Trumbull

in my SQLite backed Core Data app, a search action fetches from a
large number of objects (1.000.000) only to show them in a table.
When the user exits search mode (search string empty), I'd like to
free the managed objects to restore the app's normal memory footprint.
I do that by resetting the managed context, but it doesn't seem to
work, physical memory stays where it was when the fetch was completed.
Strangely, in ObjectAlloc instrument I can see the fetched objects
being deallocated, but the physical memory still peaks.


If ObjectAlloc shows the fetched objects being deallocated, but top  
shows a large RSIZE, and the heap command shows a very large heap  
thats most unused, then you're doing everything you can on the  
deallocation side.  There is a difference between heap size, and VM  
allocated address space.  This issue is caught at the boundary, where  
the malloc system won't aggressively deallocate address space after  
the memory using it has been deallocated.  It doesn't, because as a  
general rule that's a net loss.  So your only choice is to either (a)  
not worry about it or (b) reduce peak memory.  (b) reducing the heap  
high watermark is a separate problem than simply freeing all the  
memory you allocate.  Reducing peak memory will have many other  
performance benefits besides making your RSIZE look pretty.


If you're using an NSArrayController in Entity mode, you can turn on  
Use Lazy Fetching.  You'll want to disable auto-rearrange content.   
This works on 10.5.  On 10.6 and iPhoneOS, you have more options,  
including using Batched Fetching on the fetch request with - 
setFetchBatchSize.  This will make a vast reduction in peak memory  
when working with such a large result set.   Working with 1 million  
objects like this will take ~16MB of RAM.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data memory not freed after reset

2009-09-21 Thread Ben Trumbull

Core Data has (or, I should say, had, since I haven't investigated the
behavior in Snow Leopard) its own internal in-memory cache of object
and attribute data, which means that, up to a point, data from a
persistent store is in memory twice. AFAICT there's no way of
unloading or controlling this cache, which has a maximum size that
Core Data chooses.

So you can get back the memory occupied by the objects themselves (and
their attribute value objects), but your memory footprint could stick
at a couple of hundred MB. You could just ignore the issue (the
footprint won't grow beyond certain point, so it's sort of harmless),
or try some of the fetch performance optimization techniques described
in the Core Data documentation to see if you can keep unwanted
information out of the cache from the beginning.


The caching is happening at the NSPersistentStoreCoordinator level,  
and is shared copy-on-write with the managed objects themselves (e.g.  
faulting the same object in multiple MOCs will reuse the same string  
data).  The raw column data is not duplicated in memory.  The cache  
entries are deallocated after the managed object representing that row  
is deallocated, and at certain other times involving faulting.  Simply  
releasing the last managed object representing that row is enough.   
You may need to call -processPendingChanges to purge anything that as  
accumulated as ready to be disposed to encourage this to happen sooner  
if you find it's taking too long.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Core Data threading fun

2009-09-21 Thread Ben Trumbull

I have a server app that responds to network requests, making use of a
Core Data database to serve responses.
Some requests update the database.  I have chosen to allow requests to
arrive on multiple threads, and intend for these threads to use Core
Data directly.

In keeping with Core Data's doc related to threading, I have one
Managed Object Context per thread, and these all share a common
Persistent Store Coordinator that is managing a SQLite data file.
It's my understanding that this scenario is an acceptable
configuration, indeed it appears in the Core Data notes on threading
as the 'preferred option' (q.v. 
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdMultiThreading.html
).

OK, here comes the problem (!)...
One type of request can change the name of an object.  The handler for
this request (using its thread's own MOC):
1. Fetches the required object by persistent ID (i.e. stringified
NSManagedObjectID).


Why stringify it ?  NSManagedObjectIDs are immutable and you can just  
pass them between threads.



2. Changes the value of the 'name' property on the fetched object
3. Commits the change by calling 'save' on the MOC

Unfortunately, while this works some of the time, I have a situation
where a subsequent other request (possibly on another thread) sees the
old name of this object.  This request gets 'all' the entities of this
type and sends properties (such as name) back.


You can merge the changes into that context explicitly, or refetch the  
objects.



Should I have a PSC per thread too?  If so, will they behave correctly
talking to the same SQLite data file?
With a shared PSC, should I lock this whenever a write is being
performed (at least)?


Per-thread PSCs doesn't sound like what you want.  You probably want  
the simpler shared PSC configuration for now.  When you share a PSC  
between threads, the key point is to lock it whenever you message that  
PSC directly yourself.  Typically, that's adding and removing  
persistent stores.  It's easier to do that at init time, and leave the  
configuration stack after you start spawning threads.  Core Data  
assumes responsibility for locking the PSC if we ever send ObjC  
messages to it.




2. Locking the MOC
There is talk that locking the MOC, even one that is private to a
thread, will engender 'thread friendly' behaviour in the PSC:

...
Typically you lock the context or coordinator using tryLock or lock.
If you do this, the framework will ensure that what it does behind the
scenes is also thread-safe. For example, if you create one context per
thread, but all pointing to the same persistent store coordinator,
Core Data takes care of accessing the coordinator in a thread-safe way
(NSManagedObjectContext's lock and unlockmethods handle recursivity).
...

Should I lock the MOC, or just the PSC (see 1)?
Would this really fix my experience of changes not appearing on other
threads anyway?


No, if you find yourself locking MOCs, you're almost certainly doing  
something wrong.



3. Changes propagating back to other MOCs looking at the same data
I assume Core Data is smart enough to realise that an attribute value
change in a Managed Object cached in one thread's MOC, should be
reflected on (or at least invalidate old data in) another Managed
Object instance representing the same data in another MOC.  At the
very least, I think I'd expect a new fetch request that has this
object in the result set would cause data changed in the persistent
store to show up properly on the object.


We don't automate this step, although there is API to assist you.  We  
try as much as possible to never change the state of your objects out  
from underneath you (e.g. push state).  The reason for that is how  
complex things become when that local MOC has pending edits.  Do we  
overwrite it out from underneath you ?  Or not update it, but update  
other unchanged objects (seemingly randomly).  There isn't a clear  
paradigm for coordinating these kinds of push changes between the  
framework and your code.  So instead we follow something like a  
principle of least surprise mates with lesser evil.


Basically, Core Data uses the poll model.  State may change, but only  
because you did something to ask us to do that.  Like refetch the  
objects, use a staleness interval, or call -mergeChanges...


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: How to create subentity object inheriting from superentity object in core data

2009-09-17 Thread Ben Trumbull


On Sep 17, 2009, at 9:21 AM, Leon Starr wrote:

So, going back to my example, (and the part everyone disagrees  
with!) I still don't get it.  More importantly, my objc compiler  
doesn't get it!  In the model, Auto.license is properly inherited by  
the Sedan and Truck subentities.  No trouble at all with KVC  
interactions.  But if there is no @property/@dynamic for license in  
my Truck subclass, (only in the Auto subclasss) I cannot access  
thisTruck.license without getting a compiler error.  Which makes  
total sense to me since one NSManagedObject subclass (Truck) is not  
inheriting from another (Auto) in objc.  They each inherit from  
NSObject.  But I CAN do [thisTruck valueForKey:@license], which  
also makes perfect sense.


This violates the rule that a subentity must use an Objective-C class  
that is the same as its superentity, or a subclass of its  
superentity's Objective-C class.


If the Truck entity is a subentity of Auto, then it may reuse the  
AutoClass, or a TruckClass which must be a subclass of the AutoClass.


- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Core Data: strange keypath problem

2009-09-17 Thread Ben Trumbull

Here is the console output:
2009-09-17 12:44:17.659 myAppSales[11094:a0f] Application DMXRef:
janTotal starting...
2009-09-17 12:44:17.660 myAppSales[11094:a0f] Application DMXRef:
janTotal predicates set.
2009-09-17 12:44:17.662 myAppSales[11094:a0f] anotherArray count = 117
2009-09-17 12:44:17.663 myAppSales[11094:a0f] anotherArray firstObject
month = 5
2009-09-17 12:44:17.663 myAppSales[11094:a0f] keypath month not found
in entity NSSQLEntity AppSales id=2

Any ideas would be greatly appreciated.


Is 'month' marked transient on the AppSales entity  in your model ?   
You cannot ask a *persistent* store to query or sort on *transient*  
data.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: How to create subentity object inheriting from superentity object in core data

2009-09-16 Thread Ben Trumbull

I've got a generalization in my core data model with entities named A,
B, C let's say where A is a super class with subentities B and C.

A is not abstract, so if I create an A NSManagedObject, I need to
create and relate a single B or C subclass object. How do I make this
happen? I can create the entities, but HOW do I tell the model that
object B is a subclass of object A (or vice versa?)

Note: I did create the model programmatically and the subentities have
been set properly for entity description A.

Here's my sad attempt to move forward.  As you can see, I've created
the objects I need, but B doesn't know that A is it's superclass
object.  What to do?


Model the entity inheritance in the modeling tool is the easiest  
approach.  If you need to customize your model beyond that at runtime,  
you can make minor alterations programmatically by loading it and  
mutating it before creating your NSPersistentStoreCoordinator.  If you  
programmatically create a model, you'll need to add all the super  
entity's properties to each of the subentities.  The programmatic  
structure is much flatter than it would appear in the graphic Xcode  
tool.  There's no calling super in entity inheritance.


You'll need to set the objective-c class names for each entity.  The  
objective-c class must be either the same as the super entity's class  
or a subclass of that super entity's objective-c class.  You cannot  
create a random mapping of Objective-C classes to entity inheritance.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: How to create subentity object inheriting from superentity object in core data

2009-09-16 Thread Ben Trumbull

Okay, my understanding, then, is that the inheritance is just in the
model - makes sense.  If you subclass NSManagedObjects for the parent
and child entities, you need to explicitly declare and synthesize
(dynamically) all common properties you want to access at lower levels
of the hierarchy (at least).


entity inheritance is just in the model.  class inheritance still  
applies normally.



Just to be clear, in the model I've got Entities: Auto, Sedan, Truck
and the parent (Auto) has a common property license.  Now when I get a
pointer to a Sedan or Truck I want the ability to access via
thisTruck.license or thisSedan.license.  In fact, if I end up with a
pointer (Auto *) thisAuto, I want thisAuto.license as well.

To get this to work, without KVC,  I need to declare @property/
@dynamic for license in Auto, Sedan and Truck.  (Can't just put it in
Auto and expect Sedan.license to work).  No big deal unless I have a
bunch of common properties in the parent entity.


No, Objective-C properties are inherited by subclasses.  If you use  
the modeling tools, your model will be created correctly, and your  
custom NSManagedObject subclasses will have the correct @interface  
definitions.  Even if you need to do all this programmatically, I'd  
recommend to play with the modeling tools more to see what things are  
supposed to look like.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: CoreData multiple contexts and threads

2009-09-13 Thread Ben Trumbull

Hello, I have a stream of data (some messages) from a socket and I
need to save it in a CoreData db. I would to optimize this thing by
using more than a managedobjectcontext for each N messages arrived.
The problem is that I need to link these message between
(parent/childs). How can I check if a message exist in a context
without merge it with the main context? Need I to mantain an array of
active contexts and comunicate with them in order to search parents
and childs? If I merge each time with the main context it's a bit
slow.


Well, you can create the messages and save them in groups in their own  
thread and MOC, and link them up with their parents later.  Or you can  
organize the background threads to own parent groupings and have those  
dedicate threads save their messages.


The problem with inserting messages and relating them to parents  
haphazardly is that the to-many relationship on Parent will need to  
merge in the results on each save anyway, and having lots of threads  
banging on the same to-many will just engender a lot of merge  
conflicts.  While the right merge policy will resolve them for you,  
that's not remotely free.  You can look up a previously saved MO with - 
objectWithID: on your MOC.


If you have  a very large number of messages, you may not wish to  
model the to-many on Parent at all.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: CoreData Bug? (SQLite vs XML)

2009-09-13 Thread Ben Trumbull

I've been trying to track down a bug and it *seems* that it might be
CoreData's fault (I highly doubt it but there's a small chance). I
have the following configuration:
- A base class, let's call it Base
- A subclass of Base, let's call it Subclass

Subclass has a to-many relationship to Base. Here's what I'm  
observing:

- On startup, the to-many relationship is not restored (only in some
reproducible cases).


Are all the objects correctly marked inserted or updated before you  
save ?  Do all the objects report the correct inverses ?


If you change relationships with setPrimitiveValue:forKey: or on MOs  
that haven't been inserted into a MOC or try to wire up relationships  
in -awakeFromFetch, then things can go awry.


Do you have multiple MOCs saving ?  The XML store is atomic, so the  
last writer wins.  The SQLite store merges changes from other saves.


Can you reproduce this in a new sample project ?

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Core Data Manual Migration

2009-09-11 Thread Ben Trumbull

The process fails here and the log then contains the following:
An error occured while manually migrating document: Error
Domain=NSCocoaErrorDomain Code=134110 UserInfo=0xf336960 An error
occured during persistent store migration.
[6871:813] Error: {
   reason = Can't add source store;
}


There should be more in the userInfo dictionary explaining what's  
going on.  If you can reproduce it in a new test project with your  
models  mapping models, then please file a bug with the project  
source zipped up at bugreport.apple.com and we'll look at it.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Is Core Data appropriate to my task?

2009-09-10 Thread Ben Trumbull

Gwynne,


I have an application that manages two kinds of data: A singular file
that contains a large amount of rarely changed (but not invariant)
data, and documents that contain one root object's worth of
information that connects to the singular data set in a very large
number of places; the documents are in fact little more than a chosen
list of references into the singular data set, plus some small bits of
independant data. The documents are modified quite often.

Originally I thought Core Data must surely be ideal for this sort of
application; the object graph management alone should have been very
helpful, to say nothing of the management of stores and the abilty to
integrate with bindings and NSDocument. I got as far as reading all
the basic (and some of the not so basic) Core Data documentation and
began wondering whether or not my data would fit into its model after
all. For example, in the large singular data set, there are a large
number of what SQL would call lookup tables, data that's used only
to avoid duplicating a set of constant values that are used elsewhere.

To use the Employee/Department example from the Core Data docs,
sometime in the future an Employee might have a planetOfOrigin
attribute. Assuming one limits one's self to the restriction of the
speed of light (so, not TOO far in the future), the resulting Planet
entity would only ever have a small number of possible values. Such an
attribute might be better modeled in the Employee entity by something
like SQL's ENUM or SET types. If the set of possible values is Earth
and Not Earth, a Boolean might make more sense. If the set of
possible values is Earth, Mars, Venus, etc., an ENUM would be a
reasonably obvious choice; after all, how often does the solar system
gain or lose a planet (cough Pluto cough)? With such a small data set,
a lookup table would only be the obvious choice if the set of possible
values was expected to change with any frequency. But Core Data has no
support for such a thing; I would either have to write a custom
property type or model it by creating the Planet entity and giving it
a relationship from Employee.


Correct.  You can write a custom NSValueTransformer with the  
Transformable property type to implement an ENUM, or normalize the  
data into a separate table as a formally modeled entity.  Which is  
better depends on how big the data values are, how many of them there  
are, and how frequently they change.


Is that really so bad ?  The alternative is to do ALL the work yourself.


Let's pretend the lookup table *was* the obvious choice for some
reason; the speed of light barrier has been broken and now there's a
whole mess of planets. So in Core Data parlance, the Employee entity
has a one-to-one relationship to the Planet entity.


A lonely planet.  That's either going to be one-to-many or a no  
inverse to-one.



The inverse
relationship from Planet to Employee, all employees from this planet
is technically feasible, even easy, to model, but it's almost
certainly a waste of time and effort. But the Core Data documentation
offers a long list of very dire warnings about one-way relationships
between entities.


Yes, and for most situations those warnings are there for very good  
reasons.  But if there were no reasons for such relationships, then it  
wouldn't be a warning, it simply wouldn't exist.



Worse, the list of possible Planets certainly doesn't belong in the
same document file that holds a single Employee's data; you'd end up
duplicating that data across every single Employee. So the list of
Planets would instead be in a global store.


There are lots of ways to model that, but, yes, this would be the most  
natural.



But oops, Core Data can't
model cross-store relationships, so you use a fetched property, which
is one-way.


You could use a fetched property, or handle this in code by storing a  
URI for the destination object in a different store, and fetching the  
matching objectID either lazily in in -awakeFromFetch.  We've  
generally recommended using a custom accessor method for this instead  
of fetched properties.



Inverse relationship problem solved, unless you actually
had a use for that relationship. But fetched properties need a fetch
request, and what do you put in the predicate? Now you need some kind
of identifier in the Employee for the fetch to operate on,


Yes, but this isn't any different than the problem would be without  
Core Data for managing values in two different databases.


and now you  have two fields (the planetOfOriginName string for  
the predicate and

planetOfOrigin as the fetched property) to model a single
relationship. How to maintain referential integrity?


Again, no different than the problem would be without Core Data.  This  
is why the modeling tool recommends using inverse relationships.   
Maintaining the integrity by oneself is tedious and error prone.


And what if you DID want the inverse relationship - do you model  
another fetched

Re: Is Core Data appropriate to my task?

2009-09-10 Thread Ben Trumbull

I don't see this as being equivelant at all.

Extending the example, let's say the company with these Employees has
as its directors several discriminating unfair people, and thus an
Employee from any given Planet gets a salary adjustment based on that
Planet. The obvious place for this data is the Planets table, or in
Core Data's case, the Planet entity. A salaryAdj column (attribute)
is added to the Planets table (Planet entity) and filled in with the
(in)appropriate numbers.

Now suddenly the company is taken over by far more benevolent and
considerate people, whose only flaw is that they don't want to break a
system that works by removing an entire column from a database table
(a schema change is much more difficult than a data update, after
all), so they just UPDATE Planets SET salaryAdj=0.


Now you're conflating other issues.  This is why I recommend not  
treating O/R systems as perfectly equivalent to databases.  They're  
not.  On Snow Leopard  iPhone OS, you can make modest alterations to  
the Core Data schema easily.  Just keep a copy of the old model, and  
pass the 2 keys to the options dictionary when you add the store to  
the PSC to leverage light weight migration.  Core Data will infer the  
appropriate schema changes and adjust the schema in place (alter table  
style).


http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmLightweight.html#//apple_ref/doc/uid/TP40008426-SW1 



If you do make some unusual and radical modifications (split tables  
into multiple new tables, compose old tables into a single new table,  
etc), you can use the full mapping model migration.  While it won't  
perform as well as light weight migration, at least you'll have tools  
support in handling the schema migration.



So someone loads up an Employee whose Planet instances are in the same
store with that Employee, and the old salary adjustment is still
sitting there in the saved data. I sense unhappy Employees in this
company's future. If only the coder who wrote the payroll system had
put the Planet data in some global store where changes to it would
propogate correctly to all Employees.


If this is important, than you can use multiple persistent stores.

I suspect Erik's point, though, is many apps don't have a significant  
issue with a small amount of duplication in the individual documents.   
Disk space is usually cheap.  And being completely self contained has  
its advantages (perhaps not relevant to you, but still existent).   
global mutations is a double edged sword.  What if your documents  
are loaded in a newer version of the app, but have some implicit data  
dependency on the older global data ?  That can get messy.



Does Core Data still solve the problem? Is there some reason that
using Core Data for everything would be better than storing the global
rarely-updated data in a real database and using Core Data only for
the Employee entity, which is the only part which really talks to the
UI anyway? (Something tells me the key point is right there...) For
that matter, if Core Data is only managing one entity, what's the use
of Core Data at all? With all the data being referential between the
database and the entity, just define a simple NSObject subclass which
contains a few instance variables and implements NSCoding.



Then why not use Core Data for the database and for the entity  
implement a simple NSObject subclass with a few instances  
variables ... ?


Although, it seems a little silly to not use Core Data for the simple  
part when you'll get persistence, change tracking and Cocoa Bindings  
integration for free.  Most people find NOT maintaining backward  
compatible initWithCoder methods in perpetuity quite refreshing.  I  
know one developer seriously considering rewriting their iPhone app  
for no other reason than to use Core Data's light weight migration and  
never hand roll another database schema upgrade again.


Here's an excerpt from a post regarding when to use Core Data on the  
iPhone:


I suppose I could tell you how great an addition to Cocoa it is, or  
how much TLC its performance tuning gets.  But what I've seen our most  
sophisticated clients decide is that it saves them from writing a lot  
of code.  The model code with Core Data is usually 50% to 70% smaller  
as measured by lines of code.  Why reinvent that ?


App developers don't get paid to write database code.  Can you learn  
SQL ?  Sure.  Do your customers care ?  No.


App developers get paid for novel functionality that addresses a real  
customer need with good UI.


- Ben

Here's a more traditional reply:

- Full KVC, KVO support out of box
- Relationship maintenance (inverses, delete propagation)
- Change tracking

- Sophisticated SQL compilation
 - NSPredicate objects instead of SQL
 - NSPredicate support for correlated subqueries, basic  
functions, and other advanced SQL

 - Proper Unicode, local aware searching, sorting, regex
   

Re: Is Core Data appropriate to my task?

2009-09-10 Thread Ben Trumbull

Before anything else, let me say thank you for a clear, concise, and
very helpful set of answers to my questions; I was expecting rather
more of a struggle for understanding :).


my pleasure.


On Sep 10, 2009, at 5:04 PM, Ben Trumbull wrote:

The inverse
relationship from Planet to Employee, all employees from this
planet
is technically feasible, even easy, to model, but it's almost
certainly a waste of time and effort. But the Core Data  
documentation

offers a long list of very dire warnings about one-way relationships
between entities.

Yes, and for most situations those warnings are there for very good
reasons.  But if there were no reasons for such relationships, then
it wouldn't be a warning, it simply wouldn't exist.


The manual isn't at all clear about this, but if I understand
correctly, you're basically saying, Though it is almost always
technically possible to model an inverse to any relationship, there
are sometimes circumstances in which it is correct not to do so. Is
that accurate, and if so, should I file a documentation bug requesting
clarification on that and the circumstances in which it's true?


Sure.  It's a challenge to document some of this material in a way  
that steers most developers down the typically optimal path while  
still keeping advanced options open.  We have many developers with  
little or no database experience, and we want to encourage them to use  
inverses until they have a compelling reason not to.  The  
documentation was more open about no inverse relationships in 10.4,  
and we learned the hard way that was less than ideal.  The modeling  
tool now issues warnings for this due to the frequency and severity of  
bugs from developers incorrectly and over eagerly using no inverse  
relationships.



But oops, Core Data can't
model cross-store relationships, so you use a fetched property,  
which

is one-way.

You could use a fetched property, or handle this in code by storing
a URI for the destination object in a different store, and fetching
the matching objectID either lazily in in -awakeFromFetch.  We've
generally recommended using a custom accessor method for this
instead of fetched properties.


Is there any particular reason for that recommendation? The
documentation explicitly recommends fetched properties for cross-store
relationships (one instance of several is in the Core Data Programming
Guide, Relationships and Fetched Properties chapter, Fetched
Properties section, first paragraph, where it says  In general,
fetched properties are best suited to modeling cross-store
relationships...)


First, custom accessor methods and -awakeFromFetch offer a vast amount  
of flexibility, and can be easier to tune for performance.  Fetched  
properties are a fine alternative.  But I like to also reinforce the  
understanding that not all your custom behavior needs to be  
encapsulated in your Core Data schema.  You have full Objective-C  
objects and very powerful runtime support.  Use it liberally.



(Let me take this opportunity to say that for all the warnings that
Core Data is not and never has been a database, almost every
concept I
see in it makes me think O/R mapper for SQLite.)

Core Data is an O/R mapping framework, among other things.  But O/R
frameworks are not SQL databases.  Modeling your data in any O/R
framework as if you were writing SQL directly is inefficient and
mistaken.

Saying that Core Data is a database is like saying your compiler is
an assembler.  Well, the compiler suite uses an assembler, sure, and
they both output object code in the end, but that does not mean the
best way to use your compiler is to write in assembly.



Nonetheless, Core Data does manage the data stored on disk as well as
the representation of that data in memory; I don't see a tremendous
difference between that and what SQLite does, other than Core Data
providing a much effective organization of and means of access to that
data.


Core Data implements a lot of functionality on top of SQLite.  From an  
API perspective, that it uses SQLite at all is an implementation detail.


In any event, O/R systems present an OO view of your data, and have  
their own idioms closer to OOP.  They are providing an abstraction  
layer and perform transformations on both your queries and result  
sets.  Relational databases can support that, but in every O/R system,  
the ideal way of using the system is somewhat different from how one  
would write SQL directly against the database.


- Ben


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data fetch with to-many relationship

2009-09-09 Thread Ben Trumbull

When I log the test fetch results:

NSArray *testFetchResults = [managedObjectContext
fetchObjectsForEntityName:@Owner withPredicate:[NSString
stringWithFormat:@ANY books.name like 'myPrefix*']];
NSLog([[(Owner *)[testFetchResults objectAtIndex:0] books]
valueForKey:@name]);

I get the following sample output:

--
{(
foo,
bar,
myPrefix-v1,
myPrefix-v2
)}
--


yup.  Your print statement, though, is not for the objects you  
fetched, but their related books.



These were the four test Book objects I originally associated with one
Owner, and then saved to the managed object context.

I'm unclear why the predicate statement:

@ANY books.name like 'myPrefix*'

would return all books, whether their name starts with 'myPrefix' or
not. The output I would expect is:

--
{(
myPrefix-v1,
myPrefix-v2
)}
--


You're not fetching books, you're fetching Owner.  The predicate   
fetch request pair together to say:


Fetch all the Owners that have ANY (one or more) object in their books  
relationship with a name like 'myPrefix*'


The log statement shows the first Owner in the results array has 2  
books matching your predicate.  It also has a bunch of others, but  
that's irrelevant to whether or not it matches the predicate.  You  
seem to be thinking of this predicate


@ALL books.name like 'myPrefix*'

for which we don't currently generate SQL.

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: KVO can be unsafe in -init?

2009-09-09 Thread Ben Trumbull

On 08/09/2009, at 12:36 AM, John Chang wrote:


Hi all,
Question: is it unsafe for some reason to be adding yourself as a KVO
observer during -init?

We have a singleton with an -init that looks something like this:
- (id)init
{

if ((self = [super init]))
{

_foo = [[NSMutableDictionary alloc] init];
_bar = [[NSMutableDictionary alloc] init];

[[XYZManager sharedManager] addObserver:self forKeyPath:@allObjects
options:NSKeyValueObservingOptionInitial context:NULL];


As a general rule, in ObjC, C++, and Java it's a very bad idea to  
expose partially constructed objects to third parties, especially via  
global registries like KVO.  In addition to the obvious problems,  
multi-threading and error handling are especially pernicious.  The  
multi-threading issue is pretty self explanatory.  The moment your  
uninitialized object is registered in KVO, others can invoke methods  
on it before you and your subclasses are done setting initial state.


The error handling issue involves what happens when an initializer  
needs to error out.  In Cocoa, it should return nil, and if necessary,  
deallocate its previous self (to prevent +alloc from being unbalanced,  
and hence leak).  But this now means that third parties can reach a  
deallocated object via these registrations.  It will complicate how  
carefully you'll need to write your -dealloc method.


If the KVO registration is the last thing that happens, then it'll  
work, but of course, subclassing will break your assumptions.  This  
falls under the hack category, and is not a pattern you want to  
replicate widely.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: watch changes to any properties on an object

2009-09-03 Thread Ben Trumbull
Well, @dynamic doesn't have anything to do with KVO.  It's just  
storage and accessors for properties.  Core Data knows when non- 
dynamic modeled properties change too.  It sets a dirty flag, just as  
you would have to.  Most of that happens in -willChangeValueForKey:.   
Unfortunately, overriding that method was deprecated in 10.5.  KVO no  
longer guarantees overrides will be called.


In terms of knowing what to save, Core Data only tracks that at an  
object level, and uses snapshot deltas to compute the changed property  
set at the end.


Some people invert the observing relationship to work around this.   
You can add code in your setters to set a dirty flag, or within your  
setters manually call a notify method on another object.  If you have  
fewer objects, you could just use NSNotifications.


Almost certainly worth filing an enhancement request at bugreport.apple.com

- Ben


Ok, thats what i thought. But just for implementation ideas, how does
CoreData know when one of it's @dynamic properties is changed? It must
set some sort of flag somewhere in order to know what to write out
when it needs to save. How does it handle that?

thx

AC

On Sep 3, 2009, at 12:27 PM, Jens Alfke wrote:



On Sep 3, 2009, at 8:24 AM, Alexander Cohen wrote:


I have a base object that needs to know when any of it's properties
or subclasses properties have changed and set a dirty flag on
itself. Is there a way to do this?


No, not in general. Key-value observing requires knowing the exact
property name(s) in advance. You'll need to set the 'dirty' flag
manually.

˜Jens



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Core Data dog-slow when using first time after boot

2009-09-03 Thread Ben Trumbull


On Sep 3, 2009, at 4:49 AM, Ruotger Skupin wrote:

Since it's not a many to many, you can perform the prefetching  
effectively by hand using a fetch request to preload the relevant  
destination rows with an IN query based on the data you initially  
fetched for the source entity.  You shouldn't have to, but if  
you've run into a bug, that's how you could workaround it.


You still haven't described the NSPredicate you were using with  
filteredArrayUsingPredicate.  Being more forthcoming about the  
context and details of your problem will help us get you answers  
more quickly.
This is the predicate I was using for the test of the original  
post, but since I use Smart Folders predicates can look a lot  
different (i.e.: complex):


(additionalInfo.onTheFlyIsInternal == 0 AND  
additionalInfo.isSuppressed != 1) AND (account.uniqueID IN  
{D1AB3788-00DF-4475-A979-CE3EFC3987B5} OR FALSEPREDICATE)





You'll want to prefetch additionalInfo and account.


Hm. Problem here is: As mentioned I use the predicate for a smart  
group. So the predicate can vary wildly and can reference basically  
any entity in the model. So what is the best strategy here?  
Decompile the predicate (which is built by an NSPredicateEditor)  
and prefetch the keypaths it takes? Prefetch everything?



Prefetching everything is usually undesirable.  The easiest  
approximate solution is to just track the hot button relationships for  
each of your core entities, and look up which keypaths to prefetch by  
entity name.  Of course, you can also do a lot less filtering in  
memory if you pass the predicates to the database with the fetch  
request.  You only need to prefetch relationships you are going to use  
in memory.  You don't need to prefetch anything that's simply used as  
part of the predicate in the fetch request itself.


Walking through the predicate and gathering up the keypaths used is  
very tedious, but not especially difficult, if you find yourself  
wanting a complete solution.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: watch changes to any properties on an object

2009-09-03 Thread Ben Trumbull

On Sep 3, 2009, at 12:14, Alexander Cohen wrote:
Ah, ok, this is more like what i wanted to hear! :) I understand how
@dynamic works, but how to I get to funnel all calls to @dynamic
properties to the same call such as setValue:forKey: or something
like that where i can parse the key and update my internal data and
set the flags i need to set.


No, you're barking up the wrong tree.

There's no how @dynamic works. @dynamic is a compiler directive
telling it that getter/setter method implementations exist, but just
not in the current compilation unit. There no standard general
mechanism for supplying the implementation.

In the case of Core Data specifically, the built-in implementations
(call them dynamic if you want, but that's the same as their being
compiled as @dynamic) are simply efficient versions of what you
would otherwise have to hand-code. We don't know if they're funneled
through one funnel, several funnels, or a different function for every
property -- that's an implementation detail.

(IAC, Core Data doesn't mark objects as changed in *those* dynamic
methods, but (presumably -- another implementation detail) in the
primitiveKey dynamic methods.)

I don't how you're ever going to be able to have a class detect
invocations of its subclasses' properties, unless you have the class
muck around in the runtime, replacing methods on the fly.

A better solution, IMO, is to realize that you're considering a design
requirement for your data model, and to design the solution right into
the model. For example, if this is a self-contained class hierarchy
that you're implementing, you could make it a requirement of
subclasses that they invoke something (a superclass method) or inform
something (a controller of some kind) when they modify data values.


Good advice.

Also, instead of worrying about how Core Data does this, you could  
just leverage Core Data's change tracking, whether via inheritance or  
composition, and respond to the  
NSManagedObjectContextObjectsDidChangeNotification. You don't have to  
save to one of Core Data's persistence mechanisms just to create a  
bunch of managed objects to hold some properties.


- Ben

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Correct way to have nil undo manager in Core Data document?

2009-08-29 Thread Ben Trumbull

Well, I've got a background worker process which opens an
NSPersistenDocument.  Since it has no undo capability, I want to set
it to nil as recommended.  (I have other reasons for not wanting an
undo manager scurrying around.)  But the document doesn't like having
nil undo manager.  When I ask for it later, it creates one for itself,
and sets its managed object context to have the same one.



You need to use the NSDocument API:

/* The document's undo manager. The default implementation of - 
setUndoManager:, in addition to recording the undo manager, registers  
the document as an observer of various NSUndoManager notifications so  
that -updateChangeCount: is invoked as undoable changes are made to  
the document. The default implementation of -undoManager creates an  
undo manager if the document does not already have one and - 
hasUndoManager would return YES. */

- (void)setUndoManager:(NSUndoManager *)undoManager;
- (NSUndoManager *)undoManager;

/* Whether or not the document has an undo manager. The default  
implementation of -setHasUndoManager: releases the document's current  
undo manager if it has one before the invocation but is not to have  
one afterward. */

- (void)setHasUndoManager:(BOOL)hasUndoManager;
- (BOOL)hasUndoManager;


- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Core Data Predicate Builder - comparing dates

2009-08-29 Thread Ben Trumbull

I have a Core Data entity that has a dateCreated and a dateModified -
both NSDates in the object files.
I'd like to construct a predicate that will retrieve all records where
a record's dateModified is greater than that record's dateCreated.

Its deceptively easy to setup something that looks like it should work
using 'Control-click' and 'Key' in the predicate builder in XCode.
But when I run queries it doesn't appear to yield the right results.
My thinking is that the comparison operators don't properly evaluate
dates (am I wrong?)


Comparison operators work just fine on dates, although == and != are  
fragile since NSDates are double time stamps, and floating point  
numbers have odd == behavior.


What does the predicate look like ?  How is it not working ?  What  
does SQL logging show ?



So dropping back to code - how would I write this predicate in code?


[NSPredicate predicateWithFormat:@dateModified  dateCreated]

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


re: Curious about $SUBST_VARS within a SUBQUERY of a fetch request template

2009-08-29 Thread Ben Trumbull

I just created a fetch request template in my MOM that looked like:
SUBQUERY(platformInfos, $each, $each.platformName ==
$PLATFORM_NAME)@count == 0

I then looked up the template in the code and attempted to use it in  
the

usual manner with:
fetchRequestFromTemplateWithName:substitutionVariables:


should work


Core Data complained that it could not resolve the SQL for
$each.platformName == $PLATFORM_NAME, because of the RHS.

I would have thought that this variable would be replaced as normal,  
even
though it is inside a SUBQUERY.  Does anybody know if this is  
officially

disallowed, or a bug, or just developer-error somehow?


What your code look like for the substitution variables dictionary ?

- Ben



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


  1   2   3   >