Settings.bundle, input validation - ios

Is it possible to specify validation rules for a particular entry in a Settings.bundle? For instance, would it be possible to restrict a text field to a particular set of characters? Or do I have to alert the user if there is "garbage" in the configuration?

I believe you'll have to alert the user that they entered bad data. There isn't any way to add your own code to the settings bundle beyond the plist values.

Boy, this is an old question, and...boy, things haven't improved.
The settings metaphor -where Apple recommends that you stick ALL your app settings, BTW- is a usability train wreck.
For example, I needed to add a discrete set of integers as a range of values (1 - 7). The default is an Int.
Looks like the only UI element available is a slider.
With continuous range, and no markings.
Oh, well. There's no way in hell that I'd ever use this as a place to put general-purpose app settings; only rather obscure ones that hardly ever need to be tweaked.

Related

How to change the VoiceOver pronunciation in swift?

I am trying to implement the accessibility to my ios project.
Is there a way to correct the pronunciation of some specific words when the voice-over is turned on? For example, The correct pronunciation of 'speech' is [spiːtʃ], but I want the voice-over to read all the words 'speech' as same as 'speak' [spiːk] during my whole project.
I know there is one way that I can set the accessibility label of any UIElements that I want to change the pronunciation to 'speak'. However, some elements are dynamic. For example, we get the label text from the back-end, but we will never know when the label text will be 'speech'. If I get the words 'speech' from the back end, I would like to hear voice-over read it as 'speak'.
Therefore, I would like to change the setting for the voice-over. Every time, If the words are 'speech', the voice-over will read as 'speak'.
Can I do it?
Short answer.
Yes you can do it, but please do not.
Long Answer
Can I do it?
Yes, of course you can.
Simply fetch the data from the backend and do a find-replace on the string for any words you want spoken differently using a dictionary of words to replace, then add the new version of the string as the accessibility label.
SHOULD you do it?
Absolutely not.
Every time someone tries to "fix" pronunciation it ends up making things a lot worse.
I don't even understand why you would want screen reader users to hear "speak" whenever anyone else sees "speech", it does not make sense and is likely to break the meaning of sentences:
"I attended the speech given last night, it was very informative".
Would transform into:
"I attended the speak given last night, it was very informative"
Screen reader users are used to it.
A screen reader user is used to hearing things said differently (and incorrectly!), my guess is you have not been using a screen reader long enough to get used to the idiosyncrasies of screen reader speech.
Far from helping screen reader users you will actually end up making things worse.
I have only ever overridden screen reader default behaviour twice, once when it was a version number that was being read as a date and once when it was a password manager that read the password back and would try and read things as words.
Other than those very narrow examples I have not come across a reason to change things for a screen reader.
What about braille users?
You could change things because they don't sound right. But braille users also use screen readers and changing things for them could be very confusing (as per the example above of "speech").
What about best practices
"Give assistive technology users as similar an experience as possible to non assistive tech users". That is the number one guiding principle of accessibility, the second you change pronunciations and words, you potentially change the meaning of sentences and therefore offer a different experience.
Summing up
Anyway this is turning into a rant when it isn't meant to be (my apologies, I am just trying to get the point across as I answer similar questions to this quite often!), hopefully you get the idea, leave it alone and present the same info, I haven't even covered different speech synthesizers, language translation and more that using "unnatural" language can interfere with.
The easiest solution is to return a 2nd string from the backend that is used just for the accessibilityLabel.
If you need a bit more control, you can pass an AttributedString as the accessibilityLabel with a number of different options for controlling pronunication
https://medium.com/macoclock/ios-attributed-accessibility-labels-f54b8dcbf9fa

iOS detect keyboard layout (e.g. QWERTY, AZERTY)

I am building a custom suggestion/autocorrection feature in an iOS app. It must detect accidental adjacent keypresses and compare this to a known word list to suggest the word it thinks the user intended to type.
For example, if the custom word list contains cat, dog, monkey, and the user types cst, the app can determine that the most likely word was cat (because s is adjacent to the a key)
This will work on a standard QWERTY keyboard, but what happens if the user is using an AZERTY keyboard?
For the autocorrect/suggest to work reliably, the app must be able to detect the keyboard layout in use.
In iOS, it is possible to obtain a UITextInputMode object from a UITextField. This object has a primaryLanguage (string) property, which will display the locale (e.g. en-GB), but this does not contain enough granularity to distinguish between English (Australia) QWERTY and English (Australia) AZERTY. In both cases, the primaryLanguage is en-AU.
Is it possible to detect the keyboard layout in iOS?
I have not been able to find a clean solution to this problem.
Maybe this would be worth a TSI ticket to discuss it with Apple employees.
I know that this will not be a satisfying answer, but I would still like to share my thoughts here for future readers:
Private API of UITextInputMode:
textField.textInputMode?.value(forKey: "identifierWithLayouts")
This will return a string like de_DE#sw=QWERTZ-German;hw=Automatic from which you can infer the keyboard layout.
UserDefaults
UserDefaults.standard.object(forKey: "AppleKeyboards")
This will return a list of all keyboards that the user has installed. In most cases, this will only be one language (besides the emoji keyboard).
For example:
Optional(<__NSCFArray 0x600003b8e6c0>(en_US#sw=QWERTY;hw=Automatic,emoji#sw=Emoji))
You could also iterate over UserDefaults.standard.dictionaryRepresentation() and search for QWERTZ/QWERTY/AZERTY within the values.
With much manual effort, you could maybe encode UITextInputModes to binary data in all ambiguous cases like en_AU. Something like
NSKeyedArchiver.archivedData(withRootObject:textField.textInputMode, requiringSecureCoding: false) can then be used to compare binary encodings of the user's textInputMode at runtime.
I have found this old question that may have a solution for you. No sure it's still working, but it shows in the question how to get the current instaled keyboards, and someone provided a "gray area" solution, as it seems that there is no direct way to achieve what you intend to do.
Hope this help.
AppleLanguages object at index 0 is common way to get input language. Instead of trying to determinate which language users are using and default layout, as far I worked with custom keyboard extension, I used one of recommended ways from Apple: use separate keyboard layout for each language. In other way I don't think you will have a stable and productive prediction, auto correct, by the way. As for auto correct I used SymSpell (https://github.com/AmitBhavsarIphone/SymSpell) and different dictionaries from https://github.com/wolfgarbe/SymSpell/tree/master/SymSpell.FrequencyDictionary to make my own RealmDb for each language. So far it was a little work to do, but finally my keyboard extension was publisehd in App Store. [Note: I am not related with SynSpell owners or coders] See images

How fast is UIAccessibilityIsVoiceOverRunning()?

In a project I'm working on, I record usage metrics for various features, and I want to also track how often the features are used in accessibility mode. To that effect, I intend to use the UIAccessibilityIsVoiceOverRunning() function.
What I don't have a handle on, nor is it specified in the documentation, is whether calling this multiple times from multiple places will have an adverse impact on the overall latency of my app. There are a lot of metrics I'd like to add this to, so I worry about the combined effect of such a change. Any ideas?
Before answering, I need to caution:
Be careful not to prematurely optimize; there may be no problem here.
Consider whether you really want that answer to this question. Absolute user numbers for a particular product seldom bolster the case for accessibility. Supporting access is a moral, and sometimes legal, obligation and is not always supported by easily tabulated business metrics.
There is more than one "accessibility mode" on iOS. Measuring VoiceOver use, alone, overlooks many other accessibility tools, and their users, including Dynamic Type, Switch Control, Touch Accommodations, and others.
That said, if by some coincidence UIAccessibilityIsVoiceOverRunning() is too expensive for your particular use case, you could register for VoiceOver status change notifications using UIAccessibilityVoiceOverStatusChanged and cache the value, yourself.

Automatically transforming NSString into NSLocalizedString?

I am still paying dearly for learning iOS development, so please be kind.
I have an iOS application containing around 400 NSString litterals. I never thought that I would want to localize this app later on, so while being aware of NSLocalizedString I decided to not use them for my project. Now the world has changed and I need to localize this application. Is there any tool/script I can use that will run through my .m files and "search/replace" my NSStrings with NSLocalizedStrings before I extract them with genstrings?
Thanks
Roger
You made a mistake not writing your code correctly the first time, and now you have to pay the price.
You need to go through your program manually and change user-visible string literals to calls to NSLocalizedString.
Note that you do NOT want to globally change all string literals. Things like dictionary keys should not be localized.
Always, ALWAYS, use NSLocalizedString to create localized strings. It's only a few more characters to type, and it makes internationalizing your code DRAMATICALLY easier.
The good news is that the pain of doing this will serve as a bitter lesson and you likely won't make the same mistake again.
Yes! A find and replace regex will speed up this up.
In the find bar put:
(".*")
In the replace bar:
NSLocalizedString($1,comment:"")
This will change "normalString" to NSLocalizedString("normalString",comment:"")
So go through your code and on the ones you want to replace just press replace, this is a massive timesaver!
You generally don't want to replace ALL NSStrings with NSLocalizedString as not all strings are necessarily 'user facing'. You might have string constants that are used internally that the user never sees and these in general should not be translated. Hence, blindly replacing all NSStrings with NSLocalizedString is probably not a great idea.
There is a fair bit of work involved going through and doing this manually, but its a one-time effort - once you've done it once you'll know the correct way to handle any new user-facing strings and do it as you go. Having said that - there may very well be a tool out there somewhere that handles this elegantly, but there's no avoiding the manual picking which strings need to be translated and which don't.
From I have learned and checked out, there no automated method to turn your strings to localized one you wish. But there's a plugin for XCode called Lin, that makes your process easy.
When you are focusing on NSLocalizedString or other functions to get a localized version of a string, Lin shows the list of localizations that contains the inputted key string.
Lin
From the question and your comments it seems you have around 400 strings only 20 of which should not be localised. With that ratio, as you yourself say, changing them all and then undoing the change for 20 can make sense.
To do this get TextWrangler, or BBEdit, and perform a multi-file pattern matching search and replace. You can confine the search to files ending in .m or .h. The task will be quick and easy, apart from those 20...
HTH

Editable fields in iOS

I am building app, that there will be a "Admin Panel" Where features can be turned on and off. I have come to realize that i am not sure how that is gonna work. Would I create a Db and make that editable or would i need to make a plist and have the options work from there? Some of the options that will be able to be turned on and off will range from pages, to certain parts of the page. Anyone have any suggestion or somewhere to point me in a direction to get this answer?
How you decide to persist the data is up to you. You might try NSUSerDefaults.
Regardless of how you store the data, you can use an editable UITableView with a cell style of UITableViewCellStyleValue1. This is similar to how many of the settings are handled in the Settings app.
UITableViewCellStyleValue1
A style for a cell with a label on the left side of the cell with
left-aligned and black text; on the right side is a label that has
smaller blue text and is right-aligned. The Settings application uses
cells in this style.
This question is very broad and the answer might be "it depends". A typical approach would be to leverage NSUserDefaults and store the preferences there.
Read the documentation on NSUserDefaults and consult the Preferences and Settings Programming Guide for a bigger picture.
I did this recently and decided against using the database for storage of these options as it seemed unnecessarily complex for just storing a few settings. OTOH, I opted not to use the plist. In the end, I decided to use the NSKeyedArchiver to save those settings out to a file in the filesystem. My decision against the plist was based on the fact that I had a couple of complex data structures I wanted to save.
It may be that it could have been done in a plist or using NSDefaults, but the save and load methods took only a few lines of code, then I created a class containing all of the items I needed to save.
Were I doing it again I think I would do it the same way.

Resources