I have an app where I need to display a report of six (6) columns and a variable number of rows (lines).
What's the best approach to do this? I tried UITextView but there is no way to set the font size to make the data fit on each line.
I usually use UIWebViews for this.
A dozen lines to create a html table out of a NSArray and some nice CSS.
Edit: I can show you an example I wrote in the last 5 minutes. There's not much to it if you have a basic understanding of html. Of course you could take it much further than that.
And even if you don't know anything about html I'm sure you can learn the basics for some simple table display within a couple of hours.
- (NSString *)htmlTableRowFromArray:(NSArray *)array withOpenTag:(NSString *)openTag andCloseTag:(NSString *)closeTag {
NSMutableString *rowHtmlStr = [NSMutableString string];
for (NSString *str in array) {
[rowHtmlStr appendFormat:#"%# %# %#\n", openTag, str, closeTag];
}
return rowHtmlStr;
}
- (void)displayReport {
NSArray *dataArray = ...;
NSArray *myHeader = ...;
NSMutableString *htmlStr = [NSMutableString stringWithString:#"<html><head><title>MyTable</title></head><body>"];
// the table starts here
[htmlStr appendString:#"<table width=\"100%\" style=\"background-color:#CCC\" border=\"1\" cellpadding=\"4\" cellspacing=\"0\">"];
// this will create a table header
[htmlStr appendFormat:#"<tr>%#</tr>", [self htmlTableRowFromArray:myHeader withOpenTag:#"<th>" andCloseTag:#"</th>"]];
for (NSArray *line in dataArray) {
// one row for each array in the data
[htmlStr appendFormat:#"<tr>%#</tr>", [self htmlTableRowFromArray:line withOpenTag:#"<td>" andCloseTag:#"</td>"]];
}
// table ends
[htmlStr appendString:#"</table>"];
[htmlStr appendString:#"</body></html>"];
[webView loadHTMLString:htmlStr baseURL:nil];
}
the table should look like this. Imho not that bad for the amount of work.
Related
I have a txt file which was copied to Supporting Files of my Xcode project.The data in txt file is of format:
abacus#frame with balls for calculating
abate#to lessen to subside
abdication#giving up control authority
aberration#straying away from what is normal
....................around 4000 lines
I have successfully extracted data from the file using the below code:
NSString *greFileString = [NSString stringWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"grewords" ofType:#"txt"] encoding:NSUTF8StringEncoding error:nil];
self.greWordsArray = [NSMutableArray arrayWithArray:[greFileString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
When I print greWordsArray,I could see the below output in log
"abacus#frame",
with,
balls,
for,
calculating,
"",
"abate#to",
lessen,
to,
subside,
"",
"abdication#giving",
up,
control,
authority,
"",
"aberration#straying",
away,
from,
what,
is,
normal,
"",
But I want the values in two separate arrays,one holding abacus,abate,abdication,authority aberration and other array with frame with balls for calculating,to lessen to subside,giving up control,straying away from what is normal i.e. one array holding string before # symbol and one with after # symbol
I know there are several methods like checking for special character method,string by replacing occurrences of string,using character set,but the fact is since my string greFileString is a bundle holding multiple strings,if I try any of these methods only abacus is getting added to array,but I want abacus,abate,abdication,aberration to be added to array.
EDIT
Following suggestion of H2CO3,I have implemented the following way:
NSString *greFileString = [NSString stringWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"grewords" ofType:#"txt"] encoding:NSUTF8StringEncoding error:nil];
NSArray *greData = [NSArray arrayWithArray:[greFileString componentsSeparatedByString:#"#"]];
self.greWordsArray = [NSMutableArray array];
self.greWordHints = [NSMutableArray array];
for (NSString *greWord in greData)
{
if ([greWord characterAtIndex:0] == (unichar)'#')
{
[greWordHints addObject:greWord];
}
else
{
[greWordsArray addObject:greWord];
}
}
NSLog(#"gre words are %#",greWordsArray);
NSLog(#"gre hints are %#",greWordHints);
Here is the logged output:
gre words are (
abacus,
"frame with balls for calculating
\nabate",
"to lessen to subside
\nabdication",
"giving up control authority
\naberration",
"straying away from what is normal
\nabet",
"help/encourage somebody (in doing wrong)
\nabeyance",
"suspended action
\nabhor",
"to hate to detest
gre hints are (
)
Can someone please guide me on this?
It's quite trivial: if the first character of the string is a '#', then put it in the one array, else put it in the other one.
NSArray *words = [greFileString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSMutableArray *at = [NSMutableArray array];
NSMutableArray *noAt = [NSMutableArray array];
for (NSString *s in words)
if ([s characterAtIndex:0] == (unichar)'#')
[at addObject:s];
else
[noAt addObject:s];
Disregard the above - OP was lying to me >.< The text file actually consists of lines in which an at-symbol delimits the word and the explanation, i. e.
word1#explanation one
word2#explanation two
etc. This means that first the lines should be retrieved (perhaps using - [NSString componentsSeparatedByString:]), then each line is to be split into two part (the same method is useful here too).
Finally got it working,initially my idea was right,but couldn't execute it properly.First of all we need to fetch the data from txt file and place in array.Then as H2CO3 mentioned we need to loop through and here we need to implement components Separated By String.Now we are ready with data,what needs to be done is placing data in arrays using array object at index 0 in words and 1 in hints,i.e.:
NSString *greFileString = [NSString stringWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"grewords" ofType:#"txt"] encoding:NSUTF8StringEncoding error:nil];
self.greWordHints = [NSMutableArray array];
self.greWordsArray = [NSMutableArray array];
NSArray *greWords = [NSMutableArray arrayWithArray:[greFileString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]];
for (NSString *greWord in greWords)
{
if (greWord && greWord.length)
{
NSArray *trimmedGreData = [greWord componentsSeparatedByString:#"#"];
[greWordsArray addObject:[trimmedGreData objectAtIndex:0]];
[greWordHints addObject:[trimmedGreData objectAtIndex:1]];
}
}
Hope it helps some one,thanks :)
When the user click the next button, it generate random number and I would like to store the number into the array. My array is storing the last number only. Should I initialize the array outside the 'next' function? Moreover, I would like the 'back button' to read the array from the last in number. Please advise.
- (IBAction)Next:(id)sender {
// Do any additional setup after loading the view from its nib.
//generate random number - result is a range of 0-10
int randomnumber = (arc4random() % 10);
// Add the random number into array
[myArray addObject:[NSNumber numberWithInt:randomnumber]];
// easy way to look what is now in the array
NSLog([myArray description]);
NSString *fileName = [NSString stringWithFormat:#"File_no_%d", randomnumber +1];
//render a complete file-path out of our filename, the main-bundle and the file- extension
NSString *filePath=[[NSBundle mainBundle] pathForResource:fileName ofType:#"txt"];
//fetch the text content from that file
NSString *myText= [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:nil];
//hand that text over to our textview
TextView.text=myText;
}
- (IBAction)Back:(id)sender {
NSNumber *last_array_num = [myArray objectAtIndex:myArray.count - 1];
// read the file name based on the last number in array
NSString *fileName = [NSString stringWithFormat:#"File_no_%d", last_array_num ];
}
You say you are initializing the array within the Next method as well as adding to it? If so, the array needs to be initialized outside that method, and just once. This keeps your data intact, otherwise it is overwritten when you initialize it the next time.
You are adding to the array just fine, so that doesn't need to change at all. As for reading the number in your Back method, you simply need to have the following line of code:
EDIT: this is the code you would use to get the results you want from your array. Also, the formal approach is not to start with capital letters in your code unless it defines a class (like NSString). For methods, like this, you should use something like - (IBAction)backButton:(id)sender instead. It's not a big deal at all and your code will work fine, but it's just etiquette and keeps your code a bit less confusing in the long run. I have a feeling someone might say something about it later, so I'm just letting you know ahead of time. Anyway, here is the code you want
SECOND EDIT: Like you were thinking, you should make a variable that can be read from in the code. In your header file, add this
int arrayCount;
In your code, once myArray is created, set arrayCount
arrayCount = [myArray count];
This should also be done if add or remove any objects from the array.
Then in your action method, you can call the files
- (IBAction)Back:(id)sender {
NSString *filePath = [NSString stringWithFormat:#"File_no_%d", [[myArray objectAtIndex:arrayCount - 1] intValue]];
// make sure you aren't going beyond the bounds of the array;
if (arrayCount > 1) {
// decrease the count of the arrayCount;
arrayCount--;
}
}
Using this should allow you to move backwards in your array one step each time you click the button. Again, if this isn't what you are looking for, just let me know and we will get to the bottom of it
I’m making a languages application, and I have a long list of vocabulary relating to that language (German, in case anyone was interested). I have the functionality in my app to switch between sorting the tableview by German words, or by english words.
When I use the following:
NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:type];
NSString *string = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
NSArray *array = [[string componentsSeparatedByString:#"\n"] sortedArrayUsingSelector:#selector(compare:)];
it works absolutely perfectly - by which I mean, exactly as expected. What I would like to improve on this however, is that there are certain words, such as verbs or nouns, which are always preceded by prefixes, like “to”, as in “to do something”, or “the” in front of nouns. So what I would like to do is somehow exclude these from my sort, because otherwise I end up with all the verbs being sorted alphabetically under the “t” section in my array, which is not very user friendly.
I’ve looked through the Apple documentation about NSString and NSArray, as this is where the compare function is (unless I’m very much mistaken), and I haven’t found any way that makes sense to me. This is the first time I have done any data handling like this so I may be missing something simple, and so I would really appreciate some help.
Thanks very much
Michaeljvdw
You're on the right track. What you want to use instead of the (built-in) compare method is to write your own method, which can eliminate the "to" or "the" bits if they exist, and then use the existing compare method.
Your call would look something like this:
NSArray *array = [[string componentsSeparatedByString:#"\n"] sortedArrayUsingSelector:#selector(myCompare:)];
Using a custom category you give to NSString with the following methods:
// This method can be exposed in a header
- (NSComparisonResult)myCompare:(NSString*)aString
{
NSString* selfTrimmed = [self removeArticles];
NSString* aStringTrimmed = [s2 removeArticles];
return [self compare:aString];
}
// This method can be kept private in the .m implementation
- (NSString*)removeArticles
{
NSRange range = NSMakeRange(NSNotFound, 0);
if ([self hasPrefix:#"to "])
{
range = [self rangeOfString:#"to "];
}
else if ([self hasPrefix:#"the "])
{
range = [self rangeOfString:#"the "];
}
if (range.location != NSNotFound)
{
return [self substringFromIndex:range.length];
}
else
{
return self;
}
}
You might have some luck with localizedCompare: or localizedStandardCompare:, but I don't think that either of these will strip out articles and prepositions like you want. Instead, you will probably have to define a category on NSString that provides the specific style of sorting you're looking for:
#interface NSString (MySortAdditions)
- (NSComparisonResult)compareWithoutArticles:(NSString *)other;
#end
#implementation NSString (MySortAdditions)
- (NSComparisonResult)compareWithoutArticles:(NSString *)other {
NSMutableString *mutableSelf = [NSMutableString stringWithString:self];
[mutableSelf
replaceOccurrencesOfString:#"das"
withString:#""
options:NSCaseInsensitiveSearch
range:NSMakeRange(0, [mutableSelf length])
];
...
// delete articles from 'other' too
NSCharacterSet *trimSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
NSString *trimmedSelf = [mutableSelf stringByTrimmingCharactersInSet:trimSet];
NSString *trimmedOther = ...;
return [trimmedSelf localizedCaseInsensitiveCompare:trimmedOther];
}
#end
You can then use #selector(compareWithoutArticles:) as your sort selector for NSArray.
First, don't use compare:. Use localizedCompare: instead. This is important, because whether á appears just after a or after z as a separate letter depends on the language. localizedCompare: takes care of that.
--edit
As Justin says, localizedStandardCompare: is the selector to be used! I didn't know that method. As written in the documentation, localizedStandardCompare: does more than localizedCompare:, although the document doesn't say exactly what it does.
--end of edit
If you want more, you need to implement that yourself. You can use category for that purpose. First declare it
#interface NSString (MichaelsSuperCompareCategory)
-(NSComparisonResult)michaelsSuperCompare:(NSString*)string;
#end
and then implement it
#interface NSString (MichaelsSuperCompareCategory)
-(NSComparisonResult)michaelsSuperCompare:(NSString*)string{
...
}
#end
This way you can add methods to an existing class. Then you can use
NSArray *array = [[string componentsSeparatedByString:#"\n"]
sortedArrayUsingSelector:#selector(michaelsSuperCompare:)];
It is important to prefix the method name with something distinctive, not to accidentally crash with internal methods used by Apple.
As for the functionality, you need to implement that yourself, as far as I know. You can get the current locale with [NSLocale currentLocale]. You can implement a nicer behavior for the languages you know, and then default to localizedCompare: for unknown languages.
I would somehow do -replaceOccurancesOfStrings on all the data eg "To" -> "" - and then reload the data. (or this can in a text editor)
Another thing to think about is having eg 'to walk' changed to 'walk (to)' which can be done ahead of time (and will also create less confusion for the user as they are scrolling alphabetically).
I want to write a not so complicated but large file within my app and be able to send it by mail (using MFMailComposeViewController)
Since NSXMLElement and related classes are not ported to iPhone SDK what options do I have for creating XML documents?
Thanks in advance.
I would recommend using KissXML. The author started in a similar situation as you and created an NSXML compatible API wrapper around libxml. He discusses the options and decisions here on his blog.
Shameless self-promotion: KSXMLWriter
Try the open source XML stream writer for iOS:
Written in Objective-C, a single .h. and .m file
One #protocol for namespace support and one for without
Example:
// allocate serializer
XMLWriter* xmlWriter = [[XMLWriter alloc]init];
// start writing XML elements
[xmlWriter writeStartElement:#"Root"];
[xmlWriter writeCharacters:#"Text content for root element"];
[xmlWriter writeEndElement];
// get the resulting XML string
NSString* xml = [xmlWriter toString];
This produces the following XML string:
<Root>Text content for root element</Root>
It's a homework exercise in NSString building. Abstractly, create a protocol like:
#protocol XmlExport
-(NSString*)xmlElementName;
-(NSString*)xmlElementData;
-(NSDictionary*)xmlAttributes;
-(NSString*)toXML;
-(NSArray*)xmlSubElements;
#end
Make sure everything you're saving implements it and build the XML with something like the following:
-(NSString*)toXML {
NSMutableString *xmlString;
NSString *returnString;
/* Opening tag */
xmlString = [[NSMutableString alloc] initWithFormat:#"<%#", [self xmlElementName]];
for (NSString *type in [self xmlAttributes]) {
[xmlString appendFormat:#" %#=\"%#\"", type, [[self xmlAttributes] valueForKey:type]];
}
[xmlString appendString:#">"];
/* Add subelements */
for (id<XmlExport> *s in [self xmlSubElements]) {
[xmlString appendString:[s toXML]];
}
/* Data */
if ([self xmlElementData]) {
[xmlString appendString:[self xmlElementData]];
}
/* Close it up */
[xmlString appendFormat:#"</%#>", [self xmlElementName]];
/* Return immutable, free temp memory */
returnString = [NSString stringWithString:xmlString];
[xmlString release]; xmlString = nil;
return returnString;
}
can any body tell me how to search NSMutable Arry in which objects are stored from xml feed
i have the following code
- (void) searchTableView {
NSString *searchText = searchBar.text;
NSMutableArray *searchArray = [[NSMutableArray alloc] init];
//blog entries is the nsmutable array in which objects are stored from RSS feed
for (NSMutableDictionary *dictionary in blogEntries)
{
NSArray *images=[dictionary objectForKey:#"image"];
NSArray *titlearray = [dictionary objectForKey:#"title"];
NSDictionary *imagesDic=[NSDictionary dictionaryWithObject:images forKey:#"image"];
NSDictionary *titlearrayDic=[NSDictionary dictionaryWithObject:titlearray forKey:#"title"];
[searchArray addObject:imagesDic];
[searchArray addObject:titlearrayDic];
}
//know the problem comes in below code i just want to compare title not image string as there any way to search only of title array not for both image in title some what like this For(nsstring *stemp in searcArray.titleArray etc)
for (NSString *sTemp in searchArray)
{
NSRange titleResultsRange = [sTemp rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0){
[copyListOfItems addObject:sTemp];
}}
the problem is that this code just saving title not image and if i save image then it also search in image string which i dont want to do. i want the user will search only by title then when he type something in textbox if search is true against some values then only thos e are displayed in table cell with title and image.
as this is RSS APPLiction and feeds are comming from xml feed
which
click here
bescially i am extracting this xml feed and em displaying image and title tage in table cell know i want to implement searchbar in it
Thanks....i am waiting for your response...
#mipadi is right - try using containsObject: first.
If that doesn't work, just a simple loop will do it - you can put in whatever matching criteria you want in there. e.g. This code searches by comparing the name properties :
- (id)searchArray:(NSArray *)haystack for:(id)needle {
for(id temp in haystack)
if ([temp name] isEqual:[needle name]])
return needle;
return nil;
}
Hope that helps.
NB If you're using your own objects in the array, you can use containsObject: if you have overridden isEqual: (and hash)
Depends on how you want to search. If you're just looking for a particular object, you can use containsObject:.
Without knowing more about what you want, it's tough to answer your question. But here are some starting points:
NSArray - Check out the methods starting like indexOfObject-; I think one of these probably does what you want. There's also filteredArrayUsingPredicate.
NSMutableArray - The only notable method here is filterUsingPredicate, I think.
Hope one of these helps you.