AVSpeechSynthesizer going crazy with textView selectedRange - objective-c

I'm trying to have the AVSpeechSynthesizer read the user's text selection in a UITextView. It works quite well when I double-tap a word but whenever I try to select more than one word, the AVSpeechSynthesizer starts speaking words in a weird way. Is there a way to prevent this behaviour or to retrieve the user's text selection only when they release the selecting finger ?
Any help would be greatly appreciated.
Here is what I do :
-(void) textViewDidChangeSelection:(UITextView *)textView{
NSRange r = textView.selectedRange;
if (!(r.length == 0)) {
NSString *selText = [self.entryTextField2.text substringWithRange:r];
AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:selText];
[utterance setRate:0.5f];
utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:self.selectedSpeakerLanguage];
[self.synthesizer speakUtterance:utterance];
}
}

I think I should have done it the Apple way from the start or at least the IOS way. Reading the selectedRange directly from textViewDidChangeSelection: is definitely not a good idea. You need to use a [UIMenuController sharedMenuController] to present a UIMenuItem that triggers the readSelection method instead.

Related

Run TTS in NSArray sequentially

I have NSArray with words in it.
I want to app reads that tts sequentially and print the text in UILabel what app speak.
but word on label is shown the last one.
I tried time pause, etc
for (Word * w in ttswords) {
[self speechword:w];
}
-(void)speechword:(Word*)w{
utterance = [[AVSpeechUtterance alloc] initWithString:[w.title stringByReplacingOccurrencesOfString:#"~" withString:#""]];
utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:#"en-US"];
[synthesizer speakUtterance:utterance];
_lb_title.text = w.title;
}
I want to execute one by one.
The best way to highlight the vocalized word is using the speechSynthesizer:willSpeakRangeOfSpeechString:utterance: method of the AVSpeechSynthesizerDelegate protocol.
If you don't use this delegate method, you won't be able to reach your goal.
Take a look at this complete and useful example (ObjC and Swift) that displays each vocalized word in a bold font with the speech synthesis.

Resetting the search query string in UISearchController programmatically

I am failing to reset/substitute the search query string programmatically. I was trying to modify the UISearchBar query string from within the UISearchControllerDelegate.
I am using dictation input.
When the command "delete" is said, the searchController.searchBar.text should be set back to #"". The speech detection should continue as normal with the empty string.
The query string does get reset to #"", but the speech detection stops.
How can I reset search query string in UISearchController programmatically and still be able to continue the input using speech?
- (void)updateSearchResultsForSearchController:(nonnull UISearchController *)searchController {
NSString *searchQuery = self.searchController.searchBar.text;
// Deletion command
if ([self.searchController.searchBar.text hasSuffix:#"delete"]) {
// Things that I've tried that don't work
//[self.searchController.searchBar setText:#""];
//self.searchController = [self.searchController init];
//self.searchController.searchBar.text = #"";
searchQuery = #"";
}
}
This feature is yet not available in iOS. As soon as you try to clear the text in searchBar's TextField, it change the keyboard mode to keypad input.
So, the conclusion is, you can only provide the input to the textField using the dictation but can't clear it. User has to manually do the process to change again to Dictation Input.
Hope it helps.

Parse Issue: Expected Expression (Objective C)

For what ever reason my xcode has decided it doesn't like me... I'm getting the error stated in the title on this line
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
NSInteger row = [_tableView selectedRow];
if (row == –1) //<---- this line
{
return;
}
NSString *selectedVoice = [_voices objectAtIndex:row];
[_speechSynth setVoice:selectedVoice];
NSLog(#"new voice = %#", selectedVoice);
}
I do believe that it has something to do with _tableView being befuddled because when I attempted to get the IDE to help me to type (you know when it guesses what you might what to finish your word with by doing an API lookup of available functions) it doesn't show selectedRow as a possibility :(
incase it's needed i've put the .m and .h in a pastebin to save some space on your screens... FYI I'm following the Coca Programming for Mac OSX fourth Edition chapter 6.10
In your line
if (row == –1)
the minus-sign is not the real minus-sign, but an "EN DASH" (Unicode U+2013). Perhaps you accidentally pressed the option-key together with the minus-key when typing that code.
Replacing that character with a minus-sign fixes the problem.
UITableView doesn't have a method called selectedRow.
Perhaps you should be using:
- (NSIndexPath *)indexPathForSelectedRow

Need a view that acts like a log view

I need to implement a view that acts as a log view, so that when you push a message into it, the message would push other messages upwards.
Is there anything like that for iOS?
You can easily implement that using standard UITableView:
Each cell will be responsible for displaying 1 log message
Add new cell to the end of the table when new message arrive
Scroll table to the bottom after cell is added (using scrollToRowAtIndexPath:atScrollPosition:animated: method with UITableViewScrollPositionBottom position parameter)
That means you'll need to store your log messages in array, but if you're going to display them you need to store messages anyway
#Vladimir's answer is probably the way to go, but just for the sake of seeing some additional options, here's an example using a UITextView:
- (IBAction)addNewLog:(UIButton *)sender {
NSString *myInputText = #"some new text from string";
NSString *temp = myTextView.text;
[myTextView setText:[temp stringByAppendingString:[NSString stringWithFormat:#"\n%#: %#",[NSDate date],myInputText]]];
[myTextView setContentOffset:CGPointMake(0, myTextView.contentSize.height - myTextView.frame.size.height) animated:NO];
}
Then if you wanted to separate the text in the text view into objects in an array:
NSArray *myAwesomeArray = [myTextView.text componentsSeparatedByString:#"\n"];
Mind you, the above would break if the "myInputText" string ever contained a line break.

Xcode Like log with NSTextView

I'm trying to set up a NSTextView like the console in Xcode (or pretty much any other IDE available). That being the user cannot edit the NSTextView, however they can put in a character when appropriate, I'm trying to set up that same functionality. No clue how to go about it. Any ideas?
You could simply make an action that appends a formatted string containing a line break, a time stamp, and your desired text to the text view. Here's an example:
- (void)addToLog:(NSString *)input
{
[[self.myTextView textStorage] appendAttributedString:[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:#"\n%#: %#",[NSDate date],input]]];
}
So then instead of using NSLog(#"some text"); you could call [self addToLog:#"some text"]; and it would be added to a new line in your text view.