I have an array of items, each with their own unique descriptions. Basically, I want to create a method which takes each item from the array and returns a single descriptive string which shows the description of each item in said array.
- (NSString *) itemList
{
NSString *list = [[NSString alloc] init];
for (Item *i in _items)
{
/**
Unsure :S
*/
[NSString stringWithFormat:#"%#: %#.\n", [i firstId], [i name]];
}
return list;
}
Basically, this is the coded logic that I have so far.
Assume I have two items which are initialised as such:
Item *testItem1 = [[Item alloc] initWithIdentifiers:#[#"shovel", #"spade"] name:#"a shovel" andDesc:#"This is a mighty fine shovel"];
Item *testItem2 = [[Item alloc] initWithIdentifiers:#[#"gem", #"crystal"] name:#"a gem" andDesc:#"This is a shiny gem"];
I then add those items to my Inventory object:
[testInventory put:testItem1];
[testInventory put:testItem2];
By calling the Inventory method itemList
[testInventory itemList];
on my inventory (code listed above), I want the following result:
#"shovel: a shovel.\ngem a gem."
Does anyone have any suggestions or pointers. I'm sure it's simple; it's just that I've only recently picked up Obj - C :)
Thanks
You can just use:
list = [list stringByAppendingFormat:#"%#: %#\n", [i firstId], [i name]];
or try NSMutableString:
NSMutableString *list = [[NSMutableString alloc] init];
[list appendFormat:#"%#: %#\n", [i firstId], [i name]];
You can do it more elegantly by overriding the description method for your Item class like this:
- (NSString *) description {
return [NSString stringWithFormat:"%#: %#.", [self firstId], [self name]];
}
and then to generate the string for all the items in the array:
NSString* itemsString = [itemList componentsJoinedByString:#"\n"];
I like adding the collection of strings to a mutable array and then calling componentsJoinedByString. It works even more cleanly if it is the description method you want on each object because you don't have to do the collecting loop first.
Create nsmutablearray
For each item in list
Nsmutablearray add object item.property
Return nsmutablearray componentsJoinedByString #", "
If you want the item's description though, you can just do, assuming you have an array with the objects already
TheArray componentsJoinedByString #", "
Related
let's say i have a nsdictionary which contains an array as value.
NSMutableDictionary *test = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[[NSMutableArray alloc]initWithObjects:"#Audi",#"Mercedes",#"Ferrari",nil], #"box 1",
[[NSMutableArray alloc]initWithObjects:"#Chervrolet",#"Mercedes",#"Bentley",nil], #"box 2",
[[NSMutableArray alloc]initWithObjects:"#Audi",#"Dodge",#"Ferrari",nil], #"box 2",
nil]
that's my simple dictionary with the arrays inside.
well now i need to check if theres a value in it.
here how i check if theres a certain key
if([test objectForKey#"box 2"]) { NSLog(#"item exists"); }
how can i access now the array inside one of the value? let's say to check if the array contains an item or to add one?
let's say i want to check if box 2 contains an Audi, and if not, i want to add it
Using containsObject you can check if object exist in array.
if([[test valueForKey:#"box 2"] containsObject:#"Audi"])
NSLog(#"Audi exists");
else
{
//[[test valueForKey:#"box 2"] addObject:#"Audi"];
//EDIT
NSMutableArray *data = [test valueForKey:#"box 2"];
[data addObject:#"Audi"];
[test setObject:data forKey:#"box 2"];
NSLog(#"Add Audi");
}
I am new to Objective C coming from C# .NET, I have this scenario :
Assume I have 5 NSArrays corresponding to 5 UIButtons. the UIButtons have the exact same name
as the NSArray, so for example one UIButton is called mainScreen, and there is an NSArray called mainScreen.
Those Five buttons are linked to one IBAction where I do the following :
- (IBAction)btnClick:(id)sender {
NSString *category = [(UIButton *)sender currentTitle];
NSLog(category);
//Here I need to call the NSArray which has the same name as category
}
Now I can get the actual name of the UIButton, but how can I get the NSArray same as that title? without getting into a lot of if else or switch statements?
What I would do is store the arrays inside an NSDictionary. You can then set the 'key' as the name of your array and then the value would be the array itself.
That way you could say:
- (IBAction)btnClick:(id)sender {
NSString *category = [(UIButton *)sender currentTitle];
NSLog(category);
//Here I need to call the NSArray which has the same name as category
NSArray *theArray = (NSArray*)[self.myDictionary valueForKey:category];
}
Hope this helps!
The easiest way to associate names with objects is using an NSDictionary (or it's mutable subclass NSMutableDictionary). Dictionaries map a unique key to an object. Keys can be any object (that implements the NSCopying protocol), but are very often NSStrings
Have a look at the NSDictionary Reference and the Programming with Objective-C guide.
Note that if you use the button title this might break if you localise your app.
What you do is not the best way. You should provide tag for each button, say from 1 to 5. Also you should put your five arrays into one array. Now all you need is:
- (IBAction)btnClick:(id)sender
{
NSInteger index = [sender tag] - 1;
NSArray *array = [bigArray objectAtIndex:index];
}
That's it.
Assign different tags to all UIButtons and then access them explicitly using their tags.
- (IBAction)btnClick:(id)sender {
int tagIs = [(UIButton *)sender tag];
switch (tagIs) {
case 1:
// Access first button array
break;
case 2:
// Access second button array
break;
default:
break;
}
}
Or you can use AssociationObjects method for associating data with objects as following:
Firstly import :
#import <objc/runtime.h>
then create keys as :
static char * firstBtnKey = "firstBtnKey";
static char * secondBtnKey = "secondBtnKey";
-- - other keys same way ---
then use :
// Do any additional setup after loading the view, typically from a nib.
NSMutableArray *firstArray = [[NSMutableArray alloc] initWithObjects:#"object1",#"object 2", nil];
objc_setAssociatedObject((UIButton *)[self.view viewWithTag:1],
firstBtnKey,
firstArray,
OBJC_ASSOCIATION_RETAIN);
NSMutableArray *secondArray = [[NSMutableArray alloc] initWithObjects:#"object1",#"object 2", nil];
objc_setAssociatedObject((UIButton *)[self.view viewWithTag:2],
secondBtnKey,
secondArray,
OBJC_ASSOCIATION_RETAIN);
`
and then access these arrays as :
- (IBAction)btnClick:(id)sender {
int tagIs = [(UIButton *)sender tag];
switch (tagIs) {
case 1:
// Access first button array
NSMutableArray *tempArr = (NSMutableArray *)objc_getAssociatedObject((UIButton *)sender, firstBtnKey);
break;
case 2:
// Access second button array
NSMutableArray *tempArr = (NSMutableArray *)objc_getAssociatedObject((UIButton *)sender, secondBtnKey);
break;
default:
break;
}
}
Hope it helps.
In most programming languages objects don't have names.[1] Just because UIButtons have the exact same name as the NSArray(mainScreen), doesn't mean that your object is "called" mainScreen.
Use NSDictionary , array as object and button title as key.
or use button tag
title1= [[NSArray alloc] initWithObjects:#"1",nil];
title2= [[NSArray alloc] initWithObjects:#"2",nil];
title3= [[NSArray alloc] initWithObjects:#"3",nil];
title4= [[NSArray alloc] initWithObjects:#"4",nil];
title5= [[NSArray alloc] initWithObjects:#"5",nil];
dict = [[NSDictionary alloc] initWithObjectsAndKeys:title1,#"title1",title2,#"title2",title3,#"title3",title4,#"title4",title5,#"title5",nil];
- (IBAction)btnClick:(id)sender {
NSString *category = [(UIButton *)sender currentTitle];
NSArray *arr = [dict objectForKey:category];
}
I'm going to paste the code below, then tell you what I've tried to determine from the code.
If you're reading this quickly, start with the text right above the next code-block.
- (void)tableViewDidLoadModel:(UITableView*)tableView {
self.items = [NSMutableArray array];
self.sections = [NSMutableArray array];
NSMutableDictionary *groups = [NSMutableDictionary dictionary];
for (int c = 0;c < [_contacts.people count];c++) {
NSDictionary *person = [_contacts.people objectAtIndex:c];
NSString *name = [person objectForKey:#"fullName"];
NSString *letter = [name substringToIndex:1];
NSMutableArray *section = [groups objectForKey:letter];
NSLog(#"%# - %# - %#", name, [person objectForKey:#"index"], [person objectForKey:#"abId"]);
if (!section) {
section = [NSMutableArray array];
[groups setObject:section forKey:letter];
}
TTTableItem *item = [ttItem itemWithText:name URL:[person objectForKey:#"index"]];
[section addObject:item];
}
Someone else wrote this block of code. From what I can determine, they're trying to take the user's contacts and fill a TableView.
Now my real question has to do with that last line:
TTTableItem *item = [ttItem itemWithText:name URL:[person objectForKey:#"index"]];
[section addObject:item];
This is using the Three20 framework. Apparently what the previous developer did was use TTTableItem to kind of get a pre-formatted UITableViewCell. (Hopefully I'm thinking right?)
I need to replace this line of code with something normal.
I've thought of just using UITableViewCell, but other than that I'm not really sure how to start?
-tableViewDidLoadModel: is a method that comes from the TTTableViewDataSource protocol, so if you're trying to remove Three20 from your project, you've got more to do than just replace the TTTableItem.
TTTableItem is a subclass of NSObject, and the only thing it seems to add is a userInfo property. To get rid of it, you could start by creating your own class with the same property.
Okay I've been trying at this for about 2-3 hours now and I don't seem to quite get it. Here is the code and a brief explanation:
I'm trying to make two lists of words, pull one word from each of those lists at random, and display both words (along with a third) on the screen when a button is pressed. Here is the code:
#import "Project001ViewController.h"
#implementation Project001ViewController
-(ArrayOfWords *) advs
{
if(!advs){
advs = [[ArrayOfWords alloc] init];
NSString* advpath = #"/WordLists/adverbs.txt";
NSLog(#"1");
[[self advs] populateListOfWords:advpath];
}
return advs;
}
-(ArrayOfWords *) adjs
{
if (!adjs) {
adjs = [[ArrayOfWords alloc] init];
NSString* adjpath = #"/WordLists/adjectives.txt";
[[self adjs] populateListOfWords:adjpath];
NSLog(#"2");
}
return adjs;
}
- (IBAction)generate:(UIButton *)sender;
{
//int randy = arc4random() % 11;
//NSNumber* num= [NSNumber numberWithInteger:randy];
NSString* obj = #"app";
NSString* adverb = [[self advs] randomItem];
NSString* adjective = [[self adjs] randomItem];
NSLog(#"%i %i",[adjs size],[advs size]);
NSLog(#"1 %# %# %#.",adverb, adjective, obj);
//NSLog(#"%#",thePhrase);
[display setText:#"Hi"];
}
#end
I'm having trouble on the last NSLog line:
NSString* obj = #"app";
NSString* adverb = [[self advs] randomItem];
NSString* adjective = [[self adjs] randomItem];
NSLog(#"%i %i",[adjs size],[advs size]);
NSLog(#"1 %# %# %#.",adverb, adjective, obj);
Instead of getting the two randomly selected words (using arc4random() to produce them) the array returns Null. But I know FOR CERTAIN. That the array's are not empty because the NSLog Line where I print [adjs size] and [advs size] I get the correct sizes of the list of words. I just want to know what is causing them to print Null here.
populateListOfWords, randomItem, and size methods:
- (NSArray *) populateListOfWords:(NSString *) path {
//gets the components of the file into an NSString
NSString *wordListString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
//returns an array of all the words (uses the next line indicator '\n' to know when it's at the end of the word
NSArray* words = [wordListString componentsSeparatedByString:#"\n"];
length=(NSNumber*)([words count]);
return words;
}
-(NSString*) randomItem{
//returns random object in list
return (NSString*)[list objectAtIndex:(arc4random() % (int)length)] ;
}
-(int) size{
//returns size of list
return (int)length;
}
(If more code is needed let me know and thank you in advanced for any and all help).
I believe there is a problem with the paths. It is impossible to have access to the path /WordLists/adjectives.txt in iOS due to the application sandbox. I suggest you add these files to the application by dragging and dropping them onto the project. You can get the file paths for resources in application bundle using
NSString * path = [[NSBundle mainBundle] pathForResource:#"adjectives" ofType:#"txt"];
Now pass this path to the method populateListOfWords:.
Because of the incorrect path, I believe wordListString is nil and everything else follows to be that.
Another thing is that int and NSNumber are not toll free bridged like NSStrings and other foundation objects. So
length=(NSNumber*)([words count]);
is incorrect. I suggest you define length as int or better NSUInteger to match the type count method returns.
This method is the problem:
- (NSArray *) populateListOfWords:(NSString *) path {
//gets the components of the file into an NSString
NSString *wordListString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
//returns an array of all the words (uses the next line indicator '\n' to know when it's at the end of the word
NSArray* words = [wordListString componentsSeparatedByString:#"\n"];
length=(NSNumber*)([words count]);
return words;
}
It wasn't actually putting the words in a list that anyone else could access. I had to just modify it like so:
- (void) populateListOfWords:(NSString *) path {
//gets the components of the file into an NSString
NSString *wordListString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
//returns an array of all the words (uses the next line indicator '\n' to know when it's at the end of the word
NSArray* words = [wordListString componentsSeparatedByString:#"\n"];
list = words;
length=(int)([words count]);
}
Now it gives me the correct output. But for some reason when I press the button twice it crashes. Oh well that's a new problem. Thanks again for all the help.
UPDATE
Turns out advs and adjs were being released so the second go around it was trying to access a nil value because when I call [self advs] [self adjs] the pointers exist, but their contents do not. I had to go back and refill them each time basically removing the if (!advs) and if (adjs) parts. It now works as intended.
I've done the following to put a fetched request into an array of arrays but now i don't know which methods i need to call from chcsvparser to write this into a csv file
NSArray *objectsForExport = [fetchedResultsController fetchedObjects];
NSArray *exportKeys = [NSArray arrayWithObjects:#"best_checkout", #"darts_thrown", #"high_score", #"score_100", #"score_140", #"score_180",#"three_dart_average",nil];
NSMutableArray *csvObjects = [NSMutableArray arrayWithCapacity:[objectsForExport count]];
for (NSManagedObject *object in objectsForExport) {
NSMutableArray *anObjectArray = [NSMutableArray arrayWithCapacity:[exportKeys count]];
for (NSString *key in exportKeys) {
id value = [object valueForKey:key];
if (!value) {
value = #"";
}
[anObjectArray addObject:[value description]];
}
[csvObjects addObject:anObjectArray];
}
As Johann suggests, you should use the writeToCSVFile:atomically: convenience method. However, be aware that using it as you describe in your comment is not correct.
The NSString you pass in should be the filepath you want the data writing to.
This webpage should give you the necessary information and methods when writing CSV files:
https://github.com/davedelong/CHCSVParser#readme
Hope this helps!