After manually creating NSTableView columns, I have called
[self.tableView setAutosaveName:#"MyTable"] and [self.tableView setAutosaveTableColumns:YES]
Ok, it works.
After closing the App I have a file ~/Library/Preferences/MyApp.plist and it has my table settings.
I delete this file and relaunch App and I have seen changed position and size of columns. Not default!
I have tried find where this settings were stored but nothing.
Help me please!
There's a server process, cfprefsd, that caches and serves the user defaults. Apps communicate with that. They don't directly access the file. It has never been reliable to directly manipulate the file as a means of changing the defaults.
To manipulate the user defaults, you must either use the CFPreferences or NSUserDefaults APIs programmatically or, from a command line, use the defaults program. For example:
defaults delete com.yourdomain.yourapp
Related
I am playing around with the new UI testing introduced in Xcode 7 beta. In one of my UI testing scenarios, I need to add some code that does the same thing as clicking Simulator -> Reset Content and Settings in the setup() of my test file, which is a XCTestCase. Can the reset be done programmatically? Or, can we mimic the effect of a factory reset on an app in test code?
Not entirely programmatically, but you can always write a bash file to delete:
${user.home}/Library/Application Support/iPhone Simulator/${simulator.version}
That will clear the settings on the simulator.
My understanding is that you won't be able to that from within your app, as apps are sandboxed.
Usually people were using shell scripts or apple scripts. However, using hard reset is absolutely not necessary.
You shouldn't care about data in other apps, you should care only about the data in your app. You can always delete your app data (files, user defaults) in the beginning of your tests. So, why should you do a hard reset?
A better solution is mocking. If your test supposes that, for example, some variable in NSUserDefaults is not set, you don't have to care about the actual value stored there, just mock the method your implementation is using (e.g. objectForKey: and let it return nil.
I have an app where the user should be able to create template settings files, to save and choose from a popup list. These settings will be applied to configure an export of an item.
I just don't know how to best approach the problem of saving and restoring the saved settings.
To add to my problem is the fact that there are many different exporting methods, each with different setting types.
To explain:
User configures the settings they want for export method A, he/she saves these settings and here i want to write them to disk in a plist file.
The the user configures another set of settings for export method B, he/she saves these settings and i want to write these to disk aswell.
I have used NSSharedUsersDefaultsController to bind all interface elements and test bindings, but i don't want to keep all settings in the application plist. Also, I don't know if there is a good way of importing/exporting using that technique when i'm using different subset of settings. If there was a good way of binding to sub-dictionaries then that could work, but I have not been able to make that work.
I could create a Class for each export method and bind the settings to an NSObjectController, and then manually create an import and export method but that felt clunky.
NSDictionaryController and NSArrayController only seem to be made for TableViews and that kind of data display, not single user interface elements, at least from what i've been able to test.
So, is there a good way to create an export/import functionality while still using cocoa bindings, or do i have to create my own methods for that?
Any examples or pointers in the right direction is appreciated.
A simple and suggest way of saving not critical / not secure settings is:
[NSUserDefaults standardUserDefaults]
You can access it like a dictionary with getObject: and setObject:
I want to prevent the user to choose some file types when he opens NSOpenpanel.
what i can do at the moment is preventing him from accessing all the files and allow some but i want to allow all the files except some.
NSOpenpanel*Openpane = [NSOpenpanl openpanel];
[Openpanel setAllowFileTypes(NSArray*)];
but i want the user to choose all the files except files not choose some files out of all the files.
You can set a list of acceptable file types by calling [-NSOpenPanel setAllowedFileTypes:] and passing in an array of allowed file extensions. See the documentation for details:
A file type can be a common file extension, or a UTI. A nil value indicates that any file type can be used. The default value is nil.
If you want to filter out some filenames and not others, I think you can use the NSOpenSavePanelDelegate method -panel:shouldEnableURL:
For NSOpenPanel delegates, asks the delegate whether the specified URL should be enabled in the panel.
Implement a delegate for the panel. NSOpenPanel inherits a delegate property from its superclass NSSavePanel.
In the delegate, implement either:
- (BOOL) panel:(id)sender shouldEnableURL:(NSURL*)url;
or:
- (BOOL) panel:(id)sender validateURL:(NSURL*)url error:(NSError**)outError;
You should use the first one if you can decide whether a given URL should be enabled quickly and efficiently. It will be called frequently. It controls whether or not a given URL is selectable in the panel.
You should use the second one if your decision is slow or requires significant CPU or I/O. It is only called when the user clicks the Open button. That's not the best user experience. It's better to prevent the user from making a bad choice than to let them make a bad choice and reject it at the last moment.
All of that said, it's kind of weird to allow a user to select any kind of file except MP3s. Is there really no other restriction?
I've written an application that can be invoked as a service (by right-clicking a file in Finder and selecting to open it with my application), but there are a couple of unwanted side-effects when doing this.
Example of service target method:
- (void)doSomething:(NSPasteboard *)pboard userData:(NSString *)userData error:(NSString **)error {
NSArray *files = [pboard propertyListForType:NSFilenamesPboardType];
NSLog(#"Selected file(s): %#", files);
[self.anotherWindow makeKeyAndOrderFront:self];
}
1) When the application is launched this way (even if already open in debug mode), I seem unable to access other windows/controls from the doSomething function. The above attempt to show "anotherWindow", for example, produces no errors, but doesn't "do" anything. According to the stack trace, when inspected from -doSomething, all gui components have values 0x0000000000000000 - yet the application is displayed and fully functional. It's only from -doSomething that I cannot reach them. "self" also has a different value when inspected from -doSomething versus -applicationDidFinishLaunching. I'm not sure how or why -doSomething is acquiring a different self/AppDelegate with uninitialized components. Seemingly fixed by [NSApp setServicesProvider:self];
2) I am not clear on how the system decides which copy of the application to launch when the service is invoked, but it usually doesn't pick the one I want. I have a copy in /Debug, a copy in /Release, a copy on my desktop... and if I delete one, it opens the file with another one instead (some sort of fallback-chain?). How do I configure the service (in code or thru .plist) to open a specific version/location of this app? But this is a dev machine. If I release a distributable which installs to /Applications, do I ever really need to worry about this?
1) Double-check your XIB to makes sure that you've got everything hooked up correctly and then try launching the app with a breakpoint set at the NSLog above and verify that self.anotherWindow points at what you want. If, for some reason, the breakpoint isn't firing, trying adding an:
NSLog( #"Window: %#", self.anotherWindow);
To make sure everything is initialized and hooked up
2) The system uses Launch Services to determine which version of the application to launch. Often it is the version most recently added to the system (which will cause the Launch Services database to be modified), but it is possible, depending on how your system is configured, that it won't be the version you expect.
You can manually inquire and modify the launch services database using:
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister
(yeah, really long path). If you use the -dump option, that'll give you all of the data in the system (pipe into a file and search through it to get a better idea what's going on). If you search of the bundle id, you'll see all of the entries for the app. Generally, most recent wins, but you can force a reload (instructions below).
If you just want to force a reload based on a a particular binary, use the -f flag and the path to the application:
..../lsregister -f /Applications/Foo.app
You can also use -u to explicitly unregister something.
Hopefully this will give you an idea what's going on here.
I have a preferences pane that uses the Shared User Defaults Controller, which reading and saving preferences a piece of cake. It seems though that when changes are made to the fields, they aren't immediately saved to the plist fie. This creates a problem when my application needs to re-read the file immediately after the change has been made and the plist still hasn't been updated.
How can I force the preferences pane to update the preferences file immediately?
This will automatically save any change you do right away to disk:
NSUserDefaultsController *controller = [NSUserDefaultsController sharedUserDefaultsController];
[controller setAppliesImmediately:YES];
If you need this only in specific cases, you can also use and save some of the expensive I/O (you really should try to let the cache mechanism cache as much as possible instead of writing everything right away to disk):
NSUserDefaultsController *controller = [NSUserDefaultsController sharedUserDefaultsController];
[controller save:self];
Also, are you sure that you are trying to solve the right problem? You can always get the up to date version of the user defaults by querying NSUserDefaults where you don't need to care about wether the current version is cached in RAM or already written to disk.
Per the docs:
[userDefaults save:self];
or
[userDefaults setAppliesImmediately:YES];