Sending WatchKit Voice recognition's text to another interface controller - objective-c

I am having an issue sending dictated text to another interface controller.
Here is my code:
- (IBAction)voiceRecognition {
[self presentTextInputControllerWithSuggestions:nil allowedInputMode:WKTextInputModePlain completion:^(NSArray *results) {
NSLog(#"results: %#", results);
NSString *wordKey = [NSString stringWithFormat:#"%#",results];
NSDictionary *dict = #{#"kWord":wordKey};
[self pushControllerWithName:#"Dictionary" context:dict];
}];
}
Logs:
Watch Extension[3185:2835671] results: ( Hello )
Getting data from other Interface controller:
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
NSDictionary *dict = (NSDictionary *)context;
[_word setText:dict[#"kWord"]];
NSLog(#"The Word is %#",[dict description]);
}
Logs:
Watch Extension[3185:2835671] The Word is {
kWord = "(\n Hello\n)";
}
Here is a screen shot that shows my problem:
The ( is supposed to show the word Hello. How can I fix this issue?

You used stringWithFormat to format an array as a string.
This took ["Hello"] and correctly converted it to the literal "(\n Hello\n)"
Because that string has a newline, it can't be displayed on a single line. Your Storyboard WKInterfaceLabel number of lines is likely set to 1, so it would only show the first line, which is (.
How can you fix this?
If you're only interested in the first word, use results.firstObject and pass that single word as the string value for your kWord key.
NSDictionary *dict = #{#"kWord": results.firstObject};
Otherwise, pass the entire array as the value, and have the destination interface controller handle the array of results as needed.
NSDictionary *dict = #{#"kWord": results};
You also may want to change the number of lines to show the entire dictation text, to handle the case where the text wouldn't fit on a single line.
Other options:
If you actually intended to send the dictated text as a single string of words, you can use
NSString *wordKey = [results componentsJoinedByString:#" "]

Related

Making a simple quiz game. Stuck with the arrays part

I'm trying to make a game with 2 views, the first view has buttons which segues to another view. Depending on the segue identifier, it loads an image which the player has to guess.
I also have a an array which lists hints for the 4 images.
With the array, i made a button which shows the hints on the view, but the problem I have right now is that I don't know how to set the correct array to the image/puzzle.
A code that works right now is this:
if ([self.thePuzzle.name isEqual: #"lion"])
{
NSArray *hints = [lines[0] componentsSeparatedByString:#" "];
self.hintLabel.text = hints[0];
}
But after adding another line for the second image/puzzle, the app crashes.
2nd UPDATE: code that crashes
After entering this code
if ([self.thePuzzle.name isEqual: #"penguin"])
{
NSArray *hints = [lines[1] componentsSeparatedByString:#" "];
self.hintLabel.text = hints[1];
}
The hint button works for the 1st code, which has the lion picture, while the second part of the code, for the penguin pic, crashes when the Hint button is pressed.
3rd Update: Additional information
I made xcode access a file from the internet which contained the words for my array.
This is how i coded it.
[super viewDidLoad];
// Do any additional setup after loading the view.
self.imageView.image = [UIImage imageNamed:self.thePuzzle.imgFileName];
NSString *urlString = #"http://m.uploadedit.com/b032/1395295852132.txt";
NSString *contents = [TextFileManager readStringFromURL:urlString];
//parse contents
lines = [contents componentsSeparatedByString:#"\n"];
for( int i = 0; i < lines.count; i++)
{
NSString *line = lines[i];
NSLog(#"%d: %#", i, line);
}

Replacing bad words in a string in Objective-C

I have a game with a public highscore list where I allow layers to enter their name (or anything unto 12 characters). I am trying to create a couple of functions to filter out bad words from a list of bad words
I have in a text file. I have two methods:
One to read in the text file:
-(void) getTheBadWordsAndSaveForLater {
badWordsFilePath = [[NSBundle mainBundle] pathForResource:#"badwords" ofType:#"txt"];
badWordFile = [[NSString alloc] initWithContentsOfFile:badWordsFilePath encoding:NSUTF8StringEncoding error:nil];
badwords =[[NSArray alloc] initWithContentsOfFile:badWordFile];
badwords = [badWordFile componentsSeparatedByString:#"\n"];
NSLog(#"Number Of Words Found in file: %i",[badwords count]);
for (NSString* words in badwords) {
NSLog(#"Word in Array----- %#",words);
}
}
And one to check a word (NSString*) agains the list that I read in:
-(NSString *) removeBadWords :(NSString *) string {
// If I hard code this line below, it works....
// *****************************************************************************
//badwords =[[NSMutableArray alloc] initWithObjects:#"shet",#"shat",#"shut",nil];
// *****************************************************************************
NSLog(#"checking: %#",string);
for (NSString* words in badwords) {
string = [string stringByReplacingOccurrencesOfString:words withString:#"-" options:NSCaseInsensitiveSearch range:NSMakeRange(0, string.length)];
NSLog(#"Word in Array: %#",words);
}
NSLog(#"Cleaned Word Returned: %#",string);
return string;
}
The issue I'm having is that when I hardcode the words into an array (see commented out above) then it works like a charm. But when I use the array I read in with the first method, it does't work - the stringByReplacingOccurrencesOfString:words does not seem to have an effect. I have traced out to the log so I can see if the words are coming thru and they are... That one line just doesn't seem to see the words unless I hardcore into the array.
Any suggestions?
A couple of thoughts:
You have two lines:
badwords =[[NSArray alloc] initWithContentsOfFile:badWordFile];
badwords = [badWordFile componentsSeparatedByString:#"\n"];
There's no point in doing that initWithContentsOfFile if you're just going to replace it with the componentsSeparatedByString on the next line. Plus, initWithContentsOfFile assumes the file is a property list (plist), but the rest of your code clearly assumes it's a newline separated text file. Personally, I would have used the plist format (it obviates the need to trim the whitespace from the individual words), but you can use whichever you prefer. But use one or the other, but not both.
If you're staying with the newline separated list of bad words, then just get rid of that line that says initWithContentsOfFile, you disregard the results of that, anyway. Thus:
- (void)getTheBadWordsAndSaveForLater {
// these should be local variables, so get rid of your instance variables of the same name
NSString *badWordsFilePath = [[NSBundle mainBundle] pathForResource:#"badwords" ofType:#"txt"];
NSString *badWordFile = [[NSString alloc] initWithContentsOfFile:badWordsFilePath encoding:NSUTF8StringEncoding error:nil];
// calculate `badwords` solely from `componentsSeparatedByString`, not `initWithContentsOfFile`
badwords = [badWordFile componentsSeparatedByString:#"\n"];
// confirm what we got
NSLog(#"Found %i words: %#", [badwords count], badwords);
}
You might want to look for whole word occurrences only, rather than just the presence of the bad word anywhere:
- (NSString *) removeBadWords:(NSString *) string {
NSLog(#"checking: %# for occurrences of these bad words: %#", string, badwords);
for (NSString* badword in badwords) {
NSString *searchString = [NSString stringWithFormat:#"\\b%#\\b", badword];
string = [string stringByReplacingOccurrencesOfString:searchString
withString:#"-"
options:NSCaseInsensitiveSearch | NSRegularExpressionSearch
range:NSMakeRange(0, string.length)];
}
NSLog(#"resulted in: %#", string);
return string;
}
This uses a "regular expression" search, where \b stands for "a boundary between words". Thus, \bhell\b (or, because backslashes have to be quoted in a NSString literal, that's #"\\bhell\\b") will search for the word "hell" that is a separate word, but won't match "hello", for example.
Note, above, I am also logging badwords to see if that variable was reset somehow. That's the only thing that would make sense given the symptoms you describe, namely that the loading of the bad words from the text file works but replace process fails. So examine badwords before you replace and make sure it's still set properly.

App Store ID via Appirater different than ID from plist, and apparently random

I'm having an issue with grabbing the App Store ID from my plist, and using it with Appirater. I NSLogged the URL that was being used when the user pushes "Rate Now", and the App Store ID is way different from the App Store ID I set in Info.plist. No idea where it is getting these numbers from -- they are a different set of 9 numbers each time. This is really strange.
The code in Appirater.m that deals with grabbing the App Store ID and using it in the link looks like this: NSString *const kAppiraterAppIdBundleKey = #"AppStoreId";
NSString *templateReviewURL = #"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=APP_ID";
....
+ (NSString*)appStoreAppID {
NSString* value = [[[NSBundle mainBundle] infoDictionary] objectForKey:kAppiraterAppIdBundleKey];
NSAssert1(value, #"Error - you have not specified %# property in your info.plist", kAppiraterAppIdBundleKey);
return value;
}
//...
+ (void)rateApp {
//...
NSString *reviewURL = [templateReviewURL stringByReplacingOccurrencesOfString:#"APP_ID" withString:[NSString stringWithFormat:#"%d", [self appStoreAppID]]];
//...
}
I added a field in the plist called "AppStoreId", and entered the 9 digit code. I made it a string type. Now, the code runs perfectly when I replace "APP_ID" with the actual 9 digit code in that iTunes link above, but when I keep it as APP_ID, I get the error "Cannot connect to the iTunes Store.", and the NSLog output has 9 random numbers in the link, and again, they are different each time.
This is probably an easy fix, but I can't seem to figure it out.
Random numbers? You're using:
[NSString stringWithFormat:#"%d", [self appStoreAppID]]
where appStoreAppID is an NSString.
So you're replacing "APP_ID" with the pointer to the NSString, not the contents of the NSString.
Just use %# instead of %d.

Is there a way to get Spell Check data from an NSString?

I'm writing a simple shift cipher iPhone app as a pet project, and one piece of functionality I'm currently designing is a "universal" decryption of an NSString, that returns an NSArray, all of NSStrings:
- (NSArray*) decryptString: (NSString*)ciphertext{
NSMutableArray* theDecryptions = [NSMutableArray arrayWithCapacity:ALPHABET];
for (int i = 0; i < ALPHABET; ++i) {
NSString* theNewPlainText = [self decryptString:ciphertext ForShift:i];
[theDecryptions insertObject:theNewPlainText
atIndex:i];
}
return theDecryptions;
}
I'd really like to pass this NSArray into another method that attempts to spell check each individual string within the array, and builds a new array that puts the strings with the fewest typo'd words at lower indicies, so they're displayed first. I'd like to use the system's dictionary like a text field would, so I can match against words that have been trained into the phone by its user.
My current guess is to split a given string up into words, then spell check each with NSSpellChecker's -checkSpellingOfString:StartingAt: and using the number of correct words to sort the Array. Is there an existing library method or well-accepted pattern that would help return such a value for a given string?
Well, I found a solution that works using UIKit/UITextChecker. It correctly finds the user's most preferred language dictionary, but I'm not sure if it includes learned words in the actual rangeOfMisspelledWords... method. If it doesn't, calling [UITextChecker hasLearnedWord] on currentWord inside the bottom if statement should be enough to find user-taught words.
As noted in the comments, it may be prudent to call rangeOfMisspelledWords with each of the top few languages in [UITextChecker availableLanguages], to help multilingual users.
-(void) checkForDefinedWords {
NSArray* words = [message componentsSeparatedByString:#" "];
NSInteger wordsFound = 0;
UITextChecker* checker = [[UITextChecker alloc] init];
//get the first language in the checker's memory- this is the user's
//preferred language.
//TODO: May want to search with every language (or top few) in the array
NSString* preferredLang = [[UITextChecker availableLanguages] objectAtIndex:0];
//for each word in the array, determine whether it is a valid word
for(NSString* currentWord in words){
NSRange range;
range = [checker rangeOfMisspelledWordInString:currentWord
range:NSMakeRange(0, [currentWord length])
startingAt:0
wrap:NO
language:preferredLang];
//if it is valid (no errors found), increment wordsFound
if (range.location == NSNotFound) {
//NSLog(#"%# %#", #"Valid Word found:", currentWord);
wordsFound++;
}
else {
//NSLog(#"%# %#", #"Invalid Word found:", currentWord);
}
}
//After all "words" have been searched, save wordsFound to validWordCount
[self setValidWordCount:wordsFound];
[checker release];
}

How to change this so that it returns arrays

The following code works perfectly and shows the correct output:
- (void)viewDidLoad {
[super viewDidLoad];
[self expand_combinations:#"abcd" arg2:#"" arg3:3];
}
-(void) expand_combinations: (NSString *) remaining_string arg2:(NSString *)s arg3:(int) remain_depth
{
if(remain_depth==0)
{
printf("%s\n",[s UTF8String]);
return;
}
NSString *str = [[NSString alloc] initWithString:s];
for(int k=0; k < [remaining_string length]; ++k)
{
str = [s stringByAppendingString:[[remaining_string substringFromIndex:k] substringToIndex:1]];
[self expand_combinations:[remaining_string substringFromIndex:k+1] arg2:str arg3:remain_depth - 1];
}
return;
}
However, instead of outputting the results, I want to return them to an NSArray. How can this code be changed to do that? I need to use the information that this function generates in other parts of my program.
There are several things that you need to change in your code.
First - consider changing the name of your method to something more legible and meaningful than -expand_combinations:arg2:arg3.
Second - you have a memory leak. You don't need to set allocate memory and initialize str with the string s, because you change its value right away in the loop without releasing the old value.
Third - take a look at NSMutableArray. At the beginning of the method, create an array with [NSMutableArray array], and at every line that you have printf, instead, add the string to the array. Then return it.
basicaly you have:
create mutable array in viewDidLoad before [self expand_combinations ...
add aditional parameter (mutable array) to expand_combinations
populate array in expand_combinations