Xcode Like log with NSTextView - objective-c

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.

Related

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.

AVSpeechSynthesizer going crazy with textView selectedRange

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.

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.

Change text of a label

I have a array that reads a .txt file and when you click a button the label changes in one of the words of the .txt file, but the label doen't change.
This is the code:
if(sender == self.button) {
NSArray *words = [[NSArray alloc] initWithObjects:#"words.txt", nil];
[randomLabel setText:[words objectAtIndex:random() % [words count]]];
}
What should I do so the label changes when I press the button?
What file do I use?
A few things here:
Reading in file into an array
Well, for starters you're not reading in the contents of the .txt file.
NSArray *words = [[NSArray alloc] initWithObjects:#"words.txt", nil];
This creates a 1 element array, with that one element being #"words.txt". I don't know the format of your .txt file, so I can't say for sure how you have to load it in. See How do I format a text file to be read in using arrayWithContentsOfFile on how to potentially do this.
Setting button text
Also, you need to make sure randomLabel actually refers to the label contained within the button, otherwise the button text won't change. Typically for a button, you'd change the title using the method:
- (void)setTitle:(NSString *)title forState:(UIControlState)state
So in your instance, it'd be:
NSString* newTitle = [words objectAtIndex:random() % [words count]];
[self.button setTitle:newTitle forState:UIControlStateNormal];
Is the code actually being called?
Double check that sender == self.button evaluates to true (for readability and clarity, I'd use [sender isEqual:self.button]). Use the debugger to step through the code, to see if that particular piece of code is being called. See http://mobile.tutsplus.com/tutorials/iphone/xcode-debugging_iphone-sdk/ on how to achieve this.
You should try using
(id)initWithContentsOfFile:(NSString *)aPath

Drag file from NSTableView to other osx application

I want to drag a file from a NSTableView row to copy it to another application (i.e. Finder). I implemented the first two steps ('Configuring Your Table View', 'Beginning a Drag Operation') of this guide and thought that would do the trick:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/TableView/Tasks/UsingDragAndDrop.html
However, when I attempt to drag a row, the row text follows my mouse but the file does not copy when released. Here's what I'm sending to my UITableView upon initialization:
#define librarySongDataType #"NSFileContentsPboardType"
- (void)awakeFromNib
{
[self setDraggingSourceOperationMask:NSUIntegerMax forLocal:YES]; // allow interapplication drags
[self registerForDraggedTypes:[NSArray arrayWithObject:librarySongDataType] ]; // NSFileContentsPboardType
}
Here's how I'm handling the drag in my NSTableView's data source (an NSArrayController):
- (BOOL)tableView:(NSTableView *)aTableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard
{
NSLog(#"writeRowsWithIndexes");
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];
[pboard setData:data forType:librarySongDataType];
return YES;
}
To be clear, I'm not trying to drag files into my table view, I'm just trying to drag file(s) out of it.
Firstly, which document did you refer to when you wrote this line ?
[self setDraggingSourceOperationMask:NSUIntegerMax forLocal:YES];
This doesn't make sense. Don't use NSUIntegerMax. Use operation masks as defined here. It's written there that NSUIntegerMax stands for everything, but you shouldn't use it; Apple may re-define the bit in the future. You should use NSDragOperationCopy or something specific. If you copied that line from a webpage or a book, you should stop trusting that book/webpage.
Secondly, forLocal: should be NO to pass the data to another application; local here means application local.
Third, instead of just setting the archived data in
[pboard setData:data forType:librarySongDataType];
Consider making an NSFileWrapper and set it using writeFileWrapper:, see here. That way you can specify the file name to be created in Finder. Otherwise, the system doesn't have any idea what the data represent.