NSAttributedString on currently typed text - ios

I'm currently making a facebook-like tagging view, i.e. the user types in #name and a view is filtering the names of people which matches the #name. When the user taps a name in that view the currently typed word, in this case #name, will be replaced with the name of the tapped user. For instance, let's say I type #joh I will receive the suggestion "John Doe" which I the proceed to tap. Now #joh is replaced with John Doe. This works fine.
However, I would also like to make "John Doe" a different background color using NSAttributedString, and I have the code to do this as well. The issue I'm experiencing however is that the user might not be done typing and every single character typed after I add the NSBackgroundAttribute causes all the following text receiving the same background color.
I've checked my range for when I add the NSAttribute and it's set to, in this example with John Doe, to be start: 0 and end: 8, but even so I still get the background color on characters that are on a location above 8. What am I missing here?
Code
let tappedUserName = user.name
let myRange = (textView.text as NSString).rangeOfString(tappedUserName)
let attribute = [NSBackgroundColorAttributeName: UIColor.blueColor()]
let myString = NSMutableAttributedString(string: textView.text)
myString.setAttributes(attribute, range: myRange)
textView.attributedText = myString
After this code is executed I continue typing the UITextView's following characters will have the same background color.

Related

Removing wikitext hyperlinks in Swift

I'm trying to remove Wikitext hyperlink formatting and just get the link text, but everything I've tried either deletes nothing or deletes much more than expected. Here's the general pattern:
[[user interface]] → user interface
[[Telephone call|calls]] → calls
[[camera phone|take pictures]] → take pictures
If the text between [[ and ]] contains a |, I try to remove the text between [[ and |, remove the closing brackets, but retain the text in-between | and ]]. If it doesn't contain a |, I simply want to remove the brackets, retaining the text between them.
Example:
The iPhone has a [[user interface]] built around a [[multi-touch]] screen. It connects to [[cellular network]]s or [[Wi-Fi]], and can make [[Telephone call|calls]], [[web browser|browse the web]], [[camera phone|take pictures]], [[portable media player|play music]] and send and receive [[email]]s and [[text messaging|text messages]].
Expected result:
The iPhone has a user interface built around a multi-touch screen. It connects to cellular networks or Wi-Fi, and can make calls, browse the web, take pictures, play music and send and receive emails and text messages.
I discovered this answer but upon plugging it into my app, it removed all of the text between [[ and ]], instead of the text between [[ and |.
Using the example above, this is what the code from that answer results in:
The iPhone has a {removed} built around a {removed} screen. It connects to {removed}s or {removed}, and can make {removed}, {removed}, {removed}, {removed} and send and receive {removed}s and {removed}.
This is really leaving me stumped, can anyone help? Thanks!
extension String {
func replacingOccurrencesHyperlinks() -> String {
let regExpr = "\\[\\[[^\\]]+?\\|(.+?)\\]\\]"
return replacingOccurrences(of: regExpr, with: "{removed}", options: .regularExpression)
}
} // this is the extension I use on the MediaWiki API result.
there is probably a better one liner regex solution, but I forgot how it works, in the meantime try this to print the Expected result:
func replacingOccurrencesHyperlinks() -> String {
return self.replacingOccurrences(of: "\\[\\[(?:[^\\]|]*\\|)", with: "", options: .regularExpression)
.replacingOccurrences(of: "[[", with: "")
.replacingOccurrences(of: "]]", with: "")
}
Resolved by an awesome guy over on Reddit. Just needed to replace with: "{removed}" in the extension with simply with: "$1"!

How to use accessibilitySpeechIPANotation?

In Daniel Devesa Derksen-Staats' book 'Developing Accessible iOS Apps', the following example is included to show how IPA (International Phonetic Alphabet) notation can be used to specify the VoiceOver pronunciation:
let ipaAttributedText = NSMutableAttributedString(string: "Paella is a Valencian rice dish")
let ipaRange = ipaAttributedText.string.range(of: "Paella")!
ipaAttributedText.addAttributes([.accessibilitySpeechIPANotation: "paˈeʎa"], range: NSRange(ipaRange, in: ipaAttributedText.string))
ipaLabel.attributedText = ipaAttributedText
// Excerpt From: Daniel Devesa Derksen-Staats. “Developing Accessible iOS Apps.” Apple Books.
The result, at least in iOS 15, is clearly not what was intended. The accessibility label, as it appears in the VoiceOver caption is "ipa, Paellais a Valencian rice dish" - and this is how it is read. The VoiceOver synth's pronunciation is roughly 'paylace', that is, it is completely ignoring the phonetic transcription (I can replace "paˈeʎa" with literally anything, the pronunciation doesn't change). Also any whitespace between the target word and what follows is deleted in the caption and pronunciation. In the console, I can output the value of the ipaAttributedText, everything there looks ok:
Paella{
UIAccessibilitySpeechAttributeIPANotation = "pa\U02c8e\U028ea";
} is a Valencian rice dish{
}
This blog post contains a very similar example, differing only in that it sets the .accessibilityAttributedLabel instead of .attributedText, but it fails in the same way.
Is this broken on iOS 15? or is there something else needed to make this work?

Xcode 10 code completion placeholders — what is the "T"?

In Xcode 10 code completion, the text underlying the placeholder tokens has an extra #T# before it (to see that this is so, copy and paste the inserted code template into a different text editor):
let alert = UIAlertController(
title: <#T##String?#>, message: <#T##String?#>,
preferredStyle: <#T##UIAlertController.Style#>)
What is that? Does "T" mean Type? What difference does it make in my usage of the placeholder?
The syntax <#T##_A_##_B_#> is used to specify a default piece of code for the placeholder. The placeholder will be displayed as _A_, but when the user presses the enter key the placeholder will be replaced with _B_.
Placeholder:
After pressing enter:
It'd a useful feature when presenting something to an audience, because as opposed to snippets, I would't need to remember the name of each snippet, I'd just select a placeholder and press enter to get the right piece of code.
EDIT:
Answering your question, indeed it seems that the T refers to type. If you try to replace the placeholder with an expression, like <#T##Example1##let i = 3#>, the placeholder it's not replaced with let i = 3 as you would expect. It is instead replaced with <<error type>>.
Furthermore, this placeholder <#T##transform: (Error) throws -> U?##(Error) throws -> U?#> is replaced with:
{ (<#Error#>) -> U? in
<#code#>
}
My guess is that when you prepend the T you are telling Xcode that you will provide a type, then Xcode finds an appropriate default value for that type.

How to make this UILabel move the email address to the next Line?

I have a simple UILabel that is printing text as follows:
John Doe sent a message to blahblah-
blah#blahblah.com
Thus, the email address here : blahblah-blah#blahblah.com is being cut and partially displayed on the next line. What do I need to do to make it display as :
John Doe sent a message to
blahblah-blah#blahblah.com
?
I already have the following :
self.mailLabel.lineBreakMode = NSLineBreakModeByWordWrapping;
self.mailLabel.numberOfLines = 0;
The string in question is :
[NSString stringWithFormat:#"You sent a message to %#", emailAddress];
What should I do here? Remember, the name can be long and hence, adding a line break in the string won't work because I don't want the following case :
Jonathon Dawson sent a message
to
blahblah-blah#blahblah.com
which should be
Jonathon Dawson sent a message
to blahblah-blah#blahblah.com
self.mailLabel = [NSString StringWithFormat:#"You sent a message to\n%#"];
You use \n to make a new line.
Also, make sure you set the numberOfLines to 2 on the label.
You need to add ZWNBSP(Zero-width no-break space) characters to the left and to the right of - (hyphen, aka dash) symbol:
self.mailLabel.text = [self.mailLabel.text stringByReplacingOccurrencesOfString:#"-" withString:#"\u2060-\u2060"];
Remarks:
U+2060 - Zero-width no-break space Unicode character prevents any line breaks that may be inserter to wrap the word before and after it. As soon as UILabel (as well as other text controls in Cocoa) respects Unicode, you will get text without undesired line breaks.
Wikipedia link: http://en.wikipedia.org/wiki/Zero-width_no-break_space

set UITextLayer text to a CATextLayer?

I have a UIAlertView that asks for input and then the input is saved to a UITextField. I then want to be able to set the string of a CATextLayer to the text of the UITextField. I can NSLog the text in the text field to confirm it was set just fine like this:
NSLog (#"name = %#", nameTextField.text);
But if I try to use similar code to set the string of the CATextLayer:
[nameLayer setString:#"%#", nameTextField.text];
I get an error that says "Too many arguments to method call, expected 1, have 2". What do I need to do to set the string in the nameLayer to be the same as the text in the nameTextField?
The problem is that setString: expects one argument any you're sending two: #"%#" and nameTextField.text.
You sould be doing [nameLayer setString:nameTextField.text]; or even nameLayer.string = nameTextField.text;.

Resources