Dev:Preferences specifier plist

This document provides the specification of the .plist files that specify the layout of an iOS preference pane.

Root level
The root level of the plist may contain these keys:

Specifier Keys and Values
You can use any keys that your controller recognizes in the plist for further customization.

General to-do: Add explanations of each specifier and potentially a screenshot of it (gif for the spinner?).

Cell types
Must be one of the following:
 * PSButtonCell
 * PSEditTextCell
 * PSEditTextViewCell
 * PSGiantIconCell
 * PSGiantCell
 * PSGroupCell
 * PSLinkCell
 * PSLinkListCell
 * PSListItemCell
 * PSSecureEditTextCell
 * PSSegmentCell
 * PSSliderCell
 * PSSpinnerCell
 * PSStaticTextCell
 * PSSwitchCell
 * PSTitleValueCell

The cell type is determined from the class method.

General keys
Keys apply to all cells unless otherwise stated in their respective subsection.

PSButtonCell
The confirmation value is a dictionary containing the following fields:

''To do: confirm this last table. Tests suggest "prompt" is the title, "title" is the okTitle, "okTitle" is MIA, cancelTitle works as stated. Investigate history of "isDestructive" key.''

PSEditTextCell & PSSecureEditTextCell
''To do: Check "prompt", "okTitle" and "cancelTitle" as they appear to not work on iOS 6. Are these in the correct place? Check what "suffix" does. Find "bestGuess" selector signature. Solve the mystery of "isEmailAddressing".''

PSEditTextViewCell
This specifier doesn't show a label so it is recommended to use a previous specifier to indicate what this slider represents.

The text area expands to fit the whole cell, so setting a height key will provide more space to write.

PSGiantIconCell
The font in this cell is bigger than normal.

To do: Find out the actual font and icon sizes.

PSGiantCell
This specifier doesn't show a label so it is recommended to use a specifier before this one to indicate what this specifier represents.

PSGroupCell
If you want to make a Image Header read this.

To do: Research "isStaticText" interaction with "PSStaticTextCell".

PSLinkCell
This specifier is useful for loading extra resources and custom code.

If none of these keys are specified, the framework will try to load a plist using the label text as name.

PSLinkListCell & PSSegmentCell
valuesDataSource and titlesDataSource are performed on the target sent from. They must return an NSArray containing the values and (localized) titles respectively. Their signatures should be

In order to make a PSLinkListCell actually work like a list, you must supply the key-value pair detail = PSListItemsController;

To do: Find out how "shortTitles" work.

PSSliderCell
This specifier doesn't show a label so it is recommended to use a previous specifier to indicate what this specifier represents.

Images must reside in the same directory. They can be symlinks to files elsewhere though.

PSSpinnerCell
PSSpinnerCell is a simple cell with an animating spinner (UIActivityIndicatorView) inside it. Available only in iOS 7 (or higher)[citation needed]. There is no way to start or stop the animation manually, it is always running. Therefore, this cell is meant to be dynamically inserted and deleted from a PSListController subclass.

PSSwitchCell
You can dynamically set the UISwitch's state by returning YES or NO in the get method. When the switch's state changes, the set method is called.

Switch issues on iOS 7
Since iOS 7.0 and above the "alternateColors" key does not work. To be able to change the color of a switch, you must subclass PSSwitchTableCell in a PreferenceBundle as follows:

Then set this key-value pair for the specifier: cellClass = SRSwitchTableCell;

A detailed tutorial about this has been written on sharedroutine.com.

PSTitleValueCell
This specifier makes use of the get key to get the value in the runtime.

Miscellaneous
To do: check which specifiers support this key.

PSSpecifier runtime properties of plist keys
The table above only shows the keys recognized by SpecifiersForPlist when translating the plist into an array of PSSpecifiers. They may correspond to the actual properties of the specifier. If you would like to generate a PSSpecifier in runtime, some actions may differ:

Recipes
Use the following snippet to create a PSSpecifier in the runtime:

Using @selector(setPreferenceValue:specifier:) as setter and @selector(readPreferenceValue:) as getter will ease the load on the work as the specifier will use its properties to make itself work, namely "defaults", "key", "default", "PostNotification".

PSButtonCell
The red delete button in VPN is in fact very easy to implement. All you need to do is add the following code:

And add the following key-value pair to the button specifier: cellClass = PSDeleteTableCell;

Note that  no longer exists as of iOS 6.0. It appears to be replaced by a boolean on PSButtonCell,.

PSLinkCell
PSLinkCell is useful for linking to sub-preference-panes. The simplest example just needs 2 keys:

{ 	cell = PSLinkCell; label = "Settings-iPhone"; }

The label is the important part. When user clicked on the link cell, iPhoneOS will use the unlocalized label as the file name of the plist for the next pane. In the example above, the main settings screen will appear.

If you use just 2 keys, only plists inside can be loaded. In order to load your own plist, you must use a custom subclass of PSListController in detail: { 	cell  = PSLinkCell; label = "My Awesome Pane"; detail = MyListController; }

MyListController can simply be an empty subclass of PSListController:

The key thing is when you place MyListController inside your bundle, its bundle property will return your bundle which My Awesome Pane.plist can be found.

PSTitleValueCell
To display a value like, add the cell to your plist:

{ 	cell = PSTitleValueCell; label = Version; get = "valueForSpecifier:"; }

And add the getter method to your controller:

Custom cells
Making a custom cell, header or footer is useful because it allows you to customize the style, add an image, etc.

All you need to do is make a class that looks like:

Then, set the,   or   in your specifier. For example: ... { 	cell = PSGroupCell; footerCellClass = CustomCell; }, ... A  doesn't have to be specified for custom cells.

Constructing a PSLinkCell at runtime
If you want to dynamically add a specifier for a PSLinkCell that lazy-loads a bundle, you can do it like this:

Making an editable PSListController
With this you can perform a "swipe-to-delete" on the rows.

You just have to use a subclass of  (which is a subclass of  ) for your List Controller. For example:

Please note, you will only be able to delete a specifier, if it's class is either,   or

To perform a custom action when the specifier gets deleted, you have to implement a method in your PSEditableListController subclass like this:

and set the deletionAction Key of the specifier:

Custom Settings Libraries

 * https://github.com/mlnlover11/SettingsKit/wiki
 * https://github.com/hbang/libhbangcommon/tree/master/prefs
 * https://ibraveheartdev.co/PrefUp