mySettings: A Settings API for the iPhone

NB: Unfortunately I am not able to do any more development on this or any other projects. I am hoping that someone else will take over the project and update it. There is also this similar project.

A lot of iPhone apps have their own settings views similar to the ones in the Settings App on the iPhone home screen. But to my surprise I couldn’t find any general API for it. So I made my own and published it here. It uses a plist configuration file like the one used by the Settings App, with some added options (and some removed ones, but they will hopefully be implemented in the near future).

In a nutshell it takes a plist like this:

plist

and turns it into this:

iPhone

Features

  • Text fields, on/off switch button, integers and time intervals (with maximum/minimum values and custom format string for the integers).
    More options are needed, obviously, like dates and select lists. Feel free to help out if there are other options you would like to see implemented.
  • Titles can be indented.
  • By default the settings themselves are stored in the standard user defaults object ([NSUserDefaults standardUserDefaults]), but you can use any object that supports key-value coding. This enables you to use your model classes directly in the settings view.
  • And if you don’t find blue pyjama stripes exciting, you can of course change the table view background.

And that’s it for the time being. A work in progress, obviously. I would also like to see support for custom table cells and dynamically filling a section with the contents of an array or a dictionary. And localisation. And sliders. And customising fonts and colours. And lots more cool stuff. So if you want to check it out, follow these instructions. And if you make any changes please let me know so I can merge them back into the repository.


68 comments

  1. Pingback: iPhoneKicks.com

  2. I’ve now added support for custom cells. You can just use SettingsCellProtocol and make everything from scratch, or you can subclass SettingsCell which can set up the title label and align and size the value view automatically, leaving the actual content of the value view entirely up to you.

    Like

    • I finally added mySettings to GitHub, using the marvel that is hg-git. It allows me to continue using mercurial, and to push and pull from git repositories. The project on GitHub can be found here. The main place for mySettings will still be on BitBucket, I’m just uploading the code to GitHub to see if it will attract more users and contributors.

      Like

  3. Yes, github seems to be the de facto standard for open source collaboration these days. I chose bitbucket because I’m using Mercurial myself. I’ve never used git and I have no time to learn it, but if there is a relatively simple way to keep a repository on github in sync with a repository on bitbucket I’d be more than happy to put one up there.

    Like

  4. How do you get a text editing cell to scroll up from behind the keyboard? Mine stay right where they are when the keyboard slides up, but yours do the right thing even when the cell being edited is at the bottom of the table. And I can’t see where on earth it is you’re making that happen :(

    Like

  5. Thanks. That’s rather inconvenient if your table is mixed in with other views :(

    But scrolling the target cell to table bottom and moving table bottom to the keyboard top works nicely it seems.

    Like

  6. The ability to dynamically fill a section with the contents of an array has now been added to mySettings. Could be useful for other things than settings.

    Like

  7. I’ve added support for IsSecure:
    – (void) setConfiguration:(NSDictionary *)config {
    if ([[config objectForKey:@"IsSecure"]boolValue] == YES) {
    valuetextfield.secureTextEntry = YES;
    }
    [super setConfiguration:config];
    }

    Like

  8. First, I would like to say that this is a very nice code for generating a settings menu.

    I am, however, having one small issue. I am trying to use this within a tab in a tab bar. When i click on a cell that pushes a view with a picker on it, the bottom of the picker is cut off by the tab bar. How can i reposition the PickerView??

    Like

  9. Hey! You did a good job and saved me a lot of time although it would be good to have some _useful_ documentation. Nevertheless I managed to make it work for me like I need.

    Here are the differences I noticed from the native Settings:

    1. Highlighted color is not white.
    2. You can select Toggle cells and it will give you a pesky blue blink.

    Here are the steps to make your Settings screen really authentic (I’m too busy to get myself deeply into that open-source collaboration):

    1. Go to SettingsCell.m and set highlightedTextColor to [UIColor whiteColor] where appropriate.

    2. Go to ToggleCell.m and set selectionStyle to *None.

    Now nobody will ever find a difference. Hopefully this applies to Eclipse license since I’ve shared my changes. :)

    Thanks again,
    — Alex

    Like

    • Thank you, glad you found it useful. And I completely agree about the need for useful documentation. Much to my own surprise I’m not very good at writing documentation.

      And thanks for the suggestions. This code has to be updated for OS 3.0 anyway, I’m planning to use the new table cell styles so most of the cell layout code can hopefully be removed.

      Like

  10. Hey, this is awesome. Thanks for posting it, I was looking for something like this, as it’s such a pain to hook up these types of UI’s by hand. That said, a few things:

    I added support for sliders, I can submit the code back if you’d like.

    I got this working in my current app, but I’d like to use it for more than just NSDefaults. In fact, I’d like to have several different UI’s constructed in this manner, each with their own object holding the current data. I noticed you can pass in a settings object which has to be KVO complient, but I’m not really sure how I go about creating such a thing. Any help is appreciated!

    Like

    • Thank you. Glad you could use it.

      And good work on the sliders, mySettings definitely needs that. If you use Mercurial you can just send me a patch. If not then just send in the changed files and the revision number of mySettings you downloaded or the date you downloaded it and I’ll add the changes manually.

      The settings object needs to be key-value compliant (KVC). Which means you can use any properties that are not read-only, an NSMutableDictionary will also work.

      Like

  11. Ok, quick update on the slider. My default implementation works just fine, but if you have a bunch of sliders on the page with different labels, they all end up with different sizes. So I think I’m going to add an option to specify the size you require in the plist file. The default behavior will be to use the maximum size available. I’ll send you the files tonight, most likely..

    Also, I was wondering if you had some thoughts on making the system a little more general. As an example, one of my current UI’s features a table view of sliders inside a view with additional UI elements. Using mySettings has a few issues here that I’d like to fix, mainly:

    1. It doesn’t respect size correctly (it always thinks the view your in is the full screen).

    2. I’d like a way to get a callback when any value is changed in the UI, since my UI needs live updating. Is there a good central place to add this? It would be nice if SettingEditorViewController got a ‘valueChanged’ call with the key name when any value is changed. Then I could simply subclass the SettingsEditorViewController and do whatever updating I need when a value is changed..

    3. I also want to add a button control. The cell side of this is no problem, but I’ll need a way to call a selector as stored in the plist. I’m thinking the SettingsEditorViewController could also have a ‘OnButtonPressed’ function which gets the key name to make that easy..

    Thoughts? Do these seem like changes you’d be interested in having in the trunk, or more of my own branch? As you can see, I’m trying to use this for more than just settings UIs – and it’s almost there. I want to turn this into a more generic property editor for class data.

    Like

    • I’m assuming you mean SettingsViewController and not SettingsEditorViewController?

      1. If you are using a table view together with other views, it is best to use a UIViewController and let it create the table view and set the table view’s delegate and data source to a SettingsMetadataSource.

      2. You could add this in the delegate of SettingsMetadataSource. SettingsViewController is really meant for just the standard simple settings views. For anything more advanced you are better off making your own view controller outside of the mySettings.

      3. The easiest is probably to store the selector in the plist as a string, then let the button cell call that selector on the delegate of the SettingsViewController. This delegate is normally the UIViewController I mentioned in point 1.

      If you implement something like this I’d definitely be interested in having it in the trunk. I definitely want to use mySettings for more than settings views, actually I’m already doing that in the app I am working on. Which means that I probably should come up with a better name for the project.

      Like

  12. Oh yeah, one more thing. I’m going to want to be able to push a new KVO object into the UI and have the controls update to the new values without removing and re-creating the UI.

    Like

    • Interesting. You should be able to replace the settings data object in the SettingsMetadataSource and then call reloadData on the table view. I think.

      Like

  13. Yes, I mean SettingsViewController.

    That said, I’m not sure I totally follow. Right now I’m constructing SettingsViewController with a plist and NSMutableDictionary and adding it to a view in my scene (which is loaded from a nib).

    How would I have the ViewController create the SettingsViewController?

    On the second point, is there a function that always gets called when a value is edited in SettingsMetadataSource (which I assume is what you mean by SettingsMetadataController)? It didn’t look like there was. Wouldn’t I have to call it from the valueChanged functions of the cells?

    The third one was just what I was thinking as well.

    Like

    • I meant SettingsMetadataSource yes. Sorry about that.

      If you want something more advanced than just a plain settings view then you are probably better off not using SettingsViewController at all. Just make a subclass of UIViewcontroller and let it create a table view, whatever other views you need and a SettingsMetadataSource object. And set the table view’s delegate and data source to the SettingsMetadataSource object.

      There is a delegate method called whenever the changed values are saved, since SettingsMetadataSource caches the changes and only saves them when told to. But not immediately a value has changed. You could implement something like that in SettingsCell, in its setValue method, just keep in mind that if a table view is so large it is partly outside the screen the cells might be reused and the value of a cell might be set even though that setting hasn’t changed.

      Like

  14. ok, so what I’ve done is to add a UIViewController pointer to SettingsCell, and after a cell is created it gets set to be the UIViewController which is stored by the SettingsMetadataSource. Slider and Toggle both have an valueChanged function, so I’m simply calling the UIViewController’s onValueChanged function there for now.

    However, this will always produce a compiler warning because UIViewController doesn’t necessarily have that function on it. Can I get rid of this warning by creating a @protocol that my ViewController implements (with this function in it)? I’m not extremely familiar with the objective C side of things yet.

    Now, for controls without the valueChanged function (basically, everything else), it would be nice to prevent them from triggering a message every time you scroll and cells get reused. Any ideas on that front?

    Like

  15. Spoke too soon. I got the warning to go away by adding a new delegate class SettingsViewControllerDelegate. This will have the onValueChanged and onButtonPressed functions for you to implement in your controller class if you need that functionality. Both of these functions receive the key so you know which property was changed. Hmm, should I send the new value as well? Might be handy..

    Oh, the slider now has a FixedSize key on it which allows you to set the exact size of the slider, so if you have several in a row they can line up nicely. If not specified, it auto sizes.

    I also got the button working in a remedial way. There are a lot of options on a button, but I think I’ll restrict it to just rounded or custom buttons. I’ll allow you to specify images and text for all of the states, and allow a fixed or automatic sizing for text based buttons. Image based ones will attempt to use the image size.

    I haven’t started on refreshing the data when it changes outside of the controller, but it sounds like that will be pretty straight forward.

    Hopefully I’ll finish this up tomorrow and be able to drop you some code. Then we can talk about any changes it needs before being final.

    BTW, I have a color picker class we could integrate into this if we want color editing support. It’s a real color picker, with spectrum and HSL selection, etc. It needs some more love to be final, but it might be a nice thing to integrate down the line.

    Like

  16. Great work on this! It’s an excellent idea and has great execution.

    I wanted to suggest adding this little bit to SettingsViewController.m:

    – (id)initWithCoder:(NSCoder *)decoder {
    if (self = [super initWithCoder:decoder]) {
    settingsdatasource = [[SettingsMetadataSource alloc] initWithConfigFile:[[NSBundle mainBundle] pathForResource:@”Root” ofType:@”plist”]];
    [self setup];
    }
    return self;
    }

    This allows you to instantiate the view controller using only Interface Builder – just throw a UIViewController in and give it a class of SettingsViewController. This bit of code would just use “root.plist”… it would be great to have an interface builder field to enter in custom plists, but getting into IB plugins is a bit beyond my present desires :-)

    Like

    • Thank you. Glad you liked it.

      This is a good idea, but requiring that it use root.plist is too limiting. To enter the name of the plist in Interface builder would definitely be the best option, but IB plug-ins is beyond my present desires and skills as well I’m afraid. Hopefully someone with more experience in Interface builder can help us out here.

      Like

  17. Hi,

    Thanks for posting this library. Can someone advise me on how I can use the mysettings to get the ns default settings to display within a UITableView contained in a FlipsideView instead of of the view in your sample code? Any help would be appreciated.

    Thanks

    Like

    • Create your uiviewcontroller subclass as normal. Then after you have set up the table view in loadview or viewdidload, set its delegate and data source to an instance of SettingsMetadataSource, initialised with your plist.

      Like

  18. Can you share some sample code to do what you mentioned? I’m a little confused.

    In my FlipSideViewController.h I have defined:
    UITableView *tvSettings;

    In viewDidLoad of FlipSideViewController.m,
    tvSettings = [[UITableView alloc] initWithFrame:CGRectMake(0,44,self.view.bounds.size.width,self.view.bounds.size.height-44)];
    tvSettings.delegate = settingsdatasource;
    tvSettings.dataSource = settingsdatasource;

    [self.view addSubview:tvSettings];

    Like

    • Do you support the slider control (PSSliderSpecifier plist type) in your mysettings api? If so, how can I read and render it in a UITableView?

      Like

  19. I finally got my settings for my app to show. One problem I’m seeing now if I select a multi-value field by clicking on the > button, it just highlights the row, but it doesn’t display them. Any advice on how I can get this working?

    Like

    • FlipsideViewController.m
      #import “FlipsideViewController.h”
      #import “SettingsViewController.h”
      @implementation FlipsideViewController
      @synthesize delegate;
      @synthesize settingsViewController;

      – (void)viewDidLoad {

      [super viewDidLoad];

      self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];

      NSString *plist = [[NSBundle mainBundle] pathForResource:@”Root” ofType:@”plist”];

      myTableOfSettings = [[UITableView alloc] initWithFrame:CGRectMake(0,44,self.view.bounds.size.width,self.view.bounds.size.height-55)];

      myTableOfSettings.delegate = settingsdatasource;
      myTableOfSettings.dataSource = settingsdatasource;

      [self.view addSubview:myTableOfSettings];
      }

      This shows my settings and allows for items like ‘PSToggleSwitchSpecifier’ to work. However, items with ‘PSMultiValueSpecifier’ only highlight and do not go to the selector screen.

      Like

  20. I submitted some classes to add sliders and buttons to mysettings a little while back. Not sure if it’s made it into the trunk yet though..

    Like

    • I’ve been busy finishing the app and the website lately, so I haven’t had a chance to upload the changes yet. I have some changes planned that fit in nicely with Jason’s changes so I thought I’d combine them and upload them together. I’m going away to Ireland tonight, but when I get back in two weeks, and have made sure the release of my app goes well, I will upload the changes.

      Like

  21. Hi Kare, great little library – much appreciated.

    FYI… I’ve made a small change locally so that the settings are saved in [SettingsViewController viewWillDisappear] rather than [SettingsViewController viewDidDisappear].

    The problem was my view, which appears when the settings are closed, looks different depending on the save settings. So having the save done *after* the settings view has disappeared (and my view is displayed) was too late.

    Keep up the great work.

    Cheers, Sheldon.

    Like

  22. >>>>This is a good idea, but requiring that it use root.plist is too limiting. To enter the name of the plist in Interface builder would definitely be the best option, but IB plug-ins is beyond my present desires and skills as well I’m afraid. Hopefully someone with more experience in Interface builder can help us out here.

    Unfortunately that is not possible. I’m using Settings.plist for my purpose though.

    Like

  23. Please, replace SettingsMetadataSource::dealloc with the following code:

    – (void) dealloc {

    [sections release];
    [sectiontitles release];
    [changedsettings release];
    [settings release];
    [super dealloc];
    }

    Making [super dealloc] first lead to EXC_BAD_ACCESS, when used separately.

    Like

  24. Updated. Now see that it is already there. Cool. However I cannot get one thing working. I have a BOOL key, that can be changed in Settings and in some other screens. The screen doesn’t update itself when this value changes, also when I’m trying to regenerate the SettingsMetadataSource in viewWillAppear, I’m starting to get odd exceptions about “not KVO object”, “cannot find key Key”, and so on. Can you help how to implement that? I’m using a custom Settings controller, but for now it fully copies your SettingsViewController.

    Like

    • Ok, after some experiments finally found how to make it update.

      This construction in SettingsViewController will help:

      – (void)viewWillAppear:(BOOL)animated {
      [super viewDidLoad];
      [self.tableView reloadData];
      }

      Now can go to sleep safely. :)

      Like

  25. I know this could be a dumb question, but I have very little experience in Xcode.

    I followed the instructions on how to add mySettings to my project, but how do I use SettingsViewController? I can’t just import it using #import “SettingsViewController.h”…

    Like

  26. Kare,
    It was very odd for me to find out that SettingsEditorViewController lost its striped background. Had to get it back. Doesn’t it make sense to leave it stripe to comply with native Settings?

    Like

    • I can understand that. But there’s only been two updates since then and I don’t think any of them could have any effect on your custom cells. Try it, and if it doesn’t work you can always go back.

      Like

    • That one is there is so the settingseditorviewcontroller uses the same background as the settings view, in case people are using a custom settings view controller to make the settings screens fit in better with their app’s UI.

      Like

  27. Do you think it is a good idea to foreward all files and class with some abbreviation, say, PS*? We should have an easy way to differentiate classes from different packages. SettingsViewController is a very common name for example. If I do it myself, I won’t be able to update easily anymore.

    Like

  28. Then it will be even a better idea to base your changes on my current revision. :) It’s your latest revision + PS* prefix + keyboard type // capitalization type for text-fields + certain types of cells are not selectable imitating native Settings (text-field and toggle-switch for example). Please, tell me where I can send sources to. Or better drop me a mail to my box, I’ll reply with a ZIP with sources.

    Like

  29. Hi, great project!
    I’ve run into an issue – I have my Root.plist file inside a Settings.bundle. mySettings only works if I copy the Root.plist outside the bundle, but I’d prefer to not have to maintain it in two places. Is there something I can modify to tell it to search a different path? thanks

    Like

  30. Thanks for the excellent code!
    Has there been a button cell submitted yet or a sample anywhere of this functionality? It seems like someone could extend your custom cell with a label to respond to touches, or some other simple solution for this. Thanks! Jake

    Like

    • Hi Paolo, and thank you. I’m glad you find mySettings useful.

      Unfortunately I don’t have time at the moment to implement flip view functionality for mySettings, as I am in the beginning of a fairly large project. But it shouldn’t be any different from any other view in a flip view controller.

      Like

  31. I’m having an issue. When I have a setting that uses a MultiValue table, when I go there and select something other than the default and hit back, the row still shows the old value.

    On top of that, if I scroll down, then scroll back, when that row is about to come into view the screen suddenly transitions to the multi value selection for it again. This issue I see the problem in the code (setSelected does this, but should not — it should only be handled on didSelect)

    I have spent a day debugging this. What I’ve found is changedsettings is null when the MultiValue cell is supposed to be setting the new value. So it never gets set.

    Anyone else seeing this?

    Like

    • Found the issue. This needs to be added to SettingsEditorViewController#initWithCell:andDelegate:

      cell.changedsettings = originalcell.changedsettings;

      Also, I had to use a UINavigationControllerDelegate to make sure the SettingsViewController is refreshed when navigated to for changing values like this.

      Very weird, in the default project, this worked. But it doesn’t work in my project. Any clue as to why?

      Like

    • That is weird. I didn’t need to do anything like that in my own iPhone app. But it used its own view controller, instead of SettingsViewController. What did you use?

      Like

  32. I love this product–or at least, I think I do–but I have to say the lack of documentation is a real killer. It’s nearly impossible to figure out what is and what is not possible.

    (I’m not missing anything, am I? I haven’t run across anything that really specs out the features and how to use them.)

    My recommendation: take a break from adding features and write some docs/tutorials. At this point, it’s the biggest stumbling block to adoption.

    Like

  33. Hi

    thanks for the great kit.

    Has anyone managed to get UITableViewStyleGrouped tableview when loading the SettingsViiewController from IB?

    Thanks

    Like

  34. Very nice, this saved a bunch of time.

    I added a “StepValue” to the IntegerPickerView so that if min = 100 and max = 150 and step = 10, the picker would display 100, 110, 120, 130, 140, and 150. Very easy, but I am not sure how to ensure the default value of StepValue is 1.

    Like


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s