Loop not running completely on iPad (Fine on simulator) - objective-c

I am working on an ARC based project. I am obtaining text from a large text file and need to remove white spaces or newline characters from it. The following code works fine on the simulator but crashes on an iPad and doesn't run completely (this may be a memory issues). For example if the loop needs to be run 2000 times, it crashes after running 1800 times on iPad.
- (BOOL)formatTheText {
NSString *content = [NSString stringWithContentsOfURL:_textFileURL
encoding:NSUTF8StringEncoding
error:NULL];
NSRange paraRange = {0,1};
NSString *modifiedContent = #"";
BOOL previousLineWasEmpty = NO;
int lineNumber = 0;
while (paraRange.location < [content length]) {
NSRange currentParaRange = [content paragraphRangeForRange:paraRange];
NSString *paragraph = [content substringWithRange:currentParaRange];
NSCharacterSet *newLineSet = [NSCharacterSet newlineCharacterSet];
NSArray *array = [paragraph componentsSeparatedByCharactersInSet:newLineSet];
NSString *currentParagraph = #"";
for (NSString *line in array) {
currentParagraph = [currentParagraph stringByAppendingString:line];
}
// Add a space when combining two lines
modifiedContent = [modifiedContent stringByAppendingFormat:#"%# ",currentParagraph];
paraRange.location += currentParaRange.length;
if ([currentParagraph length] == 0) {
// If previous line was empty just add a new line character
if (previousLineWasEmpty) {
modifiedContent = [modifiedContent stringByAppendingString:#"\n"];
} else {
// Add two lines for the start of a new paragraph
modifiedContent = [modifiedContent stringByAppendingString:#"\n\n"];
}
previousLineWasEmpty = YES;
} else {
previousLineWasEmpty = NO;
}
lineNumber++;
}
self.cleanedString = modifiedContent;
return YES;
}

Related

NSString writeToFile losing Indentation

I have an OSX application that creates Objective-C code. In other words, writes to two files, .h and .m.
To write to a file, I am using NSString writeToFile atomically true, encoding NSUTF8StringEncoding.
Although my two files are created with the text correctly, all formatting is lost. Everything ends up aligned to the left, even when imported into Xcode. Although I know I can select the text and indent it using ctrl + i, this is not the solution I want.
Now, when I copy the NSString to the clipboard, and paste it into Xcode, the formatting stays how it should.
Does anyone know a way where I can keep the text indentation the way it was in Xcode without having to write rules about how many curly braces are open? Here is some modified example code of what I am doing so far:
NSString *code = #"for (int i = 0; i < 10; i++) {\n";
code = [code stringByAppendingString:#"NSLog(#\"HelloWorld\");\n"];
code = [code stringByAppendingString:#"}\n"];
// If I run the two lines below, then my NSString is copied to the clipboard. When I paste into Xcode, formatting stays as it should.
[[NSPasteboard generalPasteboard] clearContents];
[[NSPasteboard generalPasteboard] setString:code forType:NSStringPboardType];
// If I run the code below instead, then two files are created. But they do not keep the formatting.
NSSavePanel *panel = [NSSavePanel savePanel];
[panel setNameFieldStringValue:#"MyClass"];
[panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) {
if (result == NSFileHandlingPanelOKButton) {
NSError *errorH = nil;
NSError *errorM = nil;
NSString *pathH = [[[panel URL] path] stringByAppendingString:#".h"];
NSString *pathM = [[[panel URL] path] stringByAppendingString:#".m"];
[code writeToFile:pathH atomically:true encoding:NSUTF8StringEncoding error:&errorH];
[code writeToFile:pathM atomically:true encoding:NSUTF8StringEncoding error:&errorM];
if (!errorH && !errorM) {
NSLog(#"Success");
} else {
NSLog(#"Error Saving Files");
}
}
}];
EDIT: After not getting a clear way to do this elegantly, I simply had to write some of my own formatting code to mimic the formatting done by Xcode. It doesn't work 100% properly... for instance, when I am adding multiple items to an array using:
#[#"string1",
#"string2",
#"string3"];\n
This doesn't stay properly indented to where the array began. And I'm sure there are other cases that my code doesn't handle. Not a huge deal though. If a solution comes to mind later, I can implement it. But for now, the formatting simply won't be as pretty as intended. Here is a method, and a helper method, that anyone can use to implement similar functionality (handles tabs and curly braces only)
- (NSString *) formatWithIdentationForExport : (NSString *) theString {
NSString *s = #"";
NSMutableArray *fileLines = [[NSMutableArray alloc] initWithArray:[theString componentsSeparatedByString:#"\n"] copyItems: YES];
int numberOfCurlyBraces = 0;
for (int i = 0; i < fileLines.count; i++) {
NSString *currentLine = fileLines[i];
int numberOfOpenBracesInLine = [self getNumberOfOccurancesOf:#"{" inString:currentLine];
int numberOfCloseBracesInLine = [self getNumberOfOccurancesOf:#"}" inString:currentLine];
numberOfCurlyBraces -= numberOfCloseBracesInLine;
for (int j = 0; j < numberOfCurlyBraces; j++) {
currentLine = [NSString stringWithFormat:#"\t%#", currentLine];
}
currentLine = [currentLine stringByAppendingString:#"\n"];
s = [s stringByAppendingString:currentLine];
numberOfCurlyBraces += numberOfOpenBracesInLine;
}
return s;
}
- (int) getNumberOfOccurancesOf : (NSString *) substring inString : (NSString *) str {
int count = 0, length = (int)[str length];
NSRange range = NSMakeRange(0, length);
while(range.location != NSNotFound) {
range = [str rangeOfString:substring options:0 range:range];
if(range.location != NSNotFound) {
range = NSMakeRange(range.location + range.length, length - (range.location + range.length));
count++;
}
}
return count;
}
Use "\t" for an indent. I won't do it for every line of your code, but do something like
[[NSMutableString alloc] initWithString:#"for (int i = 0; i < 10; i++) {\n"];
[codeStr appendString:#"\t"];[codeStr appendString:#"NSLog(#\"center\");"];
When you generate your ObjC code, you should manually add indentation (tabs or spaces) into it, otherwise it will not be saved to file.

Check if NSString contains all or some characters

I have an NSString called query which contains ~10 characters.
I would like to check to see if a second NSString called word contains all of the characters in query, or some characters, but no other characters which aren't specified in query.
Also, if there is only one occurrence of the character in the query, there can only be one occurrence of the character in the word.
Please could you tell me how to do this?
NSString *query = #"ABCDEFJAKSUSHFKLAFIE";
NSString *word = #"fearing"; //would pass as NO as there is no 'n' in the query var.
The following answers the first half:
NSCharacterSet *nonQueryChars = [[NSCharacterSet characterSetWithCharactersInString:[query lowercaseString]] invertedSet];
NSRange badCharRange = [[word lowercaseString] rangeOfCharacterFromSet:nonQueryChars];
if (badCharRange.location == NSNotFound) {
// word only has characters in query
} else {
// found unwanted characters in word
}
I need to think about the second half of the requirement.
Ok, the following code should fulfill both requirements:
- (NSCountedSet *)wordLetters:(NSString *)text {
NSCountedSet *res = [NSCountedSet set];
for (NSUInteger i = 0; i < text.length; i++) {
[res addObject:[text substringWithRange:NSMakeRange(i, 1)]];
}
return res;
}
- (void)checkWordAgainstQuery {
NSString *query = #"ABCDEFJAKSUSHFKLAFIE";
NSString *word = #"fearing";
NSCountedSet *queryLetters = [self wordLetters:[query lowercaseString]];
NSCountedSet *wordLetters = [self wordLetters:[word lowercaseString]];
BOOL ok = YES;
for (NSString *wordLetter in wordLetters) {
int wordCount = [wordLetters countForObject:wordLetter];
// queryCount will be 0 if this word letter isn't in query
int queryCount = [queryLetters countForObject:wordLetter];
if (wordCount > queryCount) {
ok = NO;
break;
}
}
if (ok) {
// word matches against query
} else {
// word has extra letter or too many of a matching letter
}
}

How can I optimise out this nested for loop?

How can I optimise out this nested for loop?
The program should go through each word in the array created from the word text file, and if it's greater than 8 characters, add it to the goodWords array. But the caveat is that I only want the root word to be in the goodWords array, for example:
If greet is added to the array, I don't want greets or greetings or greeters, etc.
NSString *string = [NSString stringWithContentsOfFile:#"/Users/james/dev/WordParser/word.txt" encoding:NSUTF8StringEncoding error:NULL];
NSArray *words = [string componentsSeparatedByString:#"\r\n"];
NSMutableArray *goodWords = [NSMutableArray array];
BOOL shouldAddToGoodWords = YES;
for (NSString *word in words)
{
NSLog(#"Word: %#", word);
if ([word length] > 8)
{
NSLog(#"Word is greater than 8");
for (NSString *existingWord in [goodWords reverseObjectEnumerator])
{
NSLog(#"Existing Word: %#", existingWord);
if ([word rangeOfString:existingWord].location != NSNotFound)
{
NSLog(#"Not adding...");
shouldAddToGoodWords = NO;
break;
}
}
if (shouldAddToGoodWords)
{
NSLog(#"Adding word: %#", word);
[goodWords addObject:word];
}
}
shouldAddToGoodWords = YES;
}
How about something like this?
//load the words from wherever
NSString * allWords = [NSString stringWithContentsOfFile:#"/usr/share/dict/words"];
//create a mutable array of the words
NSMutableArray * words = [[allWords componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] mutableCopy];
//remove any words that are shorter than 8 characters
[words filterUsingPredicate:[NSPredicate predicateWithFormat:#"length >= 8"]];
//sort the words in ascending order
[words sortUsingSelector:#selector(caseInsensitiveCompare:)];
//create a set of indexes (these will be the non-root words)
NSMutableIndexSet * badIndexes = [NSMutableIndexSet indexSet];
//remember our current root word
NSString * currentRoot = nil;
NSUInteger count = [words count];
//loop through the words
for (NSUInteger i = 0; i < count; ++i) {
NSString * word = [words objectAtIndex:i];
if (currentRoot == nil) {
//base case
currentRoot = word;
} else if ([word hasPrefix:currentRoot]) {
//word is a non-root word. remember this index to remove it later
[badIndexes addIndex:i];
} else {
//no match. this word is our new root
currentRoot = word;
}
}
//remove the non-root words
[words removeObjectsAtIndexes:badIndexes];
NSLog(#"%#", words);
[words release];
This runs very very quickly on my machine (2.8GHz MBP).
A Trie seems suitable for your purpose. It is like a hash, and is useful for detecting if a given string is a prefix of an already seen string.
I used an NSSet to ensure that you only have 1 copy of a word added at a time. It will add a word if the NSSet does not already contain it. It then checks to see if the new word is a substring for any word that has already been added, if true then it won't add the new word. It's case-insensitive as well.
What I've written is a refactoring of your code. It's probably not that much faster but you really do want a tree data structure if you want to make it a lot faster when you want to search for words that have already been added to your tree.
Take a look at RedBlack Trees or B-Trees.
Words.txt
objective
objectively
cappucin
cappucino
cappucine
programme
programmer
programmatic
programmatically
Source Code
- (void)addRootWords {
NSString *textFile = [[NSBundle mainBundle] pathForResource:#"words" ofType:#"txt"];
NSString *string = [NSString stringWithContentsOfFile:textFile encoding:NSUTF8StringEncoding error:NULL];
NSArray *wordFile = [string componentsSeparatedByString:#"\n"];
NSMutableSet *goodWords = [[NSMutableSet alloc] init];
for (NSString *newWord in wordFile)
{
NSLog(#"Word: %#", newWord);
if ([newWord length] > 8)
{
NSLog(#"Word '%#' contains 8 or more characters", newWord);
BOOL shouldAddWord = NO;
if ( [goodWords containsObject:newWord] == NO) {
shouldAddWord = YES;
}
for (NSString *existingWord in goodWords)
{
NSRange textRange = [[newWord lowercaseString] rangeOfString:[existingWord lowercaseString]];
if( textRange.location != NSNotFound ) {
// newWord contains the a substring of existingWord
shouldAddWord = NO;
break;
}
NSLog(#"(word:%#) does not contain (substring:%#)", newWord, existingWord);
shouldAddWord = YES;
}
if (shouldAddWord) {
NSLog(#"Adding word: %#", newWord);
[goodWords addObject:newWord];
}
}
}
NSLog(#"***Added words***");
int count = 1;
for (NSString *word in goodWords) {
NSLog(#"%d: %#", count, word);
count++;
}
[goodWords release];
}
Output:
***Added words***
1: cappucino
2: programme
3: objective
4: programmatic
5: cappucine

CamelCase to underscores and back in Objective-C

I'm looking for a simple, efficient way to convert strings in CamelCase to underscore notation (i.e., MyClassName -> my_class_name) and back again in Objective C.
My current solution involves lots of rangeOfString, characterAtIndex, and replaceCharactersInRange operations on NSMutableStrings, and is just plain ugly as hell :) It seems that there must be a better solution, but I'm not sure what it is.
I'd rather not import a regex library just for this one use case, though that is an option if all else fails.
Chris's suggestion of RegexKitLite is good. It's an excellent toolkit, but this could be done pretty easily with NSScanner. Use -scanCharactersFromSet:intoString: alternating between +uppercaseLetterCharacterSet and +lowercaseLetterCharacterSet. For going back, you'd use -scanUpToCharactersFromSet: instead, using a character set with just an underscore in it.
How about these:
NSString *MyCamelCaseToUnderscores(NSString *input) {
NSMutableString *output = [NSMutableString string];
NSCharacterSet *uppercase = [NSCharacterSet uppercaseLetterCharacterSet];
for (NSInteger idx = 0; idx < [input length]; idx += 1) {
unichar c = [input characterAtIndex:idx];
if ([uppercase characterIsMember:c]) {
[output appendFormat:#"_%#", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
} else {
[output appendFormat:#"%C", c];
}
}
return output;
}
NSString *MyUnderscoresToCamelCase(NSString *underscores) {
NSMutableString *output = [NSMutableString string];
BOOL makeNextCharacterUpperCase = NO;
for (NSInteger idx = 0; idx < [underscores length]; idx += 1) {
unichar c = [underscores characterAtIndex:idx];
if (c == '_') {
makeNextCharacterUpperCase = YES;
} else if (makeNextCharacterUpperCase) {
[output appendString:[[NSString stringWithCharacters:&c length:1] uppercaseString]];
makeNextCharacterUpperCase = NO;
} else {
[output appendFormat:#"%C", c];
}
}
return output;
}
Some drawbacks are that they do use temporary strings to convert between upper and lower case, and they don't have any logic for acronyms, so myURL will result in my_u_r_l.
Try this magic:
NSString* camelCaseString = #"myBundleVersion";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"(?<=[a-z])([A-Z])|([A-Z])(?=[a-z])" options:0 error:nil];
NSString *underscoreString = [[regex stringByReplacingMatchesInString:camelCaseString options:0 range:NSMakeRange(0, camelCaseString.length) withTemplate:#"_$1$2"] lowercaseString];
NSLog(#"%#", underscoreString);
Output: my_bundle_version
If your concern is just the visibility of your code, you could make a category for NSString using the methods you've designed already. That way, you only see the ugly mess once. ;)
For instance:
#interface NSString(Conversions) {
- (NSString *)asCamelCase;
- (NSString *)asUnderscored;
}
#implementation NSString(Conversions) {
- (NSString *)asCamelCase {
// whatever you came up with
}
- (NSString *)asUnderscored {
// whatever you came up with
}
}
EDIT: After a quick Google search, I couldn't find any way of doing this, even in plain C. However, I did find a framework that could be useful. It's called RegexKitLite. It uses the built-in ICU library, so it only adds about 20K to the final binary.
Here's my implementation of Rob's answer:
#implementation NSString (CamelCaseConversion)
// Convert a camel case string into a dased word sparated string.
// In case of scanning error, return nil.
// Camel case string must not start with a capital.
- (NSString *)fromCamelCaseToDashed {
NSScanner *scanner = [NSScanner scannerWithString:self];
scanner.caseSensitive = YES;
NSString *builder = [NSString string];
NSString *buffer = nil;
NSUInteger lastScanLocation = 0;
while ([scanner isAtEnd] == NO) {
if ([scanner scanCharactersFromSet:[NSCharacterSet lowercaseLetterCharacterSet] intoString:&buffer]) {
builder = [builder stringByAppendingString:buffer];
if ([scanner scanCharactersFromSet:[NSCharacterSet uppercaseLetterCharacterSet] intoString:&buffer]) {
builder = [builder stringByAppendingString:#"-"];
builder = [builder stringByAppendingString:[buffer lowercaseString]];
}
}
// If the scanner location has not moved, there's a problem somewhere.
if (lastScanLocation == scanner.scanLocation) return nil;
lastScanLocation = scanner.scanLocation;
}
return builder;
}
#end
Here's yet another version based on all the above. This version handles additional forms. In particular, tested with the following:
camelCase => camel_case
camelCaseWord => camel_case_word
camelURL => camel_url
camelURLCase => camel_url_case
CamelCase => camel_case
Here goes
- (NSString *)fromCamelCaseToDashed3 {
NSMutableString *output = [NSMutableString string];
NSCharacterSet *uppercase = [NSCharacterSet uppercaseLetterCharacterSet];
BOOL previousCharacterWasUppercase = FALSE;
BOOL currentCharacterIsUppercase = FALSE;
unichar currentChar = 0;
unichar previousChar = 0;
for (NSInteger idx = 0; idx < [self length]; idx += 1) {
previousChar = currentChar;
currentChar = [self characterAtIndex:idx];
previousCharacterWasUppercase = currentCharacterIsUppercase;
currentCharacterIsUppercase = [uppercase characterIsMember:currentChar];
if (!previousCharacterWasUppercase && currentCharacterIsUppercase && idx > 0) {
// insert an _ between the characters
[output appendString:#"_"];
} else if (previousCharacterWasUppercase && !currentCharacterIsUppercase) {
// insert an _ before the previous character
// insert an _ before the last character in the string
if ([output length] > 1) {
unichar charTwoBack = [output characterAtIndex:[output length]-2];
if (charTwoBack != '_') {
[output insertString:#"_" atIndex:[output length]-1];
}
}
}
// Append the current character lowercase
[output appendString:[[NSString stringWithCharacters:&currentChar length:1] lowercaseString]];
}
return output;
}
If you are concerned with the speed of your code you probably want to write a more performant version of the code:
- (nonnull NSString *)camelCaseToSnakeCaseString {
if ([self length] == 0) {
return #"";
}
NSMutableString *output = [NSMutableString string];
NSCharacterSet *digitSet = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *uppercaseSet = [NSCharacterSet uppercaseLetterCharacterSet];
NSCharacterSet *lowercaseSet = [NSCharacterSet lowercaseLetterCharacterSet];
for (NSInteger idx = 0; idx < [self length]; idx += 1) {
unichar c = [self characterAtIndex:idx];
// if it's the last one then just append lowercase of character
if (idx == [self length] - 1) {
if ([uppercaseSet characterIsMember:c]) {
[output appendFormat:#"%#", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
}
else {
[output appendFormat:#"%C", c];
}
continue;
}
unichar nextC = [self characterAtIndex:(idx+1)];
// this logic finds the boundaries between lowercase/uppercase/digits and lets the string be split accordingly.
if ([lowercaseSet characterIsMember:c] && [uppercaseSet characterIsMember:nextC]) {
[output appendFormat:#"%#_", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
}
else if ([lowercaseSet characterIsMember:c] && [digitSet characterIsMember:nextC]) {
[output appendFormat:#"%#_", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
}
else if ([digitSet characterIsMember:c] && [uppercaseSet characterIsMember:nextC]) {
[output appendFormat:#"%#_", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
}
else {
// Append lowercase of character
if ([uppercaseSet characterIsMember:c]) {
[output appendFormat:#"%#", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
}
else {
[output appendFormat:#"%C", c];
}
}
}
return output;
}
I have combined the answers found here into my refactoring library, es_ios_utils. See NSCategories.h:
#property(nonatomic, readonly) NSString *asCamelCaseFromUnderscores;
#property(nonatomic, readonly) NSString *asUnderscoresFromCamelCase;
Usage:
#"my_string".asCamelCaseFromUnderscores
yields #"myString"
Please push improvements!
I happened upon this question looking for a way to convert Camel Case to a spaced, user displayable string. Here is my solution which worked better than replacing #"_" with #" "
- (NSString *)fromCamelCaseToSpaced:(NSString*)input {
NSCharacterSet* lower = [NSCharacterSet lowercaseLetterCharacterSet];
NSCharacterSet* upper = [NSCharacterSet uppercaseLetterCharacterSet];
for (int i = 1; i < input.length; i++) {
if ([upper characterIsMember:[input characterAtIndex:i]] &&
[lower characterIsMember:[input characterAtIndex:i-1]])
{
NSString* soFar = [input substringToIndex:i];
NSString* left = [input substringFromIndex:i];
return [NSString stringWithFormat:#"%# %#", soFar, [self fromCamelCaseToSpaced:left]];
}
}
return input;
}
OK guys. Here is an all regex answer, which I consider the only true way:
Given:
NSString *MYSTRING = "foo_bar";
NSRegularExpression *_toCamelCase = [NSRegularExpression
regularExpressionWithPattern:#"(_)([a-z])"
options:NSRegularExpressionCaseInsensitive error:&error];
NSString *camelCaseAttribute = [_toCamelCase
stringByReplacingMatchesInString:MYSTRING options:0
range:NSMakeRange(0, attribute.length)
withTemplate:#"\\U$2"];
Yields fooBar.
Conversely:
NSString *MYSTRING = "fooBar";
NSRegularExpression *camelCaseTo_ = [NSRegularExpression
regularExpressionWithPattern:#"([A-Z])"
options:0 error:&error];
NSString *underscoreParsedAttribute = [camelCaseTo_
stringByReplacingMatchesInString:MYSTRING
options:0 range:NSMakeRange(0, attribute.length)
withTemplate:#"_$1"];
underscoreParsedAttribute = [underscoreParsedAttribute lowercaseString];
Yields: foo_bar.
\U$2 replaces second capture group with upper-case version of itself :D
\L$1 however, oddly, does not replace the first capture group with a lower-case version of itself :( Not sure why, it should work. :/

How do I divide NSString into smaller words?

Greetings,
I am new to objective c, and I have the following issue:
I have a NSString:
"There are seven words in this phrase"
I want to divide this into 3 smaller strings (and each smaller string can be no longer than 12 characters in length) but must contain whole words separated by a space, so that I end up with:
String1 = "There are" //(length is 9 including space)
String2 = "seven words"// (length is 11)
String3 = "in this" //(length is 7), with the word "phrase" ignored as this would exceed the maximum length of 12..
Currently I am splitting my original array into an array with:
NSArray *piecesOfOriginalString = [originalString componentsSeparatedByString:#" "];
Then I have multiple "if" statements to sort out situations where there are 3 words, but I want to make this more extensible for any array up to 39 (13 characters * 3 line) letters, with any characters >40 being ignored. Is there an easy way to divide a string based on words or "phrases" up to a certain length (in this case, 12)?
Something similar to this? (Dry-code warning)
NSArray *piecesOfOriginalString = [originalString componentsSeparatedByString:#" "];
NSMutableArray *phrases = [NSMutableArray array];
NSString *chunk = nil;
NSString *lastchunk = nil;
int i, count = [piecesOfOriginalString count];
for (i = 0; i < count; i++) {
lastchunk = [[chunk copy] autorelease];
if (chunk) {
chunk = [chunk stringByAppendingString:[NSString stringWithFormat:#" %#", [piecesOfOriginalString objectAtIndex:i]]];
} else {
chunk = [[[piecesOfOriginalString objectAtIndex:i] copy] autorelease];
}
if ([chunk length] > 12) {
[phrases addObject:lastchunk];
chunk = nil;
}
if ([phrases count] == 3) {
break;
}
}
well, you can keep splitting the string as you're already doing, or you could check out whether NSScanner suits your needs. In any case, you're going to have to do the math yourself.
Thanks McLemore, that is really helpful! I will try this immediately. My current solution is very similar, but less refined, as I hard coded the loops and use individual variable to hold the sub strings (called them TopRow, MidRow, and BottomRow), that and the memory management issue is overlooked... :
int maxLength = 12; // max chars per line (in each string)
int j=0; // for looping, j is the counter for managing the words in the "for" loop
TopRow = nil; //1st string
MidRow = nil; //2nd string
//BottomRow = nil; //third row string (not implemented yet)
BOOL Row01done = NO; // if YES, then stop trying to fill row 1
BOOL Row02done = NO; // if YES, then stop trying to fill row 2
largeArray = #"Larger string with multiple words";
tempArray = [largeArray componentsSeparatedByString:#" "];
for (j=0; j<[tempArray count]; j=j+1) {
if (TopRow == nil) {
TopRow = [tempArray objectAtIndex:j];
}
else {
if (Row01done == YES) {
if (MidRow == nil) {
MidRow = [tempArray objectAtIndex:j];
}
else {
if (Row02done == YES) {
//row 3 stuff goes here... unless I can rewrite as iterative loop...
//will need to uncommend BottomRow = nil; above..
}
else {
if ([MidRow length] + [[tempArray objectAtIndex:j] length] < maxLength) {
MidRow = [MidRow stringByAppendingString:#" "];
MidRow = [MidRow stringByAppendingString:[tempArray objectAtIndex:j]];
}
else {
Row02done = YES;
//j=j-1; // uncomment once BottowRow loop is implemented
}
}
}
}
else {
if (([TopRow length] + [[tempArray objectAtIndex:j] length]) < maxLength) {
TopRow = [TopRow stringByAppendingString:#" "];
TopRow = [TopRow stringByAppendingString:[tempArray objectAtIndex:j]];
}
else {
Row01done = YES;
j=j-1; //end of loop without adding the string to TopRow, subtract 1 from j and start over inside Mid Row
}
}
}
}