Objective-C Special Index for a string - objective-c

I have a program in Cocoa that I would like to load different texts onto a Textfield. That's not the hard part. The problem I have now is that I have several paragraphs of text. I would like to, like in human language, give each paragraph a name (indexing???). For example, Paragraph1 for the 1st paragraph and Paragraph2 for the 2nd paragraph. Then I would like to call them out by their names. At first I was thinking of setValueForKey but then the "key" is unchangeable since it is a property. Is there any way of doing this? Thanks!

Use NSMutableDictionary
NSMutableDictionary *mParagraphs = [[NSMutableDictionary alloc] initWithObjectsAndKeys:#"1st paragraph ", #"Paragraph1",#"2nd paragraph ",#"Paragraph2",nil];
NSLog(#"%#", [mParagraphs objectForKey:#"Paragraph1"]);

Related

how to insert extra glyphs?

I want to an UITextView to switch between two display modes.
In mode 1 it should show abbreviations and in the full word in mode 2. For example "Abbr." vs "abbreviation".
What would be the best way to do this? Keeping in mind that some words can have the same abbreviation and that the user is free to type either the full word or the abbreviation?
So far I tried to subclass NSLayoutManager.
Assuming I get an abbreviated string and I have to draw the full word, I would implement the following method:
-(void)setGlyphs:(const CGGlyph *)glyphs
properties:(const NSGlyphProperty *)props
characterIndexes:(const NSUInteger *)charIndexes
font:(UIFont *)aFont
forGlyphRange:(NSRange)glyphRange
{
NSUInteger length = glyphRange.length;
NSString *sourceString = #"a very long string as a source of characters for substitution"; //temp.
unichar *characters = malloc(sizeof(unichar) * length+4);
CGGlyph *subGlyphs = malloc(sizeof(CGGlyph) * length+4);
[sourceString getCharacters:characters
range:NSMakeRange(0, length+4)];
CTFontGetGlyphsForCharacters((__bridge CTFontRef)(aFont),
characters,
subGlyphs,
length+4);
[super setGlyphs:subGlyphs
properties:props
characterIndexes:charIndexes
font:aFont
forGlyphRange:NSMakeRange(glyphRange.location, length+4)];
}
However this method complains about invalid glyph indices "_NSGlyphTreeInsertGlyphs invalid char index" when I try to insert 4 additional glyphs.
You're barking way up the wrong tree; trying to subclass NSLayoutManager in this situation is overkill. Your problem is merely one of swapping text stretches (replace abbrev by original or original by abbrev), so just do that - in the text, the underlying NSMutableAttributedString being displayed.
You say in a comment "some words map to the same abbreviation". No problem. Assuming you know the original word (the problem would not be solvable if you did not), store that original word as part of the NSMutableAttributedString, i.e. as an attribute in the place where the word is. Thus, when you substitute the abbreviation, the attribute remains, and thus the original word is retained, ready for you when you need to switch it back.
For example, given this string: #"I love New York" You can hide the word "New York" as an attribute in the same stretch of text occupied by "New York":
[attributedString addAttribute:#"realword" value:#"New York" range:NSMakeRange(7,8)];
Now you can set that range's text to #"NY" but the attribute remains, and you can consult it when the time comes to switch the text back to the unabbreviated form.
(I have drawn out this answer at some length because many people are unaware that you are allowed to define your own arbitrary NSAttributedString attributes. It's an incredibly useful thing to do.)

Turning plain text into NSString

I have a list of words like: hello hi bonjour etc.
I'm literally adding #"" around every word manually. It's not bad, but when you have thousands of words it can get really tedious. Is there a method, where you input a bunch plain text like hello hi and it turns it into: #"hello" #"hi", which I can then copy into code, or do I have to do this manually?
the
be
and
of
a
What I've done in similar cases is use an editor's text replacement feature to replace all blanks with (in your case) " #". You may have to get a bit fancier if you don't have blanks at the start and end of each line, or you have multiple adjacent blanks, etc, but the general technique works.
It sounds like what you want is NSString's componentsSeparatedByString: method. You can enter in a bunch of plain text into some text field or text view, get the raw string, and then push that through "componentsSeparatedByString:#" "" (make sure there's one space in there) and out comes an array of words.
You could try loading the strings from a Plist -- inserting them into code is kind of ugly. Something like [NSDictionary dictionaryWithContentsOfURL:urlToMyPlist] or [NSArray arrayWithContentsOfURL:urlToMyPlist]
Look at the docs for NSString and you'll find the -initWithCharacters:length: method, which you can use to create strings. If you have a string that you want to break up into smaller strings, use -componentsSeparatedByString:.

Syntax for writing strings spread over multiple lines

I have a string in my code and I want it to appear like this:
NSString *string = #"The string
other part of the string is bellow
the last part is in the third line";
That is, in order to make the code more readable, I want to situate the text on several lines. I think I have to write some symbols after the line breaks, but can't remember which ones. What are they? I've searched quite a lot, but I can't a find solution.
NSString *string = #"The string"
"other part of the string is bellow"
"the last part is in the third line";

NSString and NSMutableString concatenation

I have three strings (a NSString, a NSMutableString, and another NSString) which I need to concatenate into a mutable string, in that order, to display as the source for a UIWebView. Comming from a PHP/JavaScript/HTML background, my knowledge of concatenation is pretty much this:
var concatenatedString = string1 + string2 + string3;
I presume that sort of thing won't work in Objective-C, so I'm wondering how to go about pulling them all together properly.
To give a bit of setting for this, the first string (NSString) is the header and canvas element of a web page, the second string (NSMutableString) is javascript from a text field that the user can define to manipulate the canvas element, and the third string (NSString) is the end tags of the web page.
Also, rather than initially creating the NSMutableString, should I just referance the UITextView.text to the get the user's text when concatenating the whole thing, or should I pull the text from the UITextView first?
NSMutableString *concatenatedString = [[NSString stringWithFormat:#"%#%#%#", string1, string2, string3] mutableCopy];
The other two answers are correct in that they answer the question as you asked it. But by your description of what you want to do there is a much easier way. Use a format.
Assuming string1 and string3 will always be the same and only string2 will change,which is what it sounds like you are doing you can write something like this.
static NSString *formatString = #"String1Text%#String3Text";
NSString *completeString = [NSString stringWithFormat:formatString,self.myTextFieldName.text];
NSLog(#"%#",completeString);
The %# in the format says to insert the description of the object following the format.(The description of an NSString is the stringValue.)
Assuming you have a UITextField named myTextFieldName, that currently contains the text 'String2Text' Then this will be the output:
'String1TextString2TextString3Text'
In this way you only create 1 instance of an NSString format for the whole class no matter how many times you call this code.
To me it sounds like you don't need a mutable string at all. Feel free to leave a comment if I misunderstood anything.
Response to comment:
I'm not sure how you are implementing 'moves to test it out again' but, let's say you have a button named 'testJavaScript'. The IBAction method connected to that button would have the first two lines in it. So each time you pushed the button it would make a new formatted NSString filled with the current contents of the textfield. Once this string was formed it could not be changed. But it won't matter since next time it will make another.
NSString *concatenatedString = [string1 stringByAppendingFormat:#"%#%#", string2, string3];
You can make the resulting string mutable (if you really need to) by adding mutableCopy as shown in the answer by #Vinnie.

appendAttributedString: in NSMutableAttributedString

I have an MSMutableAttributedString displayContent.
The attributes of the content vary across the string
i.e. the colours and font sizes can vary by letter.
I want to add a new character to the end of the string and for it to pick up the attributes of the last character in displayContent. I cannot know what those attributes are in advance since they are under user control.
When I append the new character (tempAttr):
NSAttributedString * tempAttr = [[NSAttributedString alloc] initWithString:appendage];
[displayContent appendAttributedString:tempAttr];
it appears to reset the attributes of the whole string to the attributes of the new character (which I haven't set since I can't know what they need to be).
How do I get tempAttr to pick up the attributes of the last character in displayContent?
Thanks.
Update.
Made progress on this in a clumsy but functional way.
Copy the attributes dictionary from the last character in the display (displayContent) and then reapply those attributes to the new character being added:
NSMutableDictionary * lastCharAttrs = [NSMutableDictionary dictionaryWithCapacity:5];
[lastCharAttrs addEntriesFromDictionary: [displayContent attributesAtIndex:0
effectiveRange:NULL]]; // get style of last letter
NSMutableAttributedString * tempAttr = [[NSMutableAttributedString alloc] initWithString:newCharacter
attributes:lastCharAttrs];
[displayContent appendAttributedString:tempAttr]; // Append to content in the display field
I would have hoped there was a more elegant way to do this like setting a property of the NSTextField.
I think I discovered a solution to this by accident, then found this page while looking for the answer to the problem I created for myself (the opposite of your issue).
If you do the following:
[[displayContent mutableString] appendString:newCharacter];
You'll end up with newCharacter appended and the previous attributes "stretched" to cover it. I cannot find this behavior documented anywhere, however, so you might be weary of counting on it.