Editing in a tableview without selecting
]; // Add parts [tableView addTableColumn:[AKVariableStore columnObjectForIdentifier:nameColumnID]]; [tableView addTableColumn:[AKVariableStore columnObjectForIdentifier:equalsColumnID]]; [tableView addTableColumn:[AKVariableStore columnObjectForIdentifier:valueColumnID]]; [tableView addTableColumn:[AKVariableStore columnObjectForIdentifier:swatchColumnID]]; [tableView addTableColumn:[AKVariableStore columnObjectForIdentifier:descriptionColumnID]]; // Set ourselves up to be in charge [tableView setDelegate:self]; [tableView setDataSource:self]; [tableView setFrame:tableViewFrame]; [tableView sizeLastColumnToFit]; } return tableView; } My delegate methods (skipping the implementations for the unimportant ones): - (BOOL)tableView:(NSTableView *)aTableView shouldSelectRow: (NSInteger)rowIndex { return YES; } - (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn: (NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { return YES; } - (CGFloat)tableView:(NSTableView *)tableView heightOfRow: (NSInteger)rowIndex - (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn: (NSTableColumn *)aTableColumn row:(NSInteger)rowIndex My datasource methods: - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn: (NSTableColumn *)aTableColumn row:(NSInteger)rowIndex - (void)tableView:(NSTableView *)aTableView setObjectValue: (id)anObject forTableColumn:(NSTableColumn *)aTableColumn row: (NSInteger)rowIndex That last datasource method never gets called, if you're wondering. The only unusual thing about this tableview is that I set it up in code instead of in IB, so I assume the root of the problem is in my programmatic setup code. But where? I've been hunting for a - setEditable:YES method somewhere that I need to call, but I haven't found it... Any ideas? Thanks! Ben Haller Stick Software ___ 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: Editing in a tableview without selecting
On 1-Nov-09, at 12:42 PM, Ben Haller wrote: Hi all. I've got an NSTableView that I'd like to be editable. Even if I return YES from -tableView:shouldSelectRow: and YES from tableView:shouldEditTableColumn:row:, however, editing does not actually commence. The row selects, and I've confirmed with logs that both delegate methods are indeed getting called; the tableView seems to just decide not to start editing after all. No other console logs appear, so it's not a raise. Simply not implementing the two delegate methods mentioned above does not make any difference. The object value for cell that should enter editing is an NSString, and its cell is an NSTextFieldCell. Is there some additional step I have to take to make editing actually commence? The title of this thread is a bit wrong, sorry about that. I was originally trying to figure out a way to allow editing without selecting, but when I realized I couldn't get editing to happen at all, in any case whatsoever, my focus shifted. :- I am letting the row get selected as normal, and it seems to be selected correctly, as my first message says. Ben Haller Stick Software ___ 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: Editing in a tableview without selecting
On 1-Nov-09, at 4:22 PM, Scott Waters wrote: I'm new to Obj-c / Cocoa but this was helpful in figuring out editable table views I was trying to create with IB. Maybe it can help you in your case. http://www.idevgames.com/forum/showpost.php?p=94784postcount=3 I know I wasn't putting a dictionary object into an array with the same identifier that I had created in IB. So I could edit my data in my tableview but as soon as I was done editing it never updated my array so it my data never changed. Thanks for the reference, but the problem I'm seeing is that editing doesn't even begin on my tableview. I double-click on a cell, and nothing whatsoever happens. Ben Haller Stick Software ___ 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: Editing in a tableview without selecting
On 1-Nov-09, at 6:01 PM, Graham Cox wrote: On 02/11/2009, at 4:42 AM, Ben Haller wrote: But where? I've been hunting for a -setEditable:YES method somewhere that I need to call, but I haven't found it... Hi Ben, Have you tried -setEditable:YES on the textfield cell you're using for the table column? (Inherited from NSCell). I'm not sure what its default state is, documentation doesn't say. Just tried it; makes no difference. I think I will have to construct a test case to see if I can reproduce this in a simple, isolated way. If that test case reproduces the problem, then I will post it somewhere and follow up on the list... Ben Haller Stick Software ___ 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: 64 bit cocoa version of HIViewFlashDirtyArea() ?
On 30-Oct-09, at 9:17 PM, Sean McBride wrote: David M. Cotter (m...@davecotter.com) on 2009-10-30 9:04 PM said: anyone have some sample code for a function that does the equivalent of HIViewFlashDirtyArea() ? i'd like to have this i the debug version of my program to help flush out inefficient invalidating. or: how do i fetch the invalid region of an NSWindow* ? Never tried, but... if I search for flash in this doc: http://developer.apple.com/mac/library/technotes/tn2004/tn2124.html I think NSShowAllDrawing might help you. I just tried -NSShowAllDrawing YES in arguments to be passed on launch and it worked quite nicely. The only odd thing is that it seems to flash each view two times for every one time it gets drawn. I verified by other means (let's hear it for NSLog!) that a given view was in fact getting called to draw only once, but was flashing twice. I don't know if there's a good reason for that behavior or not. :- Apart from that issue, it worked quite nicely. Thanks for the tip, Sean. Ben Haller Stick Software ___ 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...
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
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
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
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: How to run a panel that customizes a new NSDocument
hope I've caused no lasting offense. Read this: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ErrorHandlingCocoa/CreateCustomizeNSError/CreateCustomizeNSError.html#/ /apple_ref/doc/uid/TP40001806-CH204-BAJIIGCC and note particularly: Note: Cocoa methods that indirectly return error objects in the Cocoa error domain are guaranteed to return such objects if the method indicates failure by directly returning nil or NO. With such methods, you should always check if the return value is nil or NO before attempting to do anything with the NSError object. NSDocumentController methods play by these specific rules, so your overrides must do so too. Returning the user cancelled error is a special-case refinement of the technique that permits the (ultimate) suppression of the error alert. (The same technique is useful in cases where there really is an error but you want to display the alert yourself, but you want to prevent the NSDocumentController from complaining a second time.) It's not really well documented, but -- I hope you noticed -- you got the answer for free just by asking the question. OK, very good to know. As I noted in an earlier post, I was misled by the NSError documentation that says: In general, a method should signal an error condition by—for example— returning NO or nil rather than by the simple presence of an error object. The method can then optionally return an NSError object by reference, in order to further describe the error. Thanks for the ref to the better doc; I will read that, and if it seems appropriate, will file a doc bug on the item that misled me. As for I hope you noticed -- you got the answer for free just by asking the question, yes, of course I appreciate the list's helpfulness, and your helpfulness specifically, and I think I'm careful to thank people. There's no need to be snippy. I've posted hundreds of replies to this list and other cocoa-related lists helping people out myself, although that was many years ago now, since I took a multi-year break from coding recently. I'm sure there are old- timers around who remember me. So, thank you for your help. Let's move on. Ben Haller Stick Software ___ 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?
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
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: How to run a panel that customizes a new NSDocument
On 21-Oct-09, at 12:57 AM, Graham Cox wrote: On 21/10/2009, at 3:43 PM, Ben Haller wrote: There must be a good, clean way to do this. Anyone? Well, the expected way is to have different types for your documents. You can still map them all to the same class, and discriminate in the -initWithType:error: method to set up the appropriate model. However, if you really can't or don't want to do that, I think what you've done is right. Because you have a special designated initializer, you have no option but to manually make the controllers and add the document to the controller. OK, I've switched over to an NSDocumentController and using different types for my different models. That turned out to be a forced move, because NSApplication's delegate method - applicationOpenUntitledFile: does not get called when the user chooses New from the File menu; that seems to go right to NSDocumentController. -applicationOpenUntitledFile: only seems to get called for the new document created when an app is launched or brought front without an open document. I could have started changing the actions for menu items and so forth, but I decided that since my app is document-based, I ought to go with the document architecture. So I now have an NSDocumentController subclass, and I override openUntitledDocumentAndDisplay:error:. That seems to be in the code path for all kinds of new documents. However, I still find this architecture quite unsatisfying. My - openUntitledDocumentAndDisplay:error: subclass still needs to do way too much work: - (id)openUntitledDocumentAndDisplay:(BOOL)displayDocument error: (NSError **)outError { NSString *chosenModelName = [AKNewModelController runNewModelPanel]; if (chosenModelName) { NSError *error = nil; AKDocument *document = [self makeUntitledDocumentOfType:chosenModelName error:error]; if (error) { if (outError) *outError = error; return nil; } [self addDocument:document]; if (displayDocument) { [document makeWindowControllers]; [document showWindows]; } return document; } return nil; } The sequence of -makeUntitledDocumentOfType:error:, then makeWindowControllers, then showWindows, is already in super, but I don't have any way to make super do it. So I have to duplicate that sequence in my own code, which makes my code vulnerable to architectural changes in NSDocument. I gather this sequence has already changed at least once in the past, so it is clearly fragile. There really must be a better way to do this; I feel like I'm running at counter purposes to the design of the framework. Anyone have any better suggestions? I'm curious as to why -makeUntitledDocumentOfType:error: doesn't do the work of adding the document, setting up its windowController,s and showing the windows. That would seem like the natural design to me, rather than making everyone that calls that method do that work themselves. Is there a reason for this design? Ben Haller Stick Software ___ 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 run a panel that customizes a new NSDocument
On 21-Oct-09, at 6:55 PM, Ben Haller wrote: OK, I've switched over to an NSDocumentController and using different types for my different models. That turned out to be a forced move, because NSApplication's delegate method - applicationOpenUntitledFile: does not get called when the user chooses New from the File menu; that seems to go right to NSDocumentController. -applicationOpenUntitledFile: only seems to get called for the new document created when an app is launched or brought front without an open document. I could have started changing the actions for menu items and so forth, but I decided that since my app is document-based, I ought to go with the document architecture. So I now have an NSDocumentController subclass, and I override openUntitledDocumentAndDisplay:error:. That seems to be in the code path for all kinds of new documents. However, I still find this architecture quite unsatisfying. My - openUntitledDocumentAndDisplay:error: subclass still needs to do way too much work: Furthermore, the way I have it coded now does not even work. Clicking cancel in my choose a model window returns a nil string to my NSDocumentController subclass - openUntitledDocumentAndDisplay:error:, and I see that nil and immediately return nil myself, since the user has cancelled. That results in a raise from the Kit: #0 0x964ef688 in objc_msgSend () #1 0x93d7e9e6 in -[NSDocumentController(NSInternal) _fixedFailureReasonFromError:] () #2 0x93d7c2fd in -[NSDocumentController _willPresentCreationError:] () #3 0x9393d2d4 in -[NSDocumentController(NSInternal) _openUntitled] () #4 0x9393d109 in -[NSApplication _doOpenUntitled] () #5 0x9393c7ed in -[NSApplication(NSAppleEventHandling) _handleAEOpen:] () Apparently if -openUntitledDocumentAndDisplay:error: is called, it *must* create a new document, otherwise it is a raise-worthy error. So my whole design is once again invalid. I'm not even sure how I might fix it. Overriding -newDocument instead doesn't seem to be an option, because it doesn't have any way to pass on the type chosen to the rest of the call chain. The docs for -newDocument say this: It invokes openUntitledDocumentAndDisplay:error: with the document type (first argument) being the first one specified in the CFBundleDocumentTypes property (defined in Info.plist); the document type determines the NSDocument subclass used to instantiate the document object. But that seems to be obsolete; the document type is not passed to - openUntitledDocumentAndDisplay:error: at all. I wish it were; then overriding -newDocument would clearly be the right architecture. This is driving me crazy. Tons of apps want to do this (run a panel on a new document request, and make a new document configured based on the results of that panel). There must be an easy way to do it in the NSDocument architecture; I'm just trying to tap in at the wrong point, somehow. Help! Ben Haller Stick Software ___ 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: Dirty rects getting merged together makes for inefficient drawing
On 20-Oct-09, at 6:54 AM, Uli Kusterer wrote: On 19.10.2009, at 23:58, Ben Haller wrote: On 19-Oct-09, at 5:27 PM, Dave Keck wrote: Would NSView's -getRectsBeingDrawn:count: help? Well, I'm already using it in my own code where appropriate. (Or actually I'm using -needsToDrawRect:). But the problem is that a whole bunch of NSTableView cells are getting drawn that never got invalidated. That's like saying: I'm using the setter, why would I need to use the getter? The dirtyRect parameter passed to drawRect: is the union of all redraw rectangles. So, it's the smallest rect that encloses all the dirty rects. drawRect: does not get called for each redraw rect. If you want the individual sub-rects, use getRectsBeingDrawn:count: and loop over all those rects and draw the individual parts. Uh, Uli, reread what I typed. I did not say or actually I'm using setNeedsDisplayInRect:. -needsToDrawRect is a shorthand for exactly what you propose: calling -getRectsBeingDrawn:count: and looping over those rects. From the docs for -needsToDrawRect: It gives you a convenient way to determine whether any part of a given graphical entity might need to be drawn. It is optimized to efficiently reject any rectangle that lies outside the bounding box of the area the receiver is being asked to draw in drawRect:. So whether -needsToDrawRect or -getRectsBeingDrawn:count: is a better solution depends mostly upon taste, and a little bit on how many tests you intend to do in your draw method (i.e. efficiency to testing). For my purposes, doing a total of two tests, - needsToDrawRect is fine. Ben Haller Stick Software ___ 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: Dirty rects getting merged together makes for inefficient drawing
On 20-Oct-09, at 6:59 AM, Uli Kusterer wrote: On 20.10.2009, at 03:02, Ben Haller wrote: As for NSTableView, it does appear to be doing minimal drawing. So I guess all the string-drawing overhead I see in Sampler is just from the single column that is updating, which is unfortunate since it means I have no room for optimization. I never imagined it would take so much time just to draw the one column I dirtied. This may help to optimize after all: http://zathras.de/blog-cocoa-text-system-everywhere.htm This is interesting, and I've done this sort of thing in the past quite a bit actually. I'm surprised by one bit of it, though, where it says: ...sometimes you need better performance than the NSStringDrawing category will provide... implying that doing things this way is faster than NSStringDrawing. Is that actually true? Why would that be? NSStringDrawing does more or less exactly this, doesn't it, using cached a cached textstorage/ layout/container set? If NSStringDrawing is less efficient than doing it yourself, where does that inefficiency lie, and why doesn't Apple fix that inefficiency? Presumably because Apple's way has some other benefit? So what is that benefit? I.e. I'm trying to understand what the tradeoffs are here. In the past, playing around with such things, the big win I've noticed over NSStringDrawing comes up only if you need to both measure and draw the same string. Then you set everything up with your string once, measure and draw, and layout needs to happen only once. So drawing centered or right-aligned text is faster -- almost twice as fast -- doing it yourself. If there's a way to get the same speedup from Apple's API's I'm not aware of it; AFAIK even - [NSAttributedString drawWithRect:options:] doesn't let you draw a string centered or right-aligned in the rect, which seems like a big oversight. I've just logged 7318495 on that. But if you're drawing text left-aligned, and thus don't need to measure it, is there any speedup doing things yourself? Cheers, Ben Haller Stick Software ___ 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: Dirty rects getting merged together makes for inefficient drawing
On 20-Oct-09, at 8:15 AM, Graham Cox wrote: On 20/10/2009, at 11:03 PM, Ben Haller wrote: AFAIK even -[NSAttributedString drawWithRect:options:] doesn't let you draw a string centered or right-aligned in the rect, which seems like a big oversight. I've just logged 7318495 on that. That's not the case - NSAttributedString takes its left/right/center/ justified setting from the NSParagraphStyle attribute attached to the string. If it's not there, it defaults to natural alignment for the font (left for English). Oh! Good to know. Didn't occur to me somehow! I.e. I'm trying to understand what the tradeoffs are here. Convenience versus speed. Setting up a text layout system programatically is quite involved, and for a high-level solution that is equivalent to olde-worlde DrawThemeTextBox the string drawing methods do that for you. But they have to build up and tear down a text system for every call, so incur this overhead and can't cache any layout information. I still think it's the case (borne out by profiling here) that glyph rendering still dominates the process however. But if you're drawing text left-aligned, and thus don't need to measure it, is there any speedup doing things yourself? Yes, if you are drawing the same string over and over again (as in repeated refreshes of the same string in a view). The question is whether the speed-up matters. If you have thousands of text objects in your view, probably yes. If just one or two, probably not. There's no need to (and you can't) draw faster than 60 fps so you have ~16mS to draw everything. If it takes longer, text caching etc may help. Ah, yes, that is true, repeated drawing of the same string would be a big win for this. Uli had much the same to say. Good points. Thanks guys. Ben Haller Stick Software ___ 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
How to run a panel that customizes a new NSDocument
Hi all. I've got an NSDocument-based class that can be based upon a variety of models. The documents are the same type in any case, but they are configured differently based upon their model. When the user chooses New, or when the app is launched, I want to run a panel for the user to choose their desired model. Once they dismiss the panel, a document using that model will be created. I.e. very much like how Interface Builder runs a panel where you choose the sort of nib you want to make, and then it makes you a new nib of that sort. The question is how to do this. I see the stuff in NSDocument/ NSDocumentController having to do with types but that does not seem relevant; that would be for an app that could open and save both .txt and .rtf files, for example. All of my documents are of the same type, they just have different initial state. What I have ended up with, after a fair amount of fruitless searching in the NSDocument docs, is this method in my application delegate: - (BOOL)applicationOpenUntitledFile:(NSApplication *)theApplication { AKModel *chosenModel = [AKNewModelController runNewModelPanel]; if (chosenModel) { AKDocument *newDocument = [[AKDocument alloc] initWithModel:chosenModel]; [newDocument makeWindowControllers]; [newDocument showWindows]; [[NSDocumentController sharedDocumentController] addDocument:newDocument]; return YES; } return NO; } I don't like it very much though. It works, but it hard-codes the sequence of -makeWindowControllers, then -showWindows, then - addDocument:, all of which NSDocumentController ought to be doing for me. I wonder if I need to subclass NSDocumentController instead, but it isn't really clear to me how to do that to achieve this. I could override -openUntitledDocumentAndDisplay:error:, and run my model chooser panel inside my override, but how do I get the model the user chose into the new document if the NSDocumentController creates it for me? Right now I pass the model in to the document's -initWithModel: method. I could refactor things so that the document created is generic and model-less, and then set a model on it after it has constructed; but that would be highly inconvenient, as it happens, because the windows the document makes depend upon its model, and the document's windows get shown by NSDocumentController before it would return control to me (i.e. inside [super openUntitledDocumentAndDisplay:error:] returns). There must be a good, clean way to do this. Anyone? Ben Haller Stick Software ___ 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
Dirty rects getting merged together makes for inefficient drawing
Hi all. I expected this to be an FAQ, but my searches have turned up nothing relevant, so here goes. I've got a window with a view hierarchy like this: 1. Superview that does no drawing and is not opaque A. Subview #1: a tableview that is opaque B. Subview #2: a graph view that is opaque C. Subview #3: another graph view that is opaque The tableview is on top, the two graph are on the bottom, on the left and on the right respectively. My app alternates calculating and drawing the results. Typically, what needs to get drawn is *one* column of the tableview, plus both graphs. I'm carefully calling setNeedsDisplayInRect: for only the bits that need to be drawn; I'm using [frameOfCellAtColumn:row:] to get the frame of the cells that need to be redrawn, and invalidating only them, for example. If I turn off all redrawing of the graphs, then Quartz Debug shows me that my invalidating in the tableview is minimal; only the column that needs to be drawn flashes. If I turn off all redrawing of the tableview, QuartzDebug similarly shows that my invalidating in the graphs is minimal. So taken separately, it's all good. But when drawing of all the views is turned on, somebody is merging together the dirty rects and causing pretty much the entire content of the window to redraw. This means that a ton of extra table cells are redrawing unnecessarily, and I see the overhead from this very clearly in Instruments/Sampler (text drawing is not fast!). So my question is: is there any way I can exert any control over the merging of dirty rects? I thought maybe adding some vertical space between the tableview and the graph views would disconnect them and make the dirty rects get handled separately; but no dice; even adding 100 pixels of vertical space doesn't prevent the merge. Is the merging dependent upon the view hierarchy or opacity in some way? Or are there CG calls somewhere in the bowels that I could use to change a merge threshold or something? I'm not sure whether this is a Cocoa or a CG question really, but since I'm using nothing but Cocoa calls at present, I figured I'd try this list first... Thanks! Ben Haller Stick Software ___ 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: Dirty rects getting merged together makes for inefficient drawing
On 19-Oct-09, at 5:27 PM, Dave Keck wrote: Would NSView's -getRectsBeingDrawn:count: help? Well, I'm already using it in my own code where appropriate. (Or actually I'm using -needsToDrawRect:). But the problem is that a whole bunch of NSTableView cells are getting drawn that never got invalidated. I would certainly hope that NSTableView is using one of these minimal-drawing mechanisms, and I assume that it is. I think the problem is deeper (based upon what flashes under Quartz Debug): I think the dirty rects are actually getting consolidated such that NSTableView no longer has the information it needs to do minimal drawing. I could be mistaken about that, though, if the flashes in Quartz Debug show only the area that Quartz is choosing to blit over, and not necessarily the area that was considered dirty and redrawn. (i.e. if it brings over merged areas for efficiency, for some reason; but that seems unlikely...) Ben Haller Stick Software ___ 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: Why does my font come out looking fuzzy?
Yes, it sounds like the suggestions I've gotten for modifying the antialiasing behavior would probably be helpful. I have solved the problem by simply snapshotting the LCD digit images and writing a little control that displays a number using those snap images. Seemed simpler, sadly. Works great. Thanks to the posters, though; CALayer and related concepts are quite new to me, so it is good to develop some mental context surrounding them! Ben Haller Stick Software On 19-Oct-09, at 6:24 PM, Dalmazio Brisinda wrote: Kyle's explanation #1 was spot on for my application. I had an NSSearchField in a custom window and view which was not displaying quite correctly. It looked as if it was not being anti-aliased. Going into Interface Builder, I noticed I had selected the Wants core animation layer switch for the control. Turning this off corrected the problem. Best, Dalmazio On 2009-10-17, at 9:27 PM, cocoa-dev-requ...@lists.apple.com wrote: You need to post a screenshot of what you're seeing. I can think of two possibilities off the top of my head: 1) You're rendering text into a CALayer (especially a CATextLayer). Without some tweaking, CALayer can't do subpixel antialiasing (aka LCD antialiasing), because it doesn't have the existing backing store to composite against. 2) You're overdrawing the text and are therefore ruining the antialiasing, producing a distorted image. Again, screenshot is pretty much mandatory here. --Kyle Sluder ___ 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/bhcocoadev%40sticksoftware.com This email sent to bhcocoa...@sticksoftware.com ___ 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: Dirty rects getting merged together makes for inefficient drawing
On 19-Oct-09, at 5:58 PM, Greg Guerin wrote: Ben Haller wrote: 1. Superview that does no drawing and is not opaque A. Subview #1: a tableview that is opaque B. Subview #2: a graph view that is opaque C. Subview #3: another graph view that is opaque Obvious experiment: set the superview to be opaque. Indeed. Already tried it (right after posting), and it makes no difference. I'd try rearranging the view hierarchy to test the effects of that, but that isn't trivial, because it is arranged programmatically, so I'm hoping someone has already explored this... More generally, I am interested in knowing how this mechanism works, beyond just fixing my immediate problem, so I hope somebody can comment on that more generally. And whether there is any way to affect it, beyond my immediate case. I find nothing in the docs about it. Ben Haller Stick Software ___ 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: Dirty rects getting merged together makes for inefficient drawing
On 19-Oct-09, at 6:53 PM, Andy Lee wrote: On Monday, October 19, 2009, at 05:58PM, Ben Haller bhcocoa...@sticksoftware.com wrote: I think the problem is deeper (based upon what flashes under Quartz Debug): I think the dirty rects are actually getting consolidated such that NSTableView no longer has the information it needs to do minimal drawing. To test this theory, might it help to use a subclass of NSTableView whose drawRect: method prints the rectangle passed to it, and see what happens when your graph views do and do not do any drawing? And maybe the result of getRectsBeingDrawn:count: as well? Just did this. The results are interesting. Two points of note: - my tableview does seem to be getting passed a nicely limited dirty rect, even though Quartz Debug flashes a much larger area. So apparently flashes in Quartz Debug are only indicative of what Quartz is choosing to blit over to the screen, not what is actually getting updated. If so, it would be useful to have a new checkbox in Quartz Debug that flashed only the areas actually getting marked as dirty, I think, so that one could check one's minimal-redraw correctness. I logged 7317630 on this. - there do seem to be some weirdnesses in the dirty rect accumulation code. For example, when I call -getRectsBeingDrawn:count: and log the results, I typically see something like this: count == 2 rects[0] == {{47, 12}, {45, 215}} rects[1] == {{47, 0}, {45, 12}} So abutting rects of the same width are not getting merged together. Oddly, the dividing line between these rects is not at a line boundary in my tableView; a bunch of lines get accumulated together into the tall rect, and then the topmost line gets split between the tall rect and the little rect. I have no theory as to why this would be. As for NSTableView, it does appear to be doing minimal drawing. So I guess all the string-drawing overhead I see in Sampler is just from the single column that is updating, which is unfortunate since it means I have no room for optimization. I never imagined it would take so much time just to draw the one column I dirtied. So, sorry for the false alarm. The main take-home point I get out of all this is that Quartz Debug flashes the areas being blitted over, which are not the same as the areas marked dirty or the areas requested to be redrawn! Ben Haller Stick Software ___ 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: Dirty rects getting merged together makes for inefficient drawing
On 19-Oct-09, at 10:40 PM, Andy Lee wrote: Come to think of it, another experiment would have been to add logging to the cells used for the other table columns, to see if their drawing code was actually being called. Yeah, I did that. See my previous post. The upshot is that the table is correctly doing minimal redraws. Sorry if I missed this, but is the string-drawing overhead noticeable to the user? If so, and it's because you're redrawing very frequently, maybe you could throttle redrawing to, say, 2-4 times per second. There's something called coalesced updates that might help. I'll check it out. I kinda want it to redraw a lot really really fast, though, because it looks cool. ;- I'm throttling my drawing to 60 frames per second at present, and then I'm trying to optimize the drawing code so that it takes as little time as possible, so that as much of each 1/60th second is left to calculate in as possible. Maybe I will make the tableView update every 1/30th of a second, and update everything else every 60th since it all draws faster. :- Does the table column's cell have to do much work to get the string it needs to draw (a gross example would be querying a database)? Maybe caching would help. Nope, all the time is in the string-drawing stuff inside AppKit. I don't know how much overhead is in cell drawing, but maybe you could write your own cell class that doesn't, for example, check whether the string needs to be truncated. IIRC it wasn't stuff like that. It was setting up the text storage and the typesetter, and then doing the actual drawing, I think. Nothing I could reasonably optimize, I think, without getting extremely dirty. There's a section in the docs on optimizing drawing. I must admit I haven't read it, but maybe it contains something that would help in your case? Read that. Useful tips, and it did prompt me to put in checks for whether parts of my views are inside the dirty rects or not, and to make more of my views opaque. Sorry for all the might's and maybe's --I'm hoping one of my stabs in the dark will help. Well, I'm curious about the coalesced update thing. The only ref I find through Google is here: http://developer.apple.com/mac/library/documentation/Performance/Conceptual/Drawing/Articles/CocoaDrawingTips.html and I don't think that's what you're referring to. AppKiDo (which I still love :-) doesn't find any APIs with coalesce in their name that are drawing-related. Can you give me a pointer? Thanks! Ben Haller Stick Software ___ 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: Why does my font come out looking fuzzy?
On Oct 17, 2009, at 7:46 PM, Ben Haller wrote: Copied the TrueType font from Instruments into my project, added the necessary key to my Info.plist, set the font using [NSFont fontWithName:...], and hey presto, there the font is in my app. Only... it doesn't look as nice. It's less crisp. Kind of fuzzy. The corners don't look sharp. OK, this is all replying to various helpful folks who replied to that: On 17-Oct-09, at 10:52 PM, Kyle Sluder wrote: You need to post a screenshot of what you're seeing. OK: http://www.sticksoftware.com/textrendering/ The point size in Instruments is probably 18, but I tried 19 just in case and it doesn't look right either. I can think of two possibilities off the top of my head: 1) You're rendering text into a CALayer (especially a CATextLayer). Without some tweaking, CALayer can't do subpixel antialiasing (aka LCD antialiasing), because it doesn't have the existing backing store to composite against. 2) You're overdrawing the text and are therefore ruining the antialiasing, producing a distorted image. I'm using an NSTextField to do the text drawing. It certainly renders text antialiased. In any case, the renderings do look antialiased; the edges are not sharply on pixel boundaries (see the top of the 5, for example). It just isn't the same appearance as in Instruments. On 17-Oct-09, at 11:43 PM, Clark S. Cox III wrote: There's also the possibility that the text isn't being drawn properly aligned to the pixel grid. I tried making the NSTextField have a frame offset by 0.5 pixels, just in case, but that made no visible difference to the rendering. I suspect NSTextField corrects for such misalignment. So unless the font is actually *designed* to be drawn misaligned to the grid, I think I'm OK in this department. On 18-Oct-09, at 1:32 AM, Jens Alfke wrote: Is the point size the same? If this is a special-purpose font, it might have some hinting for the specific point size used in Instruments. You might need to compare the character heights up- close with Pixie or something. I counted pixels in Pixie, and it looks to me like Instruments is 18-point. It's a bit hard to tell with the antialiasing going on, but they are somewhere from the 18-point rendering to the 19-point rendering I posted (see link above). Now I'm wondering whether Instruments is actually even using this font. I think it might be a red herring. Note that the time view in instruments appears to be monospaced, whereas the snapshots of my rendering using the font show that it is not a monospaced font. And note that their colons are centered vertically, while mine using the font are oddly low in their position. The font may be a leftover from a previous implementation, perhaps. However, a troll through the images in Instruments does not reveal any digit images. Although it is an interesting exercise anyway; many of their button images and such are PDFs, which is intriguing. Anyhow, I think it's probably time to abandon this quest, unless someone has a good idea of how to proceed. Spiffy LCD-style display on my generation counter will just have to wait. Ben Haller Stick Software ___ 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
Why does my font come out looking fuzzy?
So, I like the LCD-style font that Instruments uses to show the time counter at the top center of the window. Thought I might use it myself for an in-house project (not for release). Copied the TrueType font from Instruments into my project, added the necessary key to my Info.plist, set the font using [NSFont fontWithName:...], and hey presto, there the font is in my app. Only... it doesn't look as nice. It's less crisp. Kind of fuzzy. The corners don't look sharp. It no longer looks LCD. What's going on here? I assume it has to do with rendering differences between different typography engines, and hinting, and TrueType (or in this case FalseType, perhaps), and so forth. My basic question: is there a way I can get my Cocoa app to show this font as nicely as it appears in Instruments? I would have guessed that Instruments was itself a Cocoa app, so I'm surprised there's a difference. Anybody know what's going on? I am now considering taking little screenshots of each digit and rolling my own pseudo-font using image blits. Please save me from that fate. Ben Haller Stick Software ___ 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?
(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: A good Obc-C framework for sending email?
On 16-Oct-09, at 3:04 PM, Alastair Houghton wrote: On 16 Oct 2009, at 03:54, Andrew Farmer wrote: On 15 Oct 2009, at 13:34, Ben Haller wrote: Hi all. I need a good Obj-C framework for sending email. I used to use the Message.framework associated with Apple's Mail, but they killed that a long time ago, sadly. Then I used Pantomime; but it seems to also be abandoned, now, and it is crashing on 10.5 (and it was never terribly reliable anyway). Does anybody know of a good replacement? I haven't had any luck trying to find one using Google. Keep in mind that many users may not have any SMTP server configured -- an increasing number of users use webmail for everything, and don't have a desktop client set up. And, in many of these cases, they may be behind a firewall or ISP that blocks connections to port 25 (SMTP) on all servers other than their own. If you need to reliably deliver email from a user's machine, you'll probably need to set up a gateway of some sort yourself, or have them input SMTP settings manually. Or you could do what we do and ask their mail client to deliver it for us. The code we use for that is Open Source, and you can get it here: http://www.coriolis-systems.com/opensource/ CSMail can also generate messages and pop them up in their client ready for them to send themselves, which is something we use in some circumstances as well. (It's possible that we have updated CSMail a bit since the version on that page, I don't know... but if someone's interested in using it, I can check.) I am definitely interested in using it, Alastair. This solution would in fact be optimal for my purposes. If you could make sure it's up to date, that would be great. Ben Haller Stick Software ___ 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
A good Obc-C framework for sending email?
Hi all. I need a good Obj-C framework for sending email. I used to use the Message.framework associated with Apple's Mail, but they killed that a long time ago, sadly. Then I used Pantomime; but it seems to also be abandoned, now, and it is crashing on 10.5 (and it was never terribly reliable anyway). Does anybody know of a good replacement? I haven't had any luck trying to find one using Google. Jens Alfke suggested wrapping a call to sendmail in NSTask, while somehow groping out the right SMTP settings from Mail's prefs, but that sounds like quite a hassle, and hard to get really right such that emails would be reliably delivered. Does anybody have reusable code to do something along these lines? If no good replacement exists, then: if there is anybody on this list who knows Pantomime's code, it could very much use an update. I will be happy to supply crash logs. :- Thanks! Ben Haller Stick Software ___ 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: A good Obc-C framework for sending email?
On 15-Oct-09, at 4:57 PM, Bryan Matteson wrote: Perhaps EDMessage? http://www.mulle-kybernetik.com/software/EDFrameworks/ EDMessage looks good, thanks! Ben Haller Stick Software ___ 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
GC crash due to being naughty
Hi all. I'm getting a crash in auto_zone_root_write_barrier() that I don't understand. I suspect it has to do with this little blurb in the Garbage Collection Programming Guide: Limitations on Mac OS X v10.5: You may pass addresses of strong globals or statics into routines expecting pointers to object pointers (such as id* or NSError**) only if they have first been assigned to directly, rather than through a pointer dereference. You should never take the address of a weak global, static or instance variable, as assigning or reading through that pointer will bypass the weak barriers and expose your programs to race conditions. But I'm not really sure. :- Here's the situation. My app generates floods of instances of an NSObject subclass called AKIndividual. So many, in fact, that I don't want to alloc and dealloc them all, as that just thrashes the allocator madly (as verified with Sampler). Instead, I want to allocate a pool of them, and then throw them in the pool when I'm done with them, and get new ones out of the pool. (When I reuse them, I don't call -init again, I just wipe the ivars I'm using and put new values in, which I believe is OK.) When I'm messing about with them, and when they're in the pool, I don't want to keep them in Cocoa collections like NSMutableArray, because again that introduces too much overhead. Countless billions upon billions of these little guys I'm making, and the runtimes of my app will be measured in days to weeks, so optimizing this bottleneck really is important. So my solution was to keep pointers to them in malloced buffers instead. The unused pool is a malloced buffer, the pools of ones that are doing various things are also malloced buffers, and everything is nice fast C code at this level. But I guess pointers to objects kept in malloced buffers are weak references, so my objects would be collected if I didn't have a strong reference somewhere. So when I first allocate them, I throw them into an NSMutableArray, and I don't ever take them out. That array is kept by the controller of the whole shebang; so when that controller gets collected, then all the individuals will be collected, but until then, they should always be strong-referenced. This seems like it ought to work; and yet I get that crash in auto_zone_root_write_barrier(). After some puzzling, I found the above paragraph in the GC guide. I am indeed on 10.5. Is this what's biting me? I guess all the pointers to my AKIndividuals that are kept in my malloced arrays are all weak references, and so I guess the pointer to the malloced array itself, for example, is a pointer to a weak reference such as I am not supposed to use, and whenever I do something like individuals[i] to get an instance from my malloced buffer I guess I'm violating the weak barriers. I find it hard to believe that I'm not allowed to keep an array of pointers to objects, though; is that really what this blurb is saying? (On the other hand, the GC guide also says that the malloc zone is never scanned, which would imply that this is fine, and that the references I put in my malloced arrays are not even weak; but then I'm puzzled by the crash in a write barrier function...) I don't really understand what is prohibited and exactly why; that blurb is way too short, and the example is too short and cryptic. Can some explain what is actually prohibited, and why, and whether what I'm doing is prohibited? Given the architecture I'm aiming for, I don't need the references to even be weak references; I don't need them to zero out, because they never will, because these AKIndividuals live at least as long as any given malloced array of them will live. Indeed, I don't care about GC on them at all; I'd be quite happy to exclude them from the GC scheme altogether, and get back the overhead of these read/write barriers, given how much thrash is involved with them. Is that possible? For example, can I malloc the instances of AKIndividual myself out of the malloc zone to exclude them from GC, or is that a Bad Idea? Sorry for the long email. Comments? Ben Haller Stick Software ___ 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: GC crash due to being naughty
That looks like it is more a matter of decreasing memory usage than decreasing alloc/dealloc/containment overhead. A flyweight is an object that minimizes memory use by sharing as much data as possible with other similar objects; it is a way to use objects in large numbers when a simple repeated representation would use an unacceptable amount of memory. So I don't think it applies to my problem. Thanks though! Ben Haller Stick Software On 15-Oct-09, at 7:14 PM, Oftenwrong Soong wrote: Hi Ben, Have you considered the so-called Flyweight design pattern? It is designed to solve the problem of having a zillion objects to allocate. It sounds like this pattern might prevent your having to play the dirty tricks that are causing you problems. In the frameworks, Flyweight is used, AFAIK, in NSNumber, NSCell, and other classes. There's a good description of the pattern here: http://en.wikipedia.org/wiki/Flyweight_pattern Hope this helps a little. (I don't know what could be done to solve the crash you describe but passing pointers as you described sounds like it's bound to cause nasty problems.) Soong - Original Message From: Ben Haller bhcocoa...@sticksoftware.com To: Cocoa List cocoa-dev@lists.apple.com Sent: Thu, October 15, 2009 3:54:11 PM Subject: GC crash due to being naughty Hi all. I'm getting a crash in auto_zone_root_write_barrier() that I don't understand. I suspect it has to do with this little blurb in the Garbage Collection Programming Guide: Limitations on Mac OS X v10.5: You may pass addresses of strong globals or statics into routines expecting pointers to object pointers (such as id* or NSError**) only if they have first been assigned to directly, rather than through a pointer dereference. You should never take the address of a weak global, static or instance variable, as assigning or reading through that pointer will bypass the weak barriers and expose your programs to race conditions. But I'm not really sure. :- Here's the situation. My app generates floods of instances of an NSObject subclass called AKIndividual. So many, in fact, that I don't want to alloc and dealloc them all, as that just thrashes the allocator madly (as verified with Sampler). Instead, I want to allocate a pool of them, and then throw them in the pool when I'm done with them, and get new ones out of the pool. (When I reuse them, I don't call -init again, I just wipe the ivars I'm using and put new values in, which I believe is OK.) When I'm messing about with them, and when they're in the pool, I don't want to keep them in Cocoa collections like NSMutableArray, because again that introduces too much overhead. Countless billions upon billions of these little guys I'm making, and the runtimes of my app will be measured in days to weeks, so optimizing this bottleneck really is important. So my solution was to keep pointers to them in malloced buffers instead. The unused pool is a malloced buffer, the pools of ones that are doing various things are also malloced buffers, and everything is nice fast C code at this level. But I guess pointers to objects kept in malloced buffers are weak references, so my objects would be collected if I didn't have a strong reference somewhere. So when I first allocate them, I throw them into an NSMutableArray, and I don't ever take them out. That array is kept by the controller of the whole shebang; so when that controller gets collected, then all the individuals will be collected, but until then, they should always be strong-referenced. This seems like it ought to work; and yet I get that crash in auto_zone_root_write_barrier(). After some puzzling, I found the above paragraph in the GC guide. I am indeed on 10.5. Is this what's biting me? I guess all the pointers to my AKIndividuals that are kept in my malloced arrays are all weak references, and so I guess the pointer to the malloced array itself, for example, is a pointer to a weak reference such as I am not supposed to use, and whenever I do something like individuals[i] to get an instance from my malloced buffer I guess I'm violating the weak barriers. I find it hard to believe that I'm not allowed to keep an array of pointers to objects, though; is that really what this blurb is saying? (On the other hand, the GC guide also says that the malloc zone is never scanned, which would imply that this is fine, and that the references I put in my malloced arrays are not even weak; but then I'm puzzled by the crash in a write barrier function...) I don't really understand what is prohibited and exactly why; that blurb is way too short, and the example is too short and cryptic. Can some explain what is actually prohibited, and why, and whether what I'm doing is prohibited? Given the architecture I'm aiming for, I don't need the references to even be weak references
Re: GC crash due to being naughty
On 15-Oct-09, at 7:30 PM, Greg Parker wrote: A pointer value stored in an ordinary malloc block is neither a strong nor a weak reference. It is a dangling pointer. It can be used safely, but requires great care because the garbage collector has no knowledge of what you're doing. The auto_zone_root_write_barrier() crash can occur when you take the address of a global variable, then store into the global indirectly via that address. What does the crashed line of code look like? OK, here's a bit of context. The backtrace: #0 0x95058d7b in auto_zone_root_write_barrier () #1 0x964e40a8 in objc_assign_strongCast_gc () #2 0x7198 in -[AKPopulation addIndividualsFromPopulation:] (self=0x102b740, _cmd=0xe76c, population=0x10a9250) at .../ AKPopulation.m:101 That method: - (void)addIndividualsFromPopulation:(AKPopulation *)population { UInt32 individualCountForPop = [population individualCount]; AKIndividual **individualsForPop = [population individuals]; int i; if (individualCount + individualCountForPop individualCapacity) { individualCapacity = (individualCount + individualCountForPop) * 2; individuals = realloc(individuals, individualCapacity * sizeof(AKIndividual *)); } for (i = 0; i individualCountForPop; ++i) individuals[individualCount++] = individualsForPop[i]; } The crash is in the last line of the method, in the assignment. The class as it stands right now: @interface AKPopulation : NSObject { NSString *title; UInt32 individualCount; UInt32 individualCapacity; AKIndividual **individuals; // malloc'ed array of AKIndividual * } @property (readwrite, copy) NSString *title; @property (readonly) UInt32 individualCount; @property (readonly) AKIndividual **individuals; ... @end So the intent of the method is just to bulk-add individuals from one population into another population. Perhaps another way to ask the question is: suppose you wanted to implement a new collection class, akin to NSMutableArray but somehow different. How would you safely do it under GC, without using any of the pre-made Cocoa collections internally? That's all my AKPopulation really is: a poor man's (but a speedy man's!) re-implementation of something like NSMutableArray. Ought to be possible, right? So how do I manage this write barrier business to make it work properly? Ben Haller Stick Software ___ 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: GC crash due to being naughty
I'd start by taking a look at the CHDataStructures framework: http://cocoaheads.byu.edu/wiki/chdatastructures It's a framework hosted by our local CocoaHeads group that includes most of the data structures that Apple forgot. =) An interesting framework, looks useful. Looking at the CHAbstractCircularBufferCollection class, I don't see it doing any special GC-related dance. The only substantial differences between it and what I am doing are that: - I use malloc to make my array of pointers to objects, and it uses NSAllocateCollectable with NSScannedOption - I declare my pointer as AKIndividual **individuals and it uses __strong id *array So perhaps those choices avoid the issue, by avoiding the caveat You should never take the address of a weak global, static or instance variable, as assigning or reading through that pointer will bypass the weak barriers and expose your programs to race conditions. But then as Greg Parker said, references stored in a malloced block are neither weak nor strong, they are just dangling pointers. So I don't really understand why I'm getting bitten in the first place. Dangling pointers is exactly what I want; why is auto_zone_root_write_barrier() getting into the middle of my assignment loop in the first place? Ben Haller Stick Software ___ 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: GC crash due to being naughty
On 15-Oct-09, at 8:10 PM, Oftenwrong Soong wrote: Hi Ben, You say the crash occurs in this line: individuals[individualCount++] = individualsForPop[i]; The problem may be in the post-increment (individualCount++). IIRC, there is no agreed-upon compiler standard as to whether the post- increment will occur before or after the assignment. It is possible that you're using the bytes after the end of the array as a pointer, which points to a random location rather than to your desired data. If you want the increment to happen after the assignment, do this: for (i = 0; i individualCountForPop; ++i) { individuals[individualCount] = individualsForPop[i]; individualCount++; } If you want it before, just reverse the order of the two lines. I've had many a headache in the past with things like this!! Huh. Could've sworn that was well-defined. Well, I've been away from coding for about six years now, guess I've gotten a little rusty. In any case, this change does not fix the problem; same crash, on the assignment line. Ben Haller Stick Software ___ 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: GC crash due to being naughty
On 15-Oct-09, at 8:26 PM, Greg Parker wrote: I don't see any global pointer variables involved. My guess is that `individuals` is uninitialized or NULL or `individuals[individualCount]` is out of bounds. The write barrier objc_assign_strongCast() does range checks on the destination address, and will fall back to auto_zone_root_write_barrier() for addresses it doesn't recognize. Those include malloc blocks, global variables, and bogus addresses. Perhaps another way to ask the question is: suppose you wanted to implement a new collection class, akin to NSMutableArray but somehow different. How would you safely do it under GC, without using any of the pre-made Cocoa collections internally? That's all my AKPopulation really is: a poor man's (but a speedy man's!) re- implementation of something like NSMutableArray. Ought to be possible, right? So how do I manage this write barrier business to make it work properly? You need to ensure two things when implementing storage for GC pointers. First, the storage must be scanned by the garbage collector. Second, writes to the storage must use an appropriate write barrier function... This all makes sense to me, to the extent that I understand write barriers at all. :- I switched my code over to NSAllocateCollectable with NSScannedOption, and it still crashed. This led me to generate a new hypothesis: that I am an idiot. I have now proven that hypothesis to my full satisfaction. I will not be telling the list what the error was that caused my code to crash. Let's just say I'm very out of practice at this whole coding thing, and leave it at that. :- Still, this thread was quite useful in that it did solidify my understanding of weak/strong/dangling, and led me to switch my collection class over to strong references. That's progress. Thanks to everybody for their help! Ben Haller Stick Software ___ 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
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
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
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: Screensaver won't run on 10.6 even after porting to 64-bit
On 12-Oct-09, at 8:14 PM, Charles Srstka wrote: On Oct 11, 2009, at 9:46 PM, Ben Haller wrote: Most of the bugs I had to fix were related to either using long instead of int, or needing a -finalize method. You should actually probably be using NSInteger instead of either of those these days. Yes, but NSInteger is 10.5 or later; I'm keeping 10.4 compatibility for now. Anyhow, those uses were all in my own internal logic, which can stay using 32-bit ints. There's actually a ConvertCocoa64 script found in /Developer/Extras/ 64BitConversion that will scan your files for other things that could bite you in the transition to 64-bit. You should probably give it a spin, to make sure you're all up to date. This page contains some handy information, too: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Cocoa64BitGuide/ConvertingExistingApp/ConvertingExistingApp.html Good stuff, I'll check it out. Thanks Charles! Ben Haller Stick Software ___ 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
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?
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
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
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
bringing a previously designed project to deployment . Major changes in technologies are generally best saved for major versions. Also known as the if it's making money, don't with it principle. 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. - 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
Screensaver won't run on 10.6 even after porting to 64-bit
Hi folks. So my screensaver broke on 10.6, along with everybody else's, and I'm told that's because it has to be compiled for the 64- bit architecture, because System Prefs is a 64-bit app on 10.6. So I set up a conditional compilation thing where it compiles three versions: - ppc against the 10.4 SDK (deployment target 10.4), GCC 4.0 - intel against the 10.4 SDK (deployment target 10.4), GCC 4.0 - intel 64-bit against the 10.6 SDK (deployment target 10.6), GCC 4.2 These settings are from a web page about how to get a screensaver to work on 10.6; I don't know why the GCC version needs to vary, for example. I'm just following orders. :- This all seems to work fine, after much fussing about with deprecated APIs and such. My screensaver now builds and links without errors, and lipo gives me promising-looking output showing my three architectures. The screensaver runs fine on 10.5 intel; haven't tried it on 10.4 or ppc, but I imagine it's fine there too. But on 10.6 I still get the same error from System Preferences. Opened Console and saw this: 10/11/09 2:51:18 PM ScreenSaverEngine[204] Error loading ...: dlopen(..., 265): no suitable image found. Did find: ...: GC capability mismatch 10/11/09 2:51:18 PM ScreenSaverEngine[204] ScreenSaverModules: can't get principalClass for ... So I guess System Preferences doesn't like my garbage collection setting (which is set to Unsupported). Do I really need to turn GC on to get my screensaver to work?? I haven't seen anything about that elsewhere, so this catches me a bit off guard. I would have assumed that they would build it to be able to handle either style. Is there any way around this? Since I want my screensaver to still run on 10.4, this is more than a little inconvenient. Thanks for any advice! Ben Haller Stick Software ___ 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: Screensaver won't run on 10.6 even after porting to 64-bit
On 11-Oct-09, at 3:28 PM, Clark Cox wrote: On Sun, Oct 11, 2009 at 12:23 PM, Dave Keck davek...@gmail.com wrote: So I guess System Preferences doesn't like my garbage collection setting (which is set to Unsupported). Do I really need to turn GC on to get my screensaver to work? Yes, your screensaver must be GC-supported to support Snow Leopard. This bit me recently too - I wasn't expecting it either. So much for GC making our lives easier, eh? :) On the bright side, you can make your bundle GC-supported, which means it contains both retain/release and GC logic. This will at least buy you 10.5 10.6 support in the same bundle, but I imagine you'll have to compile a separate GC-unsupported version for 10.4, but I'm really not sure. Hopefully someone else could comment on that. You can use per-arch build settings to make the ppc and i386 parts GC-unsupported, but make the x86_64 part GC-required; there's no need to build separate bundles. OK, makes sense. My only question: what's the best way to switch at compile time based on whether GC is enabled for the build? I.e. what do I #if or #ifdef? I could do it based on the arch or the SDK, but if there's a flag specifically for GC I'd rather use that... Thanks! Ben Haller Stick Software ___ 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: Screensaver won't run on 10.6 even after porting to 64-bit
On 11-Oct-09, at 3:52 PM, Kyle Sluder wrote: On Oct 11, 2009, at 12:44 PM, Ben Haller bhcocoa...@sticksoftware.com wrote: OK, makes sense. My only question: what's the best way to switch at compile time based on whether GC is enabled for the build? I.e. what do I #if or #ifdef? I could do it based on the arch or the SDK, but if there's a flag specifically for GC I'd rather use that... The purpose of GC-supported rather than GC-required is that you don't do this. Rather, you write your code so that it works in either retain-release or garbage collected environments. Yes, but my code also needs to compile as GC-unsupported against the 10.4 SDK, where any GC-specific calls that I might need to make will not compile. Am I missing something? Ben Haller Stick Software ___ 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: Screensaver won't run on 10.6 even after porting to 64-bit
On 11-Oct-09, at 4:11 PM, Kyle Sluder wrote: On Oct 11, 2009, at 1:06 PM, Ben Haller bhcocoa...@sticksoftware.com wrote: Yes, but my code also needs to compile as GC-unsupported against the 10.4 SDK, where any GC-specific calls that I might need to make will not compile. Am I missing something? Do you really need to compile against the 10.4 SDK? Why not compile against the 10.6 SDK with a 10.4 deployment target? I frankly don't know. I'm following the instructions I found telling me what build settings would result in a screensaver that would run on 10.4 through 10.6, ppc and intel: http://www.eisbox.net/2009/09/01/2402-distributing-a-screen-saver-for-10-4-10-5-and-10-6/ I saw similar instructions on several other web pages. I've got my screensaver successfully compiling and running for everything except 10.6, so I'm loath to go back and mess around with this stuff now. I presume the author had a good reason for specifying the 10.4 SDK and GCC 4.0 for the older archs. Perhaps the 10.6 SDK is not supported for PPC builds, or something? I have no idea. I'm very new to all this (I've been away from Cocoa programming for about five years), and I'm finding the learning curve to be a bit steep. If you don't need the NS/CFMakeCollectable or other GC-specific functions (which most usually don't) then it's a moot point. Well, I imagine I'm going to need to use *something* GC-specific -- strong/weak declarations, finalize methods, whatever. At present my screensaver crashes on 10.6 when compiled with GC-supported set. That is presumably because some object is getting collected prematurely. I'll need to make some change to the code to fix that, and that change may not be compatible with the non-GC builds, since it will use APIs or Objective-C 2.0 syntax that is not available when building for 10.4 PPC. This is a large project (for a screensaver), with many classes, and runs multithreaded. The idea that I can make it compile both GC- unsupported and GC-supported without a single #if seems unlikely. I may well be completely misunderstanding something; but having read through the Garbage Collection Programming Guide several times now, I don't see any particular reason to think that I won't need GC-specific calls. They certainly give lots of examples of cases in which one does. Sorry if I'm just being clueless, but I'm trying hard to get a clue. :- Ben Haller Stick Software ___ 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: Screensaver won't run on 10.6 even after porting to 64-bit
On 11-Oct-09, at 5:28 PM, Clark Cox wrote: On Sun, Oct 11, 2009 at 1:55 PM, Ben Haller bhcocoa...@sticksoftware.com wrote: Well, I imagine I'm going to need to use *something* GC-specific -- strong/weak declarations, Not likely. finalize methods, whatever. Implementing finalize methods are actually quite rare; and even if you do implement them, that won't prevent building for/running on 10.4. I see that -finalize was available on 10.4 even though GC didn't arrive until 10.5, so I would be able to call [super finalize]. I guess Apple was planning ahead. :- It's exceedingly unlike that whatever change you need to make will render the code incompatible with 10.4. ... Perfectly understandable. I'm just trying to assure you that the cases in which you actually have to call GC-specific API is quite small, and are usually relegated to edge-cases. OK. Well, I guess I'll wait and see what changes I need to make to support GC before I worry about this further. (See the post I'm about to send in. :- ) Thanks! Ben Haller Stick Software ___ 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} Exception After Creating First Object
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
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
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
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 (Cocoa-dev
Re: CoreData async fetch request
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
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: Address Book-style editing
Brad: My app, SousChef, does this. The way adress book and SousChef do it is to use a customized textview. You add custom attributes to mark the different fields (textview's NSTextStorage is a subclass of NSAttributedString). Then you control selection based on these attributes when in edit mode. When a field is selected, you just draw a editing box + drop shadow around the full range of the field. To get the plus/minus buttons (which I'm actually kind of thinking about removing from SousChef), you can stick them in a customized rulerview as markers and show/hide the ruler based on editing mode. Hope this helps, -Ben On Oct 1, 2009, at 1:21 PM, Brad Gibbs wrote: Hi, I'm trying to re-create Address Book's editing style - if a user pushes a button labeled Edit, subsequent clicks on a label bring up what looks like a separate view for the new information. Clicking return after editing commits the edit and moves on to the next field. I'd also like to be able to have the plus and minus signs next to phone numbers, email fields, etc. I don't see a stock Cocoa / AppKit way to do this. Does anyone know of a public framework that mimics this behavior? Short of that, any ideas on how to re-create the editing field that pops up? Thanks. Brad ___ 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/blachman%40mac.com This email sent to blach...@mac.com -- Ben Lachman Acacia Tree Software http://acaciatreesoftware.com email: blach...@mac.com twitter: @benlachman mobile: 740.590.0009 -- Ben Lachman Acacia Tree Software http://acaciatreesoftware.com email: blach...@mac.com twitter: @benlachman mobile: 740.590.0009 ___ 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
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...
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)
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)
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)
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)
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
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!
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
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
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
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
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
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
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
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: Custom Fonts in UI Webview
On Sep 15, 2009, at 10:08 PM, Alex Curylo wrote: On 15-Sep-09, at 6:57 PM, cocoa-dev-requ...@lists.apple.com wrote: You can do custom fonts on the iPhone, but you cannot use system controls to draw with them. You have to draw yourself each glyph. Sure you can. It's just tricky. http://www.alexcurylo.com/blog/2009/05/29/custom-fonts/ I had seen some hints at this in my searching, and this looks to be quite a nice implementation and should make using custom fonts fairly straight forward. However, my original question was regarding web views and whether there was a way to include custom fonts in the application bundle and then access them for use in a UIWebView. Best, -Ben -- Ben Lachman Acacia Tree Software http://acaciatreesoftware.com email: blach...@mac.com twitter: @benlachman mobile: 740.590.0009 ___ 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
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
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: Custom Fonts in UI Webview
On Sep 14, 2009, at 6:08 PM, Jens Alfke wrote: On Sep 14, 2009, at 2:43 PM, Ben Lachman wrote: I was looking at the NYTimes iPhone app today and noticing that it looks like they're using a UIWebView with a custom font (not sure what font though, anyone know?). I did some digging on how to do this and couldn't come up with anything except one bit about @font- face being deprecated on MobileSafari. I saw a lot of references to using Cufón (or similar), however that doesn't allow for copying or selection and the NYTimes app does. anyone know of a way to use a real custom font face in a UIWebView? Embed the font file in your app. IIRC there is a special Info.plist key that points to a subdirectory containing font files, which will automatically be enabled. See the docs on Info.plist keys. Then you don't need to use @font-face, you can just reference the font name in your stylesheet. After some looking, I think you're talking about ATSApplicationFontsPath. Unfortunately although it shows up in the iPhone docs, it state that it only works on Mac OS X. I'm working on iPhone so this really doesn't help much. However, I also found after checking the NYTimes app again that they're actually using Georgia for their font face, not anything custom. -Ben -- Ben Lachman Acacia Tree Software http://acaciatreesoftware.com email: blach...@mac.com twitter: @benlachman mobile: 740.590.0009 ___ 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
Custom Fonts in UI Webview
Hey all. I was looking at the NYTimes iPhone app today and noticing that it looks like they're using a UIWebView with a custom font (not sure what font though, anyone know?). I did some digging on how to do this and couldn't come up with anything except one bit about @font-face being deprecated on MobileSafari. I saw a lot of references to using Cufón (or similar), however that doesn't allow for copying or selection and the NYTimes app does. anyone know of a way to use a real custom font face in a UIWebView? Thanks, -Ben -- Ben Lachman Acacia Tree Software http://acaciatreesoftware.com email: blach...@mac.com twitter: @benlachman mobile: 740.590.0009 ___ 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
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)
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
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?
property in the other direction? What's the predicate there, planetOfOriginName LIKE [c] $FETCH_SOURCE.name? Now your Planet entity has intimate knowledge of the structure of your Employee entity; that can't be good. If this were a join you coded yourself in SQL, the Planet table would effectively know which column matched in the Employee table. Also, if you do in code or fetched properties, this hand made cross store relationship, you should prefer numeric keys to text strings for your joins. Creating a de facto join through a LIKE query is pretty crazy. That's a case insensitive, local aware, Unicode regex there. String operations are much more expensive than integer comparisons. At the very least, use == for your string compares. Of that's true for any database. It seems to me that Core Data really is intended to deal with lists of root objects, i.e. the entire list of Employees in one store, rather than one Employee per store. One document per Employee is a bit unusual. But it's feasible if that's your requirement. The Core Data documentation mentions attaching multiple stores to a persistent store coordinator, but I can't make any sense of how interrelationships between the stores are handled. The old fashioned way. Is Core Data really more appropriate to my dataset than an SQLite database and a simple Employee object that fetches from that database? If so, I'd appreciate some help in understanding how. Are you comparing apples to apples here ? Using multiple SQLite database files directly will open you up to nearly all the same problems you're describing for Core Data. If you're not going to use multiple SQLite database files without Core Data, why would you with Core Data ? (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. - 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?
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?
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
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?
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
Garbage collection and about windows
Hi all. I'm just getting into my first garbage collected Cocoa project, and I'm a bit mystified by the behavior I'm seeing. I'm just trying to make a custom about panel. I put this method in my application delegate: - (IBAction)orderFrontAboutPanel:(id)sender { if (!aboutController) aboutController = [[AKAboutPanelController alloc] initWithWindowNibName:@AKSplash]; [aboutController showWindow:nil]; } I put this declaration of aboutController in my app delegate header: __weak AKAboutPanelController *aboutController; And then I implemented AKAboutPanelController like so: @interface AKAboutPanelController : NSWindowController { } @end @implementation AKAboutPanelController - (void)finalize { NSLog(@AKAboutPanelController finalize); [super finalize]; } @end My idea — perhaps being too clever for my own good — was that as long as the about window was open, the window would be referenced by the window list, and so the window and its controller would stick around. Choosing the About menu item a second time would therefore just call showWindow: on the controller again, ordering the window to the front if it had gotten buried. As soon as the window was closed, I figured it and its controller would be garbage collected, and the weak reference to it in the app delegate would zero out, so then choosing About would create a new controller and reload the nib. But this is not what happened. Instead, the about window sticks around for as long as it is the key window (presumably the window is strong-referenced by AppKit or somebody at a lower level than the Kit). As soon as it is not the key window (click on a different window in the app) it gets garbage collected immediately, even though it is still open! Now maybe this is intended behavior, but it sure isn't what I expected; it seemed intuitive to me that an open window, visible to the user, would not be garbage collected. Is there a reason that the window list uses weak references for visible windows? So. I can think of any number of ways to fix this, of course, but they all seem a little bit gross since they involve either tweaking the garbage collector (CFRetain, for example) or making the reference to the window controller in the app delegate strong, in which it doesn't automatically zero and I have to set up a way for the windowcontroller to tell the app delegate that it's no longer needed. There must be a better pattern; I imagine I'm just not used to thinking in garbage-collection terms yet. So what's the right way to do this? Thanks... Ben Haller Stick Software ___ 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
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
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
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?
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
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
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
re: core-data app design question
I have a question, or rather, I'm looking for advice, on the design of an application. Essentially I'm wanting to write a labbook-type application. My plan was to use core-data for the model. In the model will be an Entry entity. Each entry will have a one-to-one relationship to a Content entity. The Content entity will just (at the moment) contain a single attribute (data) which will be binary data. Implementing this on the Mac I planned to use NSTextView to provide a rich-text entry for the data attribute. Now comes the problem. I want to make a Cocoa Touch version of the app, and make then synchronize over Mobile me. The problem is I see no way to handle the NSAttributedString that will be stored in the data attribute on the iPhone. Does anyone have any advice as to how I might go about this? I was considering dropping back to plain text, but am loath to do this. Well, since you can't draw NSAttributedStrings on the iPhone, there isn't much point in archiving your data that way. You should use a platform neutral text run. You can write your own, which isn't hard for basic attributes, or you can use HTML instead, which you can draw on both platforms easily. Encoding your data this way is pushing the boundaries of violating MVC patterns by archiving UI information (NSTextView drawing information) into your model (database). That obviously doesn't work if the platform doesn't support NSTextView. - 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 observer exception in 10.6
In a Core Data-based app that works fine in 10.5.x, I now get an exception as follows in 10.6 when opening a document. It targets 10.5, and the same exception occurs when rebuilding on 10.6 (still targeting 10.5, but also when targeting 10.6). I don't register or unregister any observers myself, and the exception occurs without touching any of my code. What's going on? NSRangeException: Cannot remove an observer NSKeyValueObservance 0x15476c0 for the key path richText from TextEntity 0x1546380 because it is not registered as an observer. 1 +[NSException raise:format:arguments:] (in CoreFoundation) + 136 2 +[NSException raise:format:] (in CoreFoundation) + 58 3 -[NSObject(NSKeyValueObserverRegistration) _removeObserver:forProperty:] (in Foundation) + 765 4 -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:] (in Foundation) + 176 5 -[NSKeyValueNestedProperty object:didRemoveObservance:recurse:] (in Foundation) + 544 6 -[NSObject(NSKeyValueObserverRegistration) _removeObserver:forProperty:] (in Foundation) + 453 7 -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:] (in Foundation) + 176 8 -[_NSModelObservingTracker _registerOrUnregister:observerNotificationsForModelObject:] (in AppKit) + 228 9 -[_NSModelObservingTracker clearAllModelObjectObserving] (in AppKit) + 341 10 -[_NSModelObservingTracker setIndexReferenceModelObjectArray:clearAllModelObjectObserving:] (in AppKit) + 51 11 -[NSArrayController _setObjects:] (in AppKit) + 196 12 -[NSArrayController _arrangeObjectsWithSelectedObjects:avoidsEmptySelection:operationsMask:useBasis :] (in AppKit) + 510 13 -[NSArrayController rearrangeObjects] (in AppKit) + 133 14 -[NSArrayController observeValueForKeyPath:ofObject:change:context:] (in AppKit) + 338 15 NSKeyValueDidChange (in Foundation) + 377 16 -[NSObject(NSKeyValueObservingPrivate) _didChangeValuesForKeys:] (in Foundation) + 565 17 _PFFaultHandlerFulfillFault (in CoreData) + 1921 18 _PFFaultHandlerLookupRow (in CoreData) + 1573 19 -[NSFaultHandler fulfillFault:withContext:] (in CoreData) + 39 20 _PF_FulfillDeferredFault (in CoreData) + 193 21 _sharedIMPL_pvfk_core (in CoreData) + 65 22 -[NSManagedObject(_PFDynamicAccessorsAndPropertySupport) _genericValueForKey:withIndex:flags:] (in CoreData) + 79 23 -[NSManagedObject valueForKey:] (in CoreData) + 244 24 -[NSKeyValueNestedProperty object:didAddObservance:recurse:] (in Foundation) + 240 25 -[NSObject(NSKeyValueObserverRegistration) _addObserver:forProperty:options:context:] (in Foundation) + 812 26 -[NSObject(NSKeyValueObserverRegistration) addObserver:forKeyPath:options:context:] (in Foundation) + 565 27 -[_NSModelObservingTracker _registerOrUnregister:observerNotificationsForKeyPath:ofModelObject:] (in AppKit) + 134 28 -[_NSModelObservingTracker _registerOrUnregister:observerNotificationsForModelObject:] (in AppKit) + 228 29 -[_NSModelObservingTracker _startObservingModelObject:] (in AppKit) + 418 30 -[_NSModelObservingTracker startObservingModelObjectsAtReferenceIndexes:] (in AppKit) + 333 31 -[NSArrayController _arrangeObjectsWithSelectedObjects:avoidsEmptySelection:operationsMask:useBasis :] (in AppKit) + 510 32 -[NSArrayController setContent:] (in AppKit) + 889 33 -[NSArrayController(NSManagedController) _performFetchWithRequest:merge:error:] (in AppKit) + 501 34 -[NSObjectController(NSManagedController) fetchWithRequest:merge:error:] (in AppKit) + 209 35 -[NSObjectController(NSManagedController) _executeFetch:didCommitSuccessfully:actionSender:] (in AppKit) + 106 36 _NSSendCommitEditingSelector (in AppKit) + 339 37 -[NSController _controllerEditor:didCommit:contextInfo:] (in AppKit) + 216 38 __invoking___ (in CoreFoundation) + 29 39 -[NSInvocation invoke] (in CoreFoundation) + 136 40 -[NSInvocation invokeWithTarget:] (in CoreFoundation) + 72 41 __NSFireDelayedPerform (in Foundation) + 537 42 __CFRunLoopRun (in CoreFoundation) + 6846 Hard to say without more details, but it does look like a Cocoa Bindings bug. If you could create a new sample project with your NIB and your model and reproduce this, and then attach it to a bug report, that would be extremely helpful. Thanks, - 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: Using to-may relationships in fetch request predicates
in the typical CoreData example, if I want to fetch all departments whose employees have a salary higher than a specified value, I will perform a fetch on the Department entity using a predicate with the following format: ANY employees.salary %@ This is working fine. Now I want to fetch all departments whose employees fulfill the salary condition AND are born after a certain date. I would expect something like this to work: ANY (employees.salary %@ AND employees.dateOfBirth %@ But it doesn't. Does anybody know if there is a way to use the ANY statement with more than one condition? You'll need to use a SUBQUERY predicate instead of an ANY/operator. Probably easiest to do SUBQUERY(..)@count 0 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
Auto complete accepts on space, any way to change?
My app, SousChef, uses the AppKit autocomplete functionality in a bunch of places. Currently if a user types So they are presented with a list of completions and the first actual completion (Soup) is used inline and selected so that this completed part is used if the user tabs to the next item but isn't if the user keeps typing (e.g. up is selected, So is not). However in recently we've noticed that if you are typing through an autocomplete and hit space, the current completion is accepted and the space is appended to it. This is unwanted behavior. However in Safari's location bar, which has the functionality I want, if you hit space, the space is appended to the partial word instead of the full completion. Anyone have an idea of how to get this behavior of just accepting on enter/tab (cancel on escape already works)? Currently I'm only implementing - textView:completionsForPartialWordRange:indexOfSelectedItem:. I thought to override keyDown: but the problem is that the field editor is eating keystrokes. Thanks, -Ben -- Ben Lachman Acacia Tree Software http://acaciatreesoftware.com email: blach...@mac.com twitter: @benlachman mobile: 740.590.0009 ___ 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
On Aug 25, 2009, at 7:19 AM, Ruotger Skupin wrote: Am 24.08.2009 um 23:13 schrieb Ben Trumbull: When I use setRelationshipKeyPathsForPrefetching the fetch throws: -[NSSQLAttribute inverseRelationship]: unrecognized selector sent to instance 0x10ee150 Can you provide the entire stack trace at this point ? gdb use future-break objc_exception_throw Thanks. What is the actual set of keypaths you set in the fetch request ? setRelationshipKeyPathsForPrefetching expects all the keypaths to terminate in a relationship object, not the attribute off that related object. (this is 10A432) For the record: I do use one-way relationships That should be okay as long as you're not pretending to use a no inverse to-many relationship as a de facto many to many relationship. No inverse relationships can only behave as if the inverse were to-one. Specifically, each row in the destination entity may only be associated with a single row in the source entity if the relationship on the source entity does not have an inverse. (e.g. you only get join tables in fully modeled bi- directional relationships) Do I understand that correctly? No two (or more) Accounts or Transactions should point to the same Amount (see simplified schema). Unless there's a bug somewhere that's not the case. Correct. For each separate modeled no inverse relationship, the destination row (Amount) can only be pointed to by one source row. |-| | Transaction | |-| || |net | -- | Amount | -- (one other entity) |gross| -- || |fee | -- |value | - |account | - |currency|| |... ||||| |-|| | | | -- | | | ||| | || Account| | ||| | ||balances| -- -- |transactions| |... | || So basically I use Amount only as a container for a currency descriptor and a value. I would have to model 7 inverse relationships on that entity to make all relationships two-way. Hmm. I'd recommend consider whether or not it makes sense to de- normalize Amount into Transaction instead of making it a separate entity. I assume the net/gross/fee are all going to be in the same currency, yes ? Amount is very fine grained, and not (apparently) offering very much value for the abstraction cost. 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. - 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 dog-slow when using first time after boot
On Aug 24, 2009, at 3:20 AM, Ruotger Skupin wrote: Am 20.08.2009 um 22:28 schrieb Ben Trumbull: setRelationshipKeyPathsForPrefetching When I use setRelationshipKeyPathsForPrefetching the fetch throws: -[NSSQLAttribute inverseRelationship]: unrecognized selector sent to instance 0x10ee150 Can you provide the entire stack trace at this point ? gdb use future- break objc_exception_throw For the record: I do use one-way relationships That should be okay as long as you're not pretending to use a no inverse to-many relationship as a de facto many to many relationship. No inverse relationships can only behave as if the inverse were to- one. Specifically, each row in the destination entity may only be associated with a single row in the source entity if the relationship on the source entity does not have an inverse. (e.g. you only get join tables in fully modeled bi-directional relationships) 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. - 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: Using Core Data NSManagedObject subclasses outside of a managed object context
I have objects that I use with core data that were automatically generated for me by xcode and represent entities in my data store. They all subclass NSManagedObject, and do not have instance variables, but instead use the @dynamic setting for their properties, pretty standard. My understanding is that this allows the NSManagedObject superclass to generate the getters/setters at runtime and store data in it's own, more efficient, Core Data friendly way. yup What this means for me, however, is that I can't just call [[Entity alloc] init] and then get/set Entity's properties, because it won't properly initialize unless it is given a managed object context. I need to be able to use my objects in places that they won't be persisted, as just transient objects, but this prevents that. The only way I know to initialize them is by calling [NSEntityDescription insertNewObjectForEntityForName:name inManagedObjectContext:managedObjectContext] . But, when creating objects this way, they will be persisted on the next save call. There's no requirement that you put them in the same NSManagedObjectContext that you call save: on. You can just create a second transient MOC. Alternatively, you can add an in-memory store to your NSPersistentStoreCoordinator and assign the newly inserted objects to that store with -assignObject:toPersistentStore: and then they'll get saved to an in memory backing store. This is probably easier to manage, and definitely provides more features than the second MOC approach. It does do a touch more work, though. Just so you know, I'm making a feed reader that has the option to save selected stories from the feed for later, offline, browsing. I want to be able to download the feed XML and create 'story' objects from that without having to persist every story I fetch. Regardless of approach, you'll need to copy the transient objects into new persistent objects to individually change their nature from transient to normal managed objects. - 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: When do I need to override hash?
On Aug 20, 2009, at 9:09 PM, Jeff Laing wrote: If you need to know whether or not another object has put your object into an NSDictionary, you're probably doing something wrong. Do you have a specific concern about Core Data using your objects ? No, I guess the point I was trying to make was that this discussion seemed to have touched on if you put your objects into an NSSet then you'll need to be more careful about the implementation of - hash, etc. I was trying to point out that just because my application code doesn't go anywhere near NSSet, its conceivable (to me) that Core Data (for example) might be storing dirty objects in an NSSet behind your back. So you can't not implement -hash, etc properly and hope everything will work. There may be any number of external technologies (Core Data was just an example) that may be using your objects in ways you aren't expecting, and there's no future-proof way you can cut corners. There really isn't any point in cutting corners here. If you need to do something unusual, you can use a CFDictionary with custom callbacks. - 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