Save Core Data models in Xcode 4 - xcode

I want to create a new split view-based iOS project from scratch using the template wizard of Xcode 4.0 (build 4A304a). I ticked the "Use Core Data" checkbox. When I try to save the generated test.xcdatamodeld Core Data model, Xcode says The document "test.xcdatamodel" could not be saved.
How can I save the file? I already checked the file system for the proper permissions, but they seem alright.

Aha - I've been suffering from this problem all day and just found the answer. I ran /Applications/Utilities/Console and tried the save again. This error appeared in the console:
AppKit called rmdir("/Users/kris/.TemporaryItems/folders.501/TemporaryItems/
(A Document Being Saved By Xcode)"), it didn't return 0,
and errno was set to 66.
Though I couldn't see anything obviously wrong with this folder (the permissions & ownership looked normal), removing the whole of ~/.TemporaryItems/ allowed me to save again.

Related

Why does building in Xcode overwrite my SQLite database?

First of all, I'm not using Core Data, I'm using SQLite only.
I save the data in the table and then query them by opening the app and looking at the data using SQLiteStudio. I even create a LOG to check that the data is saved, and yes, it is saved.
But when I STOP and run the simulator again to consult, there is no more data!
Is Xcode overwriting the database every time? Or is something else happening that is outside my limited knowledge?
Without knowing more about how your application is setup, how you've got your app configured to build, or how it operates on the SQLite DB file in question I'll only be able to offer some pointers in things you can go check out about your code and build configuration that may be the source of your phantom deletions. Of course, if you have other info to provide, I'd be happy to edit my answer!
Case 1: 'Create DB' always running?
One thing that may be tripping your app up is what happens leading up to the decision to create a new SQLite DB file or look/open an existing file. If the code creating an empty DB is always running, then each time your app starts, your old DB file is getting overwritten with a blank DB.
Case 2: Using a 'starter' or 'template' empty database?
Sometimes developers may provide a blank database that contains the initial database schema (the general tables and structure) as well as some default or sample data. If your app does this, perhaps the logic leading up to the decision to apply that default database is accidentally always being triggered? If so, use of NSUserDefaults to record a boolean indicating the DB was successfully created may be an avenue to use to skip past the 'Load my starter DB' code. Alternatively, you could check for the existence of your DB file, or see if the contents of a specific table are different from the template data, etc.
Case 3: Different Behavior between 'Build & Run' vs. 'Run Without Building'
There's a not-so-well-known option in the Product > Perform Action menu labelled 'Run without Building' that will essentially kickoff another Debug session using the version of the application you just finished running in the Simulator or on Device. When you use this option do you see any different behavior with your database or is it still blank?
Case 4: Different Behavior when run directly in Simulator outside of an Xcode debugging session?
Part of the 'Run' operation is a build phase which may trigger the 'Copy Resources' phase even if your app hasn't changed since the last execution (as you suggest is the case in your question). If you are providing a stock 'default' or 'template' DB file and your app is simply opening and editing that 'template' during the first execution of your app, then Xcode may be replacing it with a clean copy on the subsequent 'Run' operations where 'Copy Resources' is happening. A way to test this avenue:
Build and Run your app to the simulator using Xcode like normal.
Perform some operations that would result in the creation or editing of data in your app's database.
Click the stop button in Xcode to return to the Simulator home screen.
Double-click the home button on the simulator (or if there is no home button, press CMD+SHIFT+H twice to bring up the multitasking bar and force-quit out of your application.
Check and see if your DB file has data in it.
If no data, then there is an issue persisting your changes into the database and we need to get that problem solved first. Otherwise:
Relaunch your app directly from iOS Simulator and perform different operations that would result in more or different changes to the database.
Click on the home button to return to the iOS Home Screen.
Force-quit your appellation as was done in Step 4.
Check and see if your DB file data has changed (but still has data) or has blanked out.
Finally, make sure you are following Apple's guidance about where to store user-data, if you are inadvertently storing something in an incorrect file path doesn't typically result in blanking of data, it may be prohibiting writing of data which could be interpreted as your data getting overwritten especially if you are interrogating it while it still is residing in an in-memory process. There's some really useful guidance about file paths in the Table 1-1: (http://developer.apple.com/library/ios/#documentation/FileManagement/Conceptual/FileSystemProgrammingGUide/FileSystemOverview/FileSystemOverview.html)
Locating your Simulator App on your Mac's Hard Drive
To be thorough (and you may already know about this!), iOS Simulator applications are stored on your Mac's hard drive just like other files on your machine. Their organization mimics that of a physical iOS device. To get to your App and its data:
Open a new Finder window.
Press CMD+SHIFT+G or choose 'Go to Folder' from the 'Go' menu.
Paste the following into the 'Go to Folder' box then click 'Go': ~/Library/Application Support/iPhone Simulator/
Select the folder that matches the iOS version of the simulator you built to.
Click on Appications.
You'll then be presented with zero or more folders, each folder that appears will have a string of digits separated by hyphens. Navigate through this list until you find the one containing your app. You can then browse, and copy data out of this folder to somewhere to be examined by other tools on your Mac.

Using OSX Security-Scoped Bookmarks in a Firemonkey app

I have been developing an OSX app with Delphi XE3 and running into various problems. The latest one is with the sanboxed version built for the Apple Appstore.
The user has to select an arbitrary folder and the app needs to get access to it. Since there is a problem with the OpenDialog, I had to turn to drag-drop functionality instead.
The user drags a folder to the app, the sandbox gives the app temporary access to it and all works properly.
To preserve the access to this folder when the app is restarted I have to use the so-called "security-scoped bookmarks"
I am having two issues with them:
1) How to add the "com.apple.security.files.bookmarks.app-scope" entitlement to an XE3 firemonkey app? It is not available in the Project Options->Entitlements. If I add it manually in the ".entitlements" file it gets overwritten when the app is built.
So is there a way to add a custom entitlement that is not in the list in the project options?
2) To create the bookmark I should use the NSURL.bookmarkDataWithOptions method. I think it should be used like this, but I am not sure of the exact syntax:
var
URL: NSURL;
Err: NSError;
Data: NSData;
...
URL := TNSURL.Create;
Data := URL.bookmarkDataWithOptions(NSURLBookmarkCreationWithSecurityScope, nil, #Err);
...
Maybe there should be a call to Wrap(...) instead of Create.
I have not yet experimented with it, because it is pointless without the answer to issue 1).
It seems no one has written anything about these problems for Delphi, but I hope someone here has experience with that.
Thanks in advance.
Edit:
For problem 1) I tried to add edit manually the ".entitlements" file in the OSX32 folder and set it to read-only to prevent it from being overwritten. It was too easy to be true of course, because the linker complained that the file can not be modified...
OK, I finally found the way to manually add entitlements that are not available in the Project Options > Entitlements.
Instead of selecting the "App Store" build in the Project Manager you have to select a Normal release build and deploy the application as usual.
The application gets deployed in the PAServer scratch-dir as APP package. Inside this package there is an "Entitlements.plist" file, which is in XML format and can be edited with a text editor. It is quite obvious how to add new entitlements once you open the file.
After it is edited, the app has to be code-signed manually and a package has to be prepared. It is slightly more complicated than using the Delphi IDE, but there are instructions about it on the Embarcadero and Apple websites and it actually went without problems.
Still haven't tried the bookmarkDataWithOptions functions.
An alternative could be to deactivate the checkbox for the entitlements-file in the deployment page.
But attention: Evry time you change between Build/Release or App Store/Normal, delphi activates the checkbox. That means you have to deactivate it again in the deplayment-page, to avoid the transfer of this file to the mac PC.
By the way: Do you have tryed meanwhile the StartAccessingSecurityScopedResource function?
In the MacApi.Foundation unit the function is not declared in the NSURL interface.
Do you have found a way to use this function?

Problems with implementing Versions

I try to implement Versions in application that already written for Snow Leopard. It is an Document based application with SQLite storage. Each document saves as an SQLite db file.
I have implemented appropriate methods in my NSPersistentDocument subclass:
+ (BOOL)autosavesInPlace {return YES;}
+ (BOOL)preservesVersions {return YES;}
Now I have new File menu in application with "Save a Version" etc. I create new document in my app, save it, make some changes, save again.. When I entering version browser I get:
kCGErrorFailure: CGSDisplayID: App trying to enumerate [0 to CGSGetNumberOfDisplays()] instead of using CGSGetDisplayList(). Compensating...
kCGErrorFailure: Set a breakpoint # CGErrorBreakpoint() to catch errors as they are logged.
In right side of version browser in list of versions I see few versions, but they do not displayed in stack of windows. It looks like windows are in stack but completely transparent. When I clicks on any version in list I get log:
CoreData: error: (8) attempt to write a readonly database
Than if I tried to restore one of versions - version browser normally closed, no window appears and program stops responding.
I can't understand what it all can means. Is it problem in saving version or in restoring? I just have no ideas. Will be grateful for any help.
Each Core Data store is already stored on disk when the versions browser is opened. Have you looked at your overrides for creating the document, and for reading them? Are you sure none of them also edit the document? You might also want to check your awakeFromNib methods, to see that you are not writing / saving anything to a new document.
It can be difficult to debug problems when leaving the version browser. To make it easier, you can edit your current scheme, select the 'Options' tab, and check 'Enable debugging in "Browse all versions" mode'.

Core Data template: Data Not Persisted Between Runs

I created a small test Mac app using the Core Data template (on Lion 10.7 and Xcode 4). I used the example on this site, http://www.swampfoetus.net/chapter-7-fail/, to hook up all the Cocoa Bindings with a tableview, an NSArrayController, a text box and an Add button. The NSArrayController is linked to the managedObjectContext of the App Delegate.
Everything seems to work fine when I launch the app ... I can type in text and press Add, and it gets saved in the tableview. I saved a few rows, and then pressed Save in the file menu (linked to the saveAction IBAction) and quit the app. I can see the data being saved in the xml data file (I renamed it .xml ... the PSC is of type NSXMLStoreType).
The problem is that when I launch the app again, it launches without the data that was saved in the Core Data file in the previous run.
This happens each time ... I can add data and it keeps appending to the data file, but at launch it never seems to read from this data file.
Any ideas what could be wrong here? I haven't messed around with the App Delegate generated code at all, only set up the bindings which seem to work fine. What could I check to make sure it's setup correctly?
If the data shows up in the persistent store, then the only explanation would be a problem with the binding where the UI doesn't display the previous data for some reason. It's hard to say why that is happening but my guess would be a fetch predicate or some other bound qualifier that causes the controller to ignore older objects so that they are not displayed.
I can't say for sure because I don't have access to the book.
This is one of the drawbacks of using bindings. When they work, they're fantastic but when they don't, they're a ##%! to debug.

Problem in working with core data

Am using core data framework in my cocoa application,I have created couple of entities and created reference using NSEntityDescription. When i run the application am getting an error saying that "The managed object model version used to open the persistent store is incompatible with the one that was used to create the persistent store."
You need to delete the application from your device / simulator, then build and run again.
This will happen each time you change your model, because the old data store will remain in the apps documents folder, while the classes accessing it have been altered.
In a later stage of development, you will propably want to introduce store migration, sou your testers and users won't have to delete their data each time a new version is released. If your model remains static though, you don't need to migrate the data during future updates.
You might want to take a look at the Core Data Migration Programming Guide for further information.
The answer is a bit tricky but this always works for me. This is for a clean installation of a new compatible .sqlite file, not a migration!
launch simulator, delete the app and the data (the popup after you delete the app).
quit simulator
open X-Code, after making any edits to your data model
delete the {*appname*}.sqlite file (or back it up, remove it from project folder, and delete reference)
clean the app (Product > Clean)
Run the app in a simulator (for this tutorial I will assume 4.2)
While the simulator is running, in a Finder window, navigate to:
{*home*} > Library > Application Support > iPhone Simulator > 4.2 > Applications > {*random identifier*} > Documents > {*appname*}.sqlite
Copy this file to another location
Stop running your app in X-Code
Drag and drop the {appname}.sqlite file into the files list in X-Code.
In the dialog that pops up, make sure the copy to folder checkbox, is checked.
Product > Clean
Then run the app in the simulator again
Now you should have a working sqlite file!
Cheers,
Robert
You must delete the persistent store file from either:
~/Library/$AppName
~/Library/Application Support/$AppName
(Depending on your version of Xcode.)

Resources