Code Monkey home page Code Monkey logo

inappsettingskit's Introduction

InAppSettingsKit

Build Status Version Swift Package Manager compatible Carthage compatible License Platform Sponsor Mastodon

InAppSettingsKit (IASK) is an open source framework to easily add in-app settings to your iOS, Catalyst, or visionOS apps. Normally iOS apps use the Settings.bundle resource to add app-specific settings in the Settings app. InAppSettingsKit takes advantage of the same bundle and allows you to present the same settings screen within your app. So the user has the choice where to change the settings.

IASK not only replicates the feature set of system settings but supports a large number of additional elements and configuration options.

Updating from IASK 2.x? Please read the Release Notes.

How does it work?

To support traditional Settings.app panes, the app must include a Settings.bundle with at least a Root.plist to specify the connection of settings UI elements with NSUserDefaults keys. InAppSettingsKit basically just uses the same Settings.bundle to do its work. This means there's no additional work when you want to include a new settings parameter. It just has to be added to the Settings.bundle and it will appear both in-app and in Settings.app. All settings types like text fields, sliders, toggle elements, child views etc. are supported.

How to include it?

The source code is available on github. There are several ways of installing it:

Using SPM

To install InAppSettingsKit using Swift Package Manager you can follow the tutorial published by Apple using the URL for the InAppSettingsKit repo with the current version:

  1. In Xcode, select “File” → “Add Packages…”
  2. Enter https://github.com/futuretap/InAppSettingsKit.git

Using CocoaPods

Add to your Podfile:

pod 'InAppSettingsKit'

Then run pod install.

Using Carthage

Add to your Cartfile:

github "futuretap/InAppSettingsKit" "master"

App Integration

In order to start using IASK add Settings.bundle to your project (File -> Add File -> Settings bundle) and edit Root.plist with your settings (see Apple's documentation on the Schema File Root Content). Read on to get insight into more advanced uses.

To display InAppSettingsKit, instantiate IASKAppSettingsViewController and push it onto the navigation stack or embed it as the root view controller of a navigation controller.

In code, using Swift:

let appSettingsViewController = IASKAppSettingsViewController()
navigationController.pushViewController(appSettingsViewController, animated: true)

In code, using Swift as part of a swift package:

In a modularized app, you might want to move all settings-related code into a separate package, and only reference the InAppSettingsKit dependency there. Your Package.swift would look like this:

let package = Package(
    name: "SettingsPackage",
    platforms: [.iOS(.v17)],
    dependencies: [
        .package(url: "https://github.com/futuretap/inappsettingskit", from: "3.4.0")
    ],
    .target(
        name: "SettingsPackage",
        dependencies: [
            .product(name: "InAppSettingsKit", package: "inappsettingskit"),
        ],
        resources: [
            .copy("InAppSettings.bundle")
        ]
    )
)

(Note that the InAppSettings.bundle directory is also part of the package, and does not belong to the main app anymore.)

Creating an IASKAppSettingsViewController now requires setting its bundle property to the package's bundle:

struct InAppSettingsView: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> some UIViewController {
        let iask = IASKAppSettingsViewController(style: .insetGrouped)
        iask.bundle = Bundle.module // IMPORTANT
        return iask
    }

    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) { }
}

In code, using Objective-C:

IASKAppSettingsViewController *appSettingsViewController = [[IASKAppSettingsViewController alloc] init];
[self.navigationController pushViewController:appSettingsViewController animated:YES];

Via storyboard:

  • Drag and drop a Table View Controller embedded into a Navigation Controller into your app and wire the storyboard to your app UI
  • Set the Table View Controller class to IASKAppSettingsViewController
  • Set the Table View to "Grouped" style.
  • If you’re presenting the navigation controller modally:
    • In the Table View Controller set "Show Done Button" under "App Settings View Controller" to "On"
    • Set the delegate comforming to IASKAppSettingsViewControllerDelegate.
    • Implement the delegate method -settingsViewControllerDidEnd: and dismiss the view controller.

The sample application shows how to wire everything up.

Additional changes

To customize the behavior, implement IASKSettingsDelegate and set the delegate property of IASKAppSettingsViewController. For advanced customization needs, subclassing of IASKAppSettingsViewController is supported.

Depending on your project it might be needed to make some changes in the startup code of your app. Your app has to be able to reconfigure itself at runtime if the settings are changed by the user. This could be done in a -reconfigure method that is being called from -applicationDidFinishLaunching as well as in the delegate method -settingsViewControllerDidEnd: of IASKAppSettingsViewController.

Goodies

The intention of InAppSettingsKit was to create a 100% imitation of the Settings.app behavior (see the Apple Settings Application Schema Reference). On top of that, we added a ton of bonus features that make IASK much more flexible and dynamic.

Custom inApp plists

Settings plists can be device-dependent: Root~ipad.plist will be used on iPad and Root~iphone.plist on iPhone. If not existent, Root.plist will be used.

InAppSettingsKit adds the possibility to override those standard files by using .inApp.plist instead of .plist. Alternatively, you can create a totally separate bundle named InAppSettings.bundle instead of the usual Settings.bundle. The latter approach is useful if you want to suppress the settings in Settings.app.

This is the complete search order for the plists:

  • InAppSettings.bundle/FILE~DEVICE.inApp.plist
  • InAppSettings.bundle/FILE.inApp.plist
  • InAppSettings.bundle/FILE~DEVICE.plist
  • InAppSettings.bundle/FILE.plist
  • Settings.bundle/FILE~DEVICE.inApp.plist
  • Settings.bundle/FILE.inApp.plist
  • Settings.bundle/FILE~DEVICE.plist
  • Settings.bundle/FILE.plist

Privacy link

If the app includes a usage key for various privacy features such as camera or location access in its Info.plist, IASK displays a "Privacy" cell at the top of the root settings page. This cell opens the system Settings app and displays the settings pane for the app where the user can specify the privacy settings for the app.

If you don't want to show Privacy cells, set the property neverShowPrivacySettings to YES.

The sample app defines NSMicrophoneUsageDescription to let the cell appear. Note that the settings page doesn't show any privacy settings yet because the app doesn't actually access the microphone. Privacy settings only show up in the Settings app after first use of the privacy-protected API.

Open URL

InAppSettingsKit adds a new element IASKOpenURLSpecifier that allows to open a specified URL using an external application (i.e. Safari or Mail). The URL to launch is specified in the File parameter. See the sample Root.inApp.plist for details.

Mail Composer

The custom IASKMailComposeSpecifier element allows to send mail from within the app by opening a mail compose view. You can set the following (optional) parameters using the settings plist: IASKMailComposeToRecipents, IASKMailComposeCcRecipents, IASKMailComposeBccRecipents, IASKMailComposeSubject, IASKMailComposeBody, IASKMailComposeBodyIsHTML. Optionally, you can implement

- (BOOL)settingsViewController:(id<IASKViewController>)settingsViewController shouldPresentMailComposeViewController:(MFMailComposeViewController*)mailComposeViewController forSpecifier:(IASKSpecifier*)specifier;

in your delegate to customize the mail (e.g. pre-fill the body with dynamic content, add attachments) modify the appearance of the compose view controller or even block the standard presentation. An alert is displayed if Email is not configured on the device. IASKSpecifier is the internal model object defining a single settings cell. Important IASKSpecifier properties:

  • key: corresponds to the Key in the Settings plist
  • title: the localized title of settings key
  • type: corresponds to the Type in the Settings plist
  • defaultValue: corresponds to the DefaultValue in the Settings plist

Button

InAppSettingsKit adds a IASKButtonSpecifier element that allows to call a custom action. Just add the following delegate method:

- (void)settingsViewController:(IASKAppSettingsViewController*)sender buttonTappedForSpecifier:(IASKSpecifier*)specifier;

The sender is always an instance of IASKAppSettingsViewController, a UIViewController subclass. So you can access its view property (might be handy to display an action sheet) or push another view controller. Another nifty feature is that the title of IASK buttons can be overriden by the (localizable) value from NSUserDefaults (or any other settings store - see below). This comes in handy for toggle buttons (e.g. Login/Logout). See the sample app for details.

By default, Buttons are aligned centered except if an image is specified (default: left-aligned). The default alignment may be overridden.

Multiline Text View

Similar to standard text fields, IASKTextViewSpecifier displays a full-width, multi line text view that resizes according to the entered text. It also supports KeyboardType, AutocapitalizationType and AutocorrectionType.

Date Picker

IASKDatePickerSpecifier displays a UIDatePicker to set a date and/or time. It supports the following options:

  • DatePickerMode: one of Date, Time, or DateAndTime (see UIDatePickerMode). Default is DateAndTime.
  • DatePickerStyle: one of Compact, Wheels, or Inline (see UIDatePickerStyle). Default is Wheels. Feature requires iOS 14 or higher. If the OS doesn't support it, IASK falls back to Wheels.
  • MinuteInterval: The interval at which the date picker displays minutes. Default: 1.

There are 3 optional delegate methods to customize how to store and display dates and times:

- (NSDate*)settingsViewController:(IASKAppSettingsViewController*)sender dateForSpecifier:(IASKSpecifier*)specifier;

Implement this if you store the date/time in a custom format other than as NSDate object. Called when the user starts editing a date/time by selecting the title cell above the date/time picker.

- (NSString*)settingsViewController:(IASKAppSettingsViewController*)sender datePickerTitleForSpecifier:(IASKSpecifier*)specifier;

Implement this to customize the displayed value in the title cell above the date/time picker.

- (void)settingsViewController:(IASKAppSettingsViewController*)sender setDate:(NSDate*)date forSpecifier:(IASKSpecifier*)specifier;

Implement this if you store the date/time in a custom format other than an NSDate object. Called when the user changes the date/time value using the picker.

List Groups

List groups (IASKListGroupSpecifier) are an IASK-only feature that allow you to manage a variable number of items, including adding and deleting items. Arrays of tags, accounts, names are typical use cases. A list group consists of a variable number of ItemSpecifier items. The number of these items is determined by your actual content in your NSUserDefaults (or your custom settings store). In other words, ItemSpecifier defines the type of cell, whereas the number of cells and their content comes from NSUserDefaults or your store. Cells can be deleted via swipe if the Deletable parameter is set to YES.

Optionally, a list group also has an AddSpecifier that controls the last item of the list group section. It is used to add items and could be a text field, a toggle, a slider, or a child pane. While the first three create a new item after editing is complete, a child pane presents a modal child view controller to configure a complex item, saved as a dictionary. Such child panes work very similarly to normal child panes with a few differences: They are presented not via push but modally and have a Cancel and Done button in the navigation bar. A new item is created by tapping the Done button.

You may want to specify some validation rules that need to be met before enabling the Done button. This can be achieved with the delegate method:

- (BOOL)settingsViewController:childPaneIsValidForSpecifier:contentDictionary:

The Done button is disabled when returning false from this method. Also note that the contentDictionary is a mutable dictionary. If you change some of the values, the UI will reflect that. This allows you to autocorrect invalid settings.

Custom Views

You can specify your own UITableViewCell within InAppSettingsKit by using the type IASKCustomViewSpecifier. A mandatory field in this case is the Key attribute. Also, you have to support the IASKSettingsDelegate protocol and implement these methods:

- (CGFloat)settingsViewController:(UITableViewController<IASKViewController> *)settingsViewController heightForSpecifier:(IASKSpecifier *)specifier;
- (UITableViewCell*)settingsViewController:(UITableViewController<IASKViewController> *)settingsViewController cellForSpecifier:(IASKSpecifier*)specifier;

Both methods are called for all your IASKCustomViewSpecifier entries. To differentiate them, you can access the Key attribute using specifier.key. In the first method you return the height of the cell, in the second method the cell itself. You should use reusable UITableViewCell objects as usual in table view programming. There's an example in the Demo app.

Optionally you can implement

- (void)settingsViewController:(IASKAppSettingsViewController*)settingsViewController

didSelectCustomViewSpecifier:(IASKSpecifier*)specifier;

to catch tap events for your custom view.

If you specify File, IASKViewControllerClass, IASKViewControllerStoryBoardId, or IASKSegueIdentifier (see below), the selection behavior of a custom view is identical to a child pane and the delegate is not called on selection.

Section Headers and Footers

The FooterText key for Group elements is available in system settings. It is supported in InAppSettingsKit as well. On top of that, we support this key for Multi Value elements as well. The footer text is displayed below the table of multi value options.

You can define a custom header view for PSGroupSpecifier segments by adding a Key attribute and implementing the following method in your IASKSettingsDelegate:

- (UIView *)settingsViewController:(id<IASKViewController>)settingsViewController tableView:(UITableView *)tableView viewForHeaderForSection:(NSInteger)section;

You can adjust the height of the header by implementing the following method:

- (CGFloat)settingsViewController:(id<IASKViewController>)settingsViewController tableView:(UITableView*)tableView heightForHeaderForSection:(NSInteger)section;

For simpler header title customization without the need for a custom view, and provided the -settingsViewController:tableView:viewForHeaderForSection: method has not been implemented or returns nil for the section, implement the following method:

- (NSString *)settingsViewController:(id<IASKViewController>)settingsViewController tableView:(UITableView*)tableView titleForHeaderForSection:(NSInteger)section;

If the method returns nil or a 0-length string, the title defined in the .plist will be used.

This behaviour is similar to custom table view cells. When implementing a method and if you need it, the section key can be retrieved from its index conveniently with:

NSString *key = [settingsViewController.settingsReader keyForSection:section];

Check the demo app for a concrete example.

For footer customization, three methods from the IASKSettingsDelegate protocol can be similarly implemented.

Extending Child Panes

Custom ViewControllers

For child pane elements (PSChildPaneSpecifier), Apple requires a file key that specifies the child plist. InAppSettingsKit allow to alternatively specify IASKViewControllerClass and IASKViewControllerSelector. In this case, the child pane is displayed by instantiating a UIViewController subclass of the specified class and initializing it using the init method specified in the IASKViewControllerSelector. The selector must have two arguments: an NSString argument for the file name in the Settings bundle and the IASKSpecifier. The custom view controller is then pushed onto the navigation stack. See the sample app for more details.

Using Custom ViewControllers from StoryBoard

Alternatively specify IASKViewControllerStoryBoardId to initiate a viewcontroller from main storyboard. Specify IASKViewControllerStoryBoardFile to use a storyboard other than the main storyboard from the app’s Info.plist.

Perform Segues

As an alternative to IASKViewControllerClass and IASKViewControllerSelector for child pane elements (PSChildPaneSpecifier), InAppSettingsKit is able to navigate to another view controller, by performing any segue defined in your storyboard. To do so specify the segue identifier in IASKSegueIdentifier.

Extending various specifiers

Subtitles

The IASKSubtitle key allows to define subtitles for these elements: Toggle, ChildPane, OpenURL, MailCompose, Button. Using a subtitle implies left alignment. A child pane displays its value as a subtitle, if available and no IASKSubtitle is specified. The subtitle can be a localizable String or a Dictionary with localizable subtitles depending on the current value. YES and NO are used as keys for boolean toggle values. The dictionary may contain a __default__ key to define a subtitle if no key is matching.

Text alignment

For some element types, a IASKTextAlignment attribute may be added with the following values to override the default alignment:

  • IASKUITextAlignmentLeft (ChildPane, TextField, Buttons, OpenURL, MailCompose)
  • IASKUITextAlignmentCenter (ChildPane, Buttons, OpenURL)
  • IASKUITextAlignmentRight (ChildPane, TextField, Buttons, OpenURL, MailCompose)

Variable font size

By default, the labels in the settings table are displayed in a variable font size, especially handy to squeeze-in long localizations (beware: this might break the look in Settings.app if labels are too long!). To disable this behavior, add a IASKAdjustsFontSizeToFitWidth Boolean attribute with value NO.

Icons

All element types (except sliders which already have a MinimumValueImage) support an icon image on the left side of the cell. You can specify the image name in an optional IASKCellImage attribute. The ".png" or "@2x.png" suffix is automatically appended and will be searched in the project. Optionally, you can add an image with suffix "Highlighted.png" or "[email protected]" to the project and it will be automatically used as a highlight image when the cell is selected (for Buttons and ChildPanes). If the image is not found as a resource in the project, InAppSettingsKit falls back to SF Symbols.

Extending Text Fields

Placeholder

The IASKPlaceholder key allows to define placeholder for TextField and TextView (IASKTextViewSpecifier).

Content Type

To support autofill based on the content type, add the IASKTextContentType key accepting the (prefix-less) constant names of UITextContentType. Example: to configure a text field with UITextContentTypeEmailAddress, use IASKTextContentType: EmailAddress.

Validation

Text fields can be validated using the delegate callback:

- (IASKValidationResult)settingsViewController:(IASKAppSettingsViewController*)settingsViewController validateSpecifier:(IASKSpecifier*)specifier textField:(IASKTextField*)textField previousValue:(nullable NSString*)previousValue replacement:(NSString* _Nonnull __autoreleasing *_Nullable)replacement;

The callback receives the IASKTextField which is a UITextField subclass to allow styling of the text field in case of a validation error (e.g. red text). It contains a replacement out parameter to replace invalid text. Returning IASKValidationResultFailedWithShake lets the text field shake to visually indicate the validation error.

Customizing Toggles

PSToggleSwitchSpecifier switches use a UISwitch by default. By specifying the option IASKToggleStyle: Checkmark, checkmarks are displayed for selected keys.

Dynamic MultiValue Lists

MultiValue lists (PSMultiValueSpecifier) and radio groups (PSRadioGroupSpecifier) can fetch their values and titles dynamically from the delegate instead of the static Plist. Implement these two methods in your IASKSettingsDelegate:

- (NSArray*)settingsViewController:(IASKAppSettingsViewController*)sender valuesForSpecifier:(IASKSpecifier*)specifier;
- (NSArray<NSString*>*)settingsViewController:(IASKAppSettingsViewController*)sender titlesForSpecifier:(IASKSpecifier*)specifier;

The sample app returns a list of all country codes as values and the localized country names as titles.

MultiValue lists can be sorted alphabetically by adding a true Boolean DisplaySortedByTitle key in the Plist. MultiValue list entries can be given an image. Specify images via the IconNames attribute (next to Values/Titles/ShortTitles etc.).

Settings Storage

The default behaviour of IASK is to store the settings in [NSUserDefaults standardUserDefaults]. However, it is possible to change this behavior by setting the settingsStore property on an IASKAppSettingsViewController. IASK comes with two store implementations: IASKSettingsStoreUserDefaults (the default one) and IASKSettingsStoreFile, which read and write the settings in a file of the path you choose. If you need something more specific, you can also choose to create your own store. The easiest way to create your own store is to create a subclass of IASKAbstractSettingsStore. Only 3 methods are required to override. See IASKSettingsStore.{h,m} for more details.

Notifications

There's a IASKSettingChangedNotification notification that is sent for every changed settings key. The object of the notification is the sending view controller and the userInfo dictionary contains the key and new value of the affected key.

Dynamic cell hiding

Sometimes, options depend on each other. For instance, you might want to have an "Auto Connect" switch, and let the user set username and password if enabled. To react on changes of a specific setting, use the IASKSettingChangedNotification notification explained above.

To hide a set of cells use:

- (void)[IASKAppSettingsViewController setHiddenKeys:(NSSet*)hiddenKeys animated:(BOOL)animated];

or the non-animated version:

@property (nonatomic, strong) NSSet *hiddenKeys;

See the sample app for more details. Including a PSGroupSpecifier key in the hiddenKeys hides the complete section.

Register default values

Settings property lists support the DefaultValue parameter to display default values in case there’s no value stored in NSUserDefaults. However, when the app queries NSUserDefaults for the value, that default value is not propagated. This makes sense since NSUserDefaults doesn’t know about settings property lists.

To initially set values for the various settings keys, NSUserDefaults provides the registerDefaults: method that takes a dictionary of "fallback" values that are returned from NSUserDefaults if no value has been stored. This is typically called at app launch.

However, creating and maintaining that dictionary can be cumbersome and there’s a risk that this dictionary and the settings default values get out of sync.

To address this, IASKSettingsReader provides a method that generates this dictionary by traversing the Root.plist and all child plists and gathering the DefaultValue for all keys.

NSDictionary *defaultDict = [appSettingsViewController.settingsReader gatherDefaultsLimitedToEditableFields:YES];
[NSUserDefaults.standardUserDefaults registerDefaults:defaultDict];

iCloud sync

To sync your NSUserDefaults with iCloud, there's another project called FTiCloudSync which is implemented as a category on NSUserDefaults: All write and remove requests are automatically forwarded to iCloud and all updates from iCloud are automatically stored in NSUserDefaults. InAppSettingsKit automatically updates the UI if the standard NSUserDefaults based store is used.

Support

Please don't use Github issues for support requests, we'll close them. Instead, post your question on StackOverflow with tag inappsettingskit.

License

We released the code under the liberal BSD license in order to make it possible to include it in every project, be it a free or paid app. The only thing we ask for is giving the original developers some credit. The easiest way to include credits is by leaving the "Powered by InAppSettingsKit" notice in the code. If you decide to remove this notice, a noticeable mention on the App Store description page or homepage is fine, too.

Author

Originally developed by Luc Vandal, Ortwin Gentz (Mastodon) took over the development and continues to update the framework. InAppSettingsKit is used in FutureTap’s Where To? app, so we eat our own dog food!

Sponsors wanted

If you would like to support my Open Source work, consider joining me as a sponsor! 💪️ Your sponsorship enables me to spend more time on InAppSettingsKit and other community projects. Thank you!

inappsettingskit's People

Contributors

696grocuttt avatar abestanis avatar chrisvasselli avatar dannyshmueli avatar danschlet avatar defagos avatar diederich avatar futuretap avatar gamma avatar gereons avatar hubertzhang avatar irlabs avatar jensdee avatar joshaber avatar jspahrsummers avatar keremerkan avatar mickeyreiss avatar mmllr avatar nschum avatar obotdev avatar orenmeiri avatar pcantrell avatar rastersize avatar saturnpolly avatar shanegao avatar strimper avatar sunbohong avatar triplef avatar vjyanand avatar wkoszek avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

inappsettingskit's Issues

Child pane cell color is off-white for iPad

The child pane row color is slightly off-white on iPad. Seems to work fine on iPhone. It's more noticeable if you change the angle of your screen/monitor to enhance the contrast.

No simple way to wholesale re-style group headers

Even though delegate method

  - (UIView *)tableView:(UITableView *)tableView viewForHeaderForKey:(NSString*)key;

is provided, it is of rather limited usability if you want to re-style group headers (for example change bg/fg colors). Basic problem is that there is no straightforward way to get group header text inside this method (so you can build custom UILabel view). To solve this problem, I have added one more method to IASKSettingsDelegate

  - (UIView *)tableView:(UITableView *)tableView viewForHeaderWithTitle:(NSString*)title;

and altered

- (UIView *)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section {
    UIView *result = nil;

    if ([self.delegate respondsToSelector:@selector(tableView:viewForHeaderForKey:)]) {
        NSString *key  = [self.settingsReader keyForSection:section];
        result = [self.delegate tableView:_tableView viewForHeaderForKey:key];
    } 

    if (( result == nil ) && [ self.delegate respondsToSelector: @selector( tableView: viewForHeaderWithTitle: )]) {
        NSString *title = [ self.settingsReader titleForSection: section ];
        result = [ self.delegate tableView:_tableView viewForHeaderWithTitle: title ];
    }


    return result;
}

This way it is possible to use tableView: viewForHeaderForKey: if something has to be done for particular header and at the same it is possible to re-style all headers.

Regardless of this issue, massively useful piece of code! Thanks a bunch.

Andrei
Leaping Bytes, LLC

Link delegate with view controller in interface builder

Hi,
I've copied the tab bar version from app example in my project.
I can see the settings I've put in setting.bundle (root.plist), and now I cant link in IB the delegate with the ViewController, so I cant caught the events from the setting panel.
In the sample app the delegate (from class IASKAppSettingsViewController in TabBar) is linked with MainViewController.
How can I link with my MyViewController?

thanks a lot

Memory Leaks

Hi Ortwin and Luc

Seems like the leak is something serious.
I added the InAppSettingsKit to my project and added an ordinary Settings.bundle.
When I run and click the default Name field a leak starts.
I'm not an experienced iPhone developer, but thought to share this with you guys.
Sorry if I'm missing something.

Regards
Geevan Lal

Different behaviour between Settings and InAppSettingsKit for password fields

Hi,

In InAppSettingsKit, a password field is a text field with setSecureTextEntry. But it also does setAutocorrectionType, which if nothing is present in the Settings.bundle defaults to UITextAutocorrectionTypeDefault, which is generally YES on most systems.

The problem is that if a password contains a sequence like '9ble' it will be changed to 'able' (with an english dictionary) without the user even noticing (nothing is displayed since it's a secure text field). The workaround is to add a AutoCorrectionType No entry to the Settings.bundle

It seems that the Settings application forces auto-correction to NO if it's a secure field and AutoCorrectionType is not specified.

I suggest to do the same, which is logical (passwords that are dictionary words are not recommended...)

Let me know what you think and I can contribute a fix.

Stefan

NumberPad done button

Hi,
when using NumberPad the keyboard remains open and the only possibility to close it is to select another field and close it's keyboard (if it is not NumberPad too).

There is any way to put a "done" button on bottom/left empty place?

Thank you.

Black or white bar shown above keyboard during edit

In both the default app and my application, I get a black or white bar above the keyboard that covers the preference pane.

It only happens when opening the settings pane by clicking on the Settings tab in the toolbar. In the sample app, if it is opened via a modal or push, the bar is not there.

I see that "Resize view from nib" is checked on the tab bar for the settings item in the sample app. But that seems to have no affect.

How to implement localization

Hi all,
I have update IASKSettingsReader.m with if ([_bundle pathForResource:self.localizationTable ofType:@"strings"] == nil).

This operation will find A file of type "strings", but how to let it open the right file in order to respect user's language?

I have 2 folders in my service.bundle:

  • en.lproj
  • it.lproj
    inside both there is a Root.strings file.

Thank you a lot.

PSMultiValueSpecifier using array stored in NSUserDefaults

HI, i would like to have a PSMultiValueSpecifier or a PSGroupSpecifier using values from an array i store in NSUserDefaults (idea is to store servers and the user can add a server to store):

  • can i do that with inAppSettingsKit?
  • if so can we ask the settings panel to update when the user added a new entry?

Thanks

Undefined Symbols

I just downloaded the latest version since I was behind in my current App and wanted to get some of the new features. I removed the old version from my project and added new files, pointing XCode at the InAppSettingsKit folder on my system. Here's what I got when I compiled my app against the new code:

Undefined symbols:
"OBJC_CLASS$_MFMailComposeViewController", referenced from:
objc-class-ref-to-MFMailComposeViewController in IASKAppSettingsWebViewController.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

Custom settings store not passed to child panes

If a custom settings store is used, it is not passed to child pane view controllers.

The following needs to be added around line 628 of IASKAppSettingsViewController.m

targetViewController.settingsStore = self.settingsStore; 

Using IASK with a settings file in the Documents folder

I really like what guys have done with IASK, but I need to change the IASK behavior to read and write the settings to a file in my Documents folder. I understand that there is an IASKSettingsStoreFile implementation that supports this and have tried changing the settingsStore property in the IASKAppSettingsViewController, but I'm not having much luck. My settings.plist file is read correctly, but doesn't appear get written with the changes I make.

What is the proper way to change the IASKAppSettingsViewController code to use a different (non- settings bundle) file?

Merging custom cell and controller class customization from fork

In my fork, there is a partial implementation that allows one to override classes used for the switch, the cells and the table view controller, so it’s possible to create customized UI.

Currently, I’ve placed properties on the settings view controller that get assigned to classes of various cells, which is used to create them when appropriate. I’ve also re-factored the project a bit, so it is possible to create custom UIControl classes that work like UISwitch, but are not descendants of UISwitch, to allow customized switches. For example, SSSwitch from SSToolkit is used in one of my projects.

I can then do this in a IASKAppSettingsViewController subclass:

self.specifierViewControllerClass = [TASettingsSpecifierViewController class];
self.switchSpecifierCellClass = [TASettingsToggleSwitchSpecifierViewCell class];
self.sliderSpecifierCellClass = [TASettingsSliderSpecifierViewCell class];

Because UISwitch is changed to UIControl<IASKSwitchCustomizing> in IASKPSToggleSwitchSpecifierViewCell, TASettingsToggleSwitchSpecifierViewCell can then use a custom switch which would support custom appearance. As of UISlider it supports plenty of customization hooks already, so the cell just reconfigures the slider in -awakeFromNib.

I’d like to keep the fork as up-to-date with the trunk as possible, so please advise if this mechanism is going to make its way back to trunk, are there any changes or further enhancements that are required or nice to have.

Thanks!

Settings aren't kept in sync on iOS4

It seems to be very easy to get settings out of sync on iOS4. Switching between the App and Settings App you can see the settings aren't always the same.

  1. changing the setting in InAppSettingsKit doesn't alway sync to the main Settings App.
  2. changing the setting in Settings App seems to sync back correctly, but the visual isn't updated until InAppSettings is closed and reopened. leading to confusion.

e.g.

InApp to Settings

  1. Open the App
  2. Open InAppSettings
  3. Make a change (close or don't close InAppSettings
  4. App switch to settings
  5. View the setting note it hasn't updated

Setting to InApp and back again

  1. Open Settings
  2. Make a change
  3. Open the app
  4. Open InAppSettings
  5. Not the change is reflected
  6. Leaving InAppSettings open
  7. Switch to Settings app
  8. Update the settings
  9. Switch back to the App (where InAppSettings is still open)
  10. Note the change is not reflected
  11. Close/Reopen InAppSettings
  12. Note the change is reflected

I've implemented code to eliminate use of XIBs for custom cells

@interface IASKPSSliderSpecifierViewCell ()
- (void)createSubviews;
@end

@implementation IASKPSSliderSpecifierViewCell

@synthesize slider=_slider, 
        minImage=_minImage, 
        maxImage=_maxImage;

- (id) initWithFrame:(CGRect)frame
{
    if ((self = [super initWithFrame:frame]))
    {
        [self createSubviews];
    }
    return self;
}

- (id) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    if ((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]))
    {
        [self createSubviews];
    }
    return self;
}

- (id) init
{
    if ((self = [super init]))
    {
        [self createSubviews];
    }
    return self;
}

- (void) createSubviews
{
    self.selectionStyle = UITableViewCellSelectionStyleNone;
    self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;

    CGRect selfFrame = self.contentView.frame, rc;

    rc.origin.x = kIASKPaddingLeft;
    rc.origin.y = 13;
    rc.size.width = 21;
    rc.size.height = 21;

    _minImage = [[UIImageView alloc] initWithFrame:rc];
    _minImage.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;

    rc.origin.x = selfFrame.size.width - rc.size.width - kIASKPaddingRight;
    _maxImage = [[UIImageView alloc] initWithFrame:rc];
    _maxImage.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin;

    rc.origin.y = 12;
    rc.origin.x = 42+kIASKPaddingLeft;
    rc.size.width = selfFrame.size.width - rc.origin.x - 42 - kIASKPaddingRight;
    rc.size.height = 23;

    _slider = [[IASKSlider alloc] initWithFrame:rc];
    _slider.continuous = YES;
    _slider.minimumValue = 0.0f;
    _slider.maximumValue = 1.0f;
    _slider.value = 0.5f;
    _slider.autoresizingMask = UIViewAutoresizingFlexibleWidth  | UIViewAutoresizingFlexibleBottomMargin;

    [self.contentView addSubview:_minImage];
    [self.contentView addSubview:_maxImage];
    [self.contentView addSubview:_slider];
}


@interface IASKPSTextFieldSpecifierViewCell ()
- (void)createSubviews;
@end

@implementation IASKPSTextFieldSpecifierViewCell

@synthesize label=_label,
        textField=_textField;

- (id) initWithFrame:(CGRect)frame
{
    if ((self = [super initWithFrame:frame]))
    {
        [self createSubviews];
    }
    return self;
}

- (id) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    if ((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]))
    {
        [self createSubviews];
    }
    return self;
}

- (id) init
{
    if ((self = [super init]))
    {
        [self createSubviews];
    }
    return self;
}

- (void) createSubviews
{
    self.selectionStyle = UITableViewCellSelectionStyleNone;
    self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;

    CGRect selfFrame = self.contentView.frame, rc;

    rc.origin.x = kIASKPaddingLeft;
    rc.origin.y = 11;
    rc.size.width = selfFrame.size.width - rc.origin.x - 71;
    rc.size.height = selfFrame.size.height - rc.origin.y - 12;

    _label = [[UILabel alloc] initWithFrame:rc];
    _label.font = [UIFont boldSystemFontOfSize:17];
    _label.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin;

    rc.origin.x = 100;
    rc.size.width = selfFrame.size.width - rc.origin.x - kIASKPaddingRight;

    _textField = [[IASKTextField alloc] initWithFrame:rc];
    _textField.font = [UIFont systemFontOfSize:17];
    _textField.textColor = [UIColor colorWithRed:0.275 green:0.376 blue:0.522 alpha:1.000];
    _textField.textAlignment = UITextAlignmentRight;
    _textField.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin;

    [self.contentView addSubview:_label];
    [self.contentView addSubview:_textField];
}



@interface IASKPSToggleSwitchSpecifierViewCell ()
- (void)createSubviews;
@end

@implementation IASKPSToggleSwitchSpecifierViewCell

@synthesize label=_label, 
toggle=_toggle;

- (id) initWithFrame:(CGRect)frame
{
    if ((self = [super initWithFrame:frame]))
    {
        [self createSubviews];
    }
    return self;
}

- (id) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    if ((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]))
    {
        [self createSubviews];
    }
    return self;
}

- (id) init
{
    if ((self = [super init]))
    {
        [self createSubviews];
    }
    return self;
}

- (void) createSubviews
{
    self.selectionStyle = UITableViewCellSelectionStyleNone;
    self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;

    CGRect selfFrame = self.contentView.frame, rc;

   _toggle = [[IASKSwitch alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
    rc = _toggle.frame;
    rc.origin.x = selfFrame.size.width - rc.size.width - kIASKPaddingRight;
    rc.origin.y = (selfFrame.size.height - rc.size.height) / 2;
    _toggle.frame = rc;
    _toggle.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin;

    rc.origin.x = kIASKPaddingLeft;
    rc.origin.y = 11;
    rc.size.width = selfFrame.size.width - rc.origin.x - 71;
    rc.size.height = selfFrame.size.height - rc.origin.y - 12;

    _label = [[UILabel alloc] initWithFrame:rc];
    _label.font = [UIFont boldSystemFontOfSize:17];
    _label.autoresizingMask = UIViewAutoresizingFlexibleWidth 
    | UIViewAutoresizingFlexibleBottomMargin
    | UIViewAutoresizingFlexibleRightMargin;

    [self.contentView addSubview:_label];
    [self.contentView addSubview:_toggle];
}

And then when you create the cells just use initWithStyle:reuseIdentifier:
Then you can delete the cells' XIBs, and this way be more memory-efficient.

easy way to set background image for all inappsettings views?

dear community,
i am looking for a fast and dirty way to change the wallpaper for all inappsettings views.

so far, i added this line to IASKAppSettingsViewController.m / viewWillAppear:
_tableView.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"background1.png"]];
but then both table view AND table cells get the background pic individually, which looks wrong.

i rather would aim to leave the table view background transparent and change the background of the view "behind" it if there is any.

any suggestions are highly appreciated. :)

cheers,
dave

Entry is too wide on iPad

I'm trying out some stuff on iPad. One of my fields is too wide. Picture here:
http://picasaweb.google.com/ewmailing/MailingList#5497703713636723410

Here is the excerpt from the plist:

Type
PSTextFieldSpecifier
Title
Show only last # of days
IsSecure

KeyboardType
NumberPad
AutocapitalizationType
None
AutoCorrectionType
No
Key
LimitViewToLastNumberOfDays
DefaultValue
0

The layout problem only exists inside the app. From the system wide settings, the width is normal.

disabling email support

I would need to disable the email support for my application, due to conflicts with MessageUI. What is the most elegant way to do that, so I don't have to link my application with the MessageUI framework?

thanks,
Teresa

settingsViewControllerDidEnd in InAppSettingsKitSampleApp not called?

hello,
when i enter/leave the settings view via the "Settings" button in the UITabBarController
the delegate method "settingsViewControllerDidEnd" is not called.
is this behavior intended? could somebody hint to a solution how to connect this method, since i do not want to use the push or modal buttons.

thanks in advance,
best
dave

Alignment problem in PSTextFieldSpecifier

There is an alignment problem for PSTextFieldSpecifier since commit 7af791d.

It seems to be caused by this change:

--- a/InAppSettingsKit/Views/IASKPSTextFieldSpecifierViewCell.m
+++ b/InAppSettingsKit/Views/IASKPSTextFieldSpecifierViewCell.m
@@ -24,6 +24,7 @@
             textField=_textField;
 
 - (void)layoutSubviews {
+    [super layoutSubviews];
    CGSize labelSize = [_label sizeThatFits:CGSizeZero];
    labelSize.width = MIN(labelSize.width, _label.bounds.size.width);

I don't know the reason for this change, but everything seems to work normal without it.

PSTitleValueSpecifier differs InApp vs Settings App

I have a PSTitleValueSpecifier that I use to store the Application version. It's default value is "1.0" but I set it to the correct value using the NSUserDefaults object. The value is displayed correctly if I use Apple's setting app, but not in my In App view. Any idea?

settingsViewControllerDidEnd not called

Hi,

I am new to Obj C but I got it to work so the modal view would dismiss. I had to comment out the if statement

if (self.delegate && [self.delegate conformsToProtocol:@protocol(IASKSettingsDelegate)])

in IASKAppSettingsViewController.m on line 250. Am I screwing anything up? I wish there was documentation that has examples/instructions on integration for newbs like me.

Memory Leak StoreUserDefaults

By the way thanks for your great settings app.

Have been testing my app and found:

  • (id)settingsStore {
    if (!_settingsStore) {
    _settingsStore = [[IASKSettingsStoreUserDefaults alloc] init];
    }
    return _settingsStore;
    }
    but there is no release??

Merge plist files into one grouped file

I suggest an option that allows merging of different plist files into one grouped settings panel. This way one could split up groups into files and reuse them in other places - but still can create one big settings page.

Problem at Localization webview's html

I find when I make Localization to my app.
the html files(IASKAppSettingsWebViewController) Localzation doesn't work.

Look into the code IASKAppSettingsWebViewController.h.(Line 30)
if (!self.url || ![self.url scheme]) {
self.url = [NSURL fileURLWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:urlString]];
}

just by contract string.
If I make manual.html Localization, this path will be ..../en.lproj/manual.html
so the webview will not wok.
fix this we can change it to

if (!self.url || ![self.url scheme]) {

    self.url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:[urlString stringByDeletingPathExtension] ofType: [urlString pathExtension]]];
//      self.url = [NSURL fileURLWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:urlString]];
    }

is it right?

IASKButtonSpecifier help

Hi,

noob question but how can i call -(void)resetMethod; from within the default +(void)buttonDemoAction:(IASKAppSettingsViewController_)sender key:(NSString_)key; in the MainViewController of the demo app.

Thanks in advance

Reopen #8: Entry is too wide

Sorry, I didn't mean to close the issue. I didn't understand what "Comment and close" meant. I thought it would close the view/window, not the issue.

Feature request documentation/slider

Hi. Just like to thank you guys for IASK. It's very functional and the source looks great. I have a request, and for lack of a better place - did I miss an official forum? - I've put it here.

Documentation. Actual documentation. Of any kinda.

Otherwise, could a slider shows the current value and the min/max range

ie:
0Mb ----------o--------- 50Mb
You are currently using 25Mb

Where the 25 will change as the slider does. I'm looking at implementing this in a custom view atm, but I have a feeling that I'm reinventing the wheel somewhat, but the lack of implementation documentation (including trivial things such as enumerating all the PStypes and any dependant key/values) is killing me :(

Cheers

Mawt

*.inApp.plist not working

I've tried placing an alternate Root.inApp.plist both within Settings.bundle and within the main project directory - but in neither case does InAppSettingsKit use the alternative file.

Is this feature yet to be implemented - I couldn't find any reference to 'inApp' in the source?

How to synchronise defaults into settingsStore?

I note that the default values specified in the plist don't make it into NSUserDefaults, they just appear as text in the text field on the settings screen. How do I synchronise the settingsStore with the default values that are specified? Am I missing something?

First PSToggleSwitchSpecifier not working...

My Root.plist contains two PSToggleSwitchSpecifiers, configured identically except for Title and Key.

Whilst the second of these works exactly as expected through InAppSettingsKit, the first is always displayed as being off. In fact, even with a null delegate method, setting the toggle to on, exiting the settings modal view, and immediately re-entering again shows the Toggle as being off. Indeed, the value of this Toggle is only ever read in code, never altered.

If I set the Toggle to On in Apple's Settings, then load InAppSettingsKit and toggle it On then Off, the Apple Settings app show it as Off. Simply leaving the InAppSettingKit Setting page doesn't change the Apple Settings value, even if other controls are changed.

A snippet of my Root.plist is:

            <dict>
                    <key>Type</key>
                    <string>PSGroupSpecifier</string>
                    <key>Title</key>
                    <string>Download updates ...</string>
            </dict>
            <dict>
                    <key>Type</key>
                    <string>PSToggleSwitchSpecifier</string>
                    <key>Title</key>
                    <string>... over Wi-Fi</string>
                    <key>Key</key>
                    <string>checkForUpdates</string>
                    <key>TrueValue</key>
                    <string>isSet</string>
                    <key>FalseValue</key>
                    <string>isNotSet</string>
                    <key>DefaultValue</key>
                    <string>isSet</string>
            </dict>
            <dict>
                    <key>Type</key>
                    <string>PSToggleSwitchSpecifier</string>
                    <key>Title</key>
                    <string>... over EDGE/3G</string>
                    <key>Key</key>
                    <string>allowCellularDownloads</string>
                    <key>TrueValue</key>
                    <string>isSet</string>
                    <key>FalseValue</key>
                    <string>isNotSet</string>
                    <key>DefaultValue</key>
                    <string>isNotSet</string>
            </dict>

... so the value (Off) which InAppSettingsKit always shows isn't even the default for the control!

Everything else seems to work fine - any ideas why this particular control isn't?

Fields are right justified when editing

In my own app and the sample app, I've noticed that when you edit a text field, the value is suddenly right justified. When it wasn't being edited, the value was left justified.

This behavior is not present in the iPhone settings app.

I see it against the 3.0 and 3.1 simulators. (Haven't tried anything else.)

Why no Xcode project and static library?

Any reason why you don't have an xcode project with a static library target for easy integration into our xcode projects? The alternative of adding references to the required files directly -- as the demo project does -- is strongly contraindicated.

Leak in Advanced section of sample project

Your code has been a great help for me in my ongoing project.
Apparently i found a leak in the advanced section of the sample project .
When I click password and type in something a leak starts.
Didn't get time to look into it.

Text field notification?

I have a PSTextFieldSpecifier in my plist, and since it is used for login (username/password), I need to know when the user has finished editing text (i.e. pressed Done button on keyboard, aka textFieldDidEndEditing in UITextFieldDelegate) in order to try to login (as opposed to having a "Login" button).
Unfortunately there's no method in IASKSettingsDelegate for this event, so I'm not sure how to implement this. Am I missing something, or the only solution is to add a new delegate method on my own?

I'm having trouble reading the root.inApp.plist

Any help would be awesome, i at a dead end as to how to retrieve the data using your program from the plist files in settings bundle. Do you need to initialize the settings in the delegate and if not how do you get the data into a dic or array so i can use them in the app.

Sorry for the noob question its my first big app and i've never used settings bundle before.

Thanks

Matthew

Default values on first launch

It seems default values in my plist aren't available on a freshly installed version of my app. For example a toggle switch with default value set to YES results in a NO value until the user actually switches the toggle. I guess that's because default values from the plist aren't written to the settings storage upon first launch. If I'm right, what's the best way to deal with this? Thanks!

P.S. is this the right way to read a value?
[appSettingsViewController.settingsStore boolForKey:@"myKey"]

please, help to run sample

I'm new with objetive-c, (but I know how open a project, build and run it)
I want to try this framework to include in my app and I've downloaded it ... but I have problems to run the sample app.
What I did

  • open XCode, open InAppSettingsKitSampleApp
  • As Base SDK missing, change Base SDK in Project and Target (IOS Simulator 4.1)
  • Build and Run ... and Build Failed (1347 errors) ... That's bad ¿is not?

Is there a tutorial for dummies?
What have I to do to run (at least) the sample app?

thanks in advanced

Multiple IASKCustomViewSpecifier

i am trying to create multiple IASKCustomViewSpecifier cells using the InAppSettingsKit. I noticed that in the example you have the key set to customCell. thats fine but when i added a second one and changed the key to customCellTwo it made the cell shrink. i then added an if statement in the - (CGFloat)tableView:(UITableView_)tableView heightForSpecifier:(IASKSpecifier_)specifier in my mainViewController to include the customCellTwo and specified the height. so now it looks fine but the problem i am having now is that after typing something in (to the second customCellTwo cell) and getting out of the settings and going back the value i entered hasn't changed. it does work with the original customCell.

What am i doing wrong?

IASKSettingsStoreFile Synchronize Issue

I tried a little experimental code to test the "mySettings" feature of the kit and found that the toggle switch does not get synchronized (writeToFile) like many of the other features. I suspect that this applies to the slider also. Seems like they both end up with only defaultCenter notifications that do not call the IASKSettingsStoreFile synchronize method.

He is my trial code just in case I am doing something wrong:

  • (IBAction)showSettingsPush:(id)sender {
    //[viewController setShowCreditsFooter:NO]; // Uncomment to not display InAppSettingsKit credits for creators.
    // But we encourage you no to uncomment. Thank you!
    self.appSettingsViewController.showDoneButton = NO;

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];

    // the path to write file
    NSString *settingsFile = [documentsDirectory stringByAppendingPathComponent:@"mySettings"];

    IASKSettingsStoreFile* mySettingsBundle = [[IASKSettingsStoreFile alloc] initWithPath:settingsFile];
    self.appSettingsViewController.settingsStore = mySettingsBundle;

    BOOL testbool = [mySettingsBundle boolForKey:@"toggleSwitch"];

    NSLog(@"testbool = %@",(testbool ? @"YES" : @"NO"));

    [mySettingsBundle release];

    //self.appSettingsViewController.settingsStore =IASKSettingsStoreFile:
    [self.navigationController pushViewController:self.appSettingsViewController animated:YES];
    }

key not set in buttonAction callback

As per subject, I have added a custom button. My callback gets triggered, but the passed key is an empty string even if I set Key in the plist item.

By the way, is there any way to get a reference to the triggered button?
I am a bit of a noob. I expected the sender to be the button, not the controller. I'm parsing down the subviews using introspection to get the button, with no success so far.

Thank you, keep up the good job.

iPad Orientation and Popovers with SplitViewController (_keyboardWillShow)

There seems to be two_keyboardWillShow issues with the current version when using with iPad2 and a SplitViewController.

  1. When app is started in landscape mode the logic

if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation )

does not successfully detect the orientation and the correct view frame size changes are not made.

I added this function to get it to work, although you may want to come up with a better one:

  • (BOOL)screenOrientation {
    if (([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft) ||
    ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight)) {
    //landscape view
    return YES;
    }

    /// portrait view
    return NO;
    }

Seems like the status Bar info is more reliable.

  1. In either landscape or portrait the calc

CGRect viewRectAbsolute = [_tableView convertRect:_tableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];

returns invalid x,y coordinates for a popover view. If I use

CGRect viewRectAbsolute = [_tableView convertRect:_tableView.bounds toView:appDelegate.splitViewController.view];

the correct x,y coordinates are returned.

Probably need some code to test
if iPad and SplitViewController and Popover
do special for this condition
else
do what you currently do

Hope this helps

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.