addObject to NSArray - xcode

I am a newbe and have been working all day readying/watching/searching for a solution to this. The following code works, but now how do I add an integer to the array?
//this works
NSArray *array = [NSArray arrayWithObjects:[NSNumber numberWithInt:10],
[NSNumber numberWithFloat:25.96], #"Hello World", nil];
for (id obj in array)
NSLog(#"%#", obj);
The following returns error: Use of undeclared identifier 'obj'
NSArray *array = [NSArray arrayWithObjects:[NSNumber numberWithInt:10],
[NSNumber numberWithFloat:25.96], #"Hello World", nil];
for (id obj in array)
[array addObject:7];
NSLog(#"%#", obj);

you must use a NSMutabbleArray not an NSArray to add objects dynamically and don't forget [] and arrayWithObjects is only for nsarray. try this:
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:[NSNumber numberWithInt:10]];
[array addObject:[NSNumber numberWithFloat:25.96]];
[array addObject:#"Hello World"];
[array addObject:[NSNumber numberWithInt:7]];
for (id obj in array) {
NSLog(#"%#", obj);
}
Just Copy paste this code and it will initiate the array with object you want and then show them.

There are several issues here:
You are attempting to mutate (change) an immutable array. You would need an NSMutableArray instead of NSArray to do what you want. (Incidentally, your actual NSArray creation code is fine.)
Your for() loop is blowing up mainly because you don't have braces to delimit your code. Absent braces, the compiler is going to use only the first line following the for as the loop contents. Hence your NSLog() is outside the loop, and obj out of scope.
I don't know why you don't have brackets around your addObject: line, as in [array addObject:...]. Did that even compile? Is that a copy and paste error?
Finally, you can't add a naked integer to a Cocoa collection such as NSArray. You would need to follow what you properly did earlier in your code: [array addObject:[NSNumber numberWithInt:7]].
Given that you were using indentation as syntax, I'm guessing maybe you have more of a Python (or similar) background? If so, you are going to have to quickly adjust some of your modes of thinking to program effectively in C or Objective-C. I urge you to get a beginners book on Cocoa programming and start at the beginning or you are going to get very frustrated very quickly.
Edit: I notice that after I posted you added brackets back in, so I struck #3 above. This leads to another important note: make sure that if you ask a question that you copy and paste the exact code that failed. Never re-type!

It's because your using indentation in your for loop which only considers the following line. Try this instead
    for (id obj in array) {
        [array addObject:[NSNumber numberWithInt:7]];
        NSLog(#"%#", obj);
}
Note
I think you need to use a NSMutableArray if you want to add objects after initialising it. Also it's not a good idea to modify a collection your looping through (in this case the loop will never end as you keep adding an object into an array your looping through). You can make a mutable version of the array by using this line.
NSMutableArray * mutArray = [NSMutableArray arrayWithArray:array];

Related

The Idea? creating sorted array from NSDictionary key values (with objects)

I know there are a whole bunch of questions that have been asked and answered in stackoverflow about the challenge of getting keys in an NSDictionary sorted by putting those keys into sort order in an array. I understand that objects are not stored in sort order within the actual dictionary and that is, I think, for reasons of efficiency or maybe memory management on the part of Foundation code.
I have been working on trying out examples from several answers out here and in apple documentation and blogs (some I can get to work, others not!) , but I can't seem to find an example that solves my confusion.
I think my confusion is that the examples I'm encountering both here, in apple documentation and in the different helpful blogs, all seem to have examples where there is just a key value pair and the second value is not an object - it's more like just a value. (However isn't it really an object at some level? I would think it is)
One example, that I couldn't get to work (Sorting an NSArray by an NSDictionary value ) , uses this idea
[array sortedArrayUsingComparator:^(NSDictionary *item1, NSDictionary *item2) {
NSString *age1 = [item1 objectForKey:#"age"];
NSString *age2 = [item2 objectForKey:#"age"];
return [age1 compare:age2 options:NSNumericSearch];
}];
I thought maybe this idea, specifying the key in a more specific manner, might be my problem.
I wonder if maybe I'm not communicating to the compiler what the key is, and what the object is, and that is why I'm getting an "unrecognized selector sent to instance" error.
..... Code Snips Follow .....
1)
I have a class called "Dog". A given dog object has several properties, including an NSString key.
My key is "licenseString" is an alphanumeric key - I'm also wondering if I should use decimalNumberWithString but that's not the question here
#property (strong,nonatomic) NSString *licenseString;
#property (strong, nonatomic) NSString *dogName;
#property (strong, nonatomic) NSString *whatMakesDogSpecial;
#property (strong, nonatomic) UIImage *dogPhoto;
2) I have an NSDictionary
#property (nonatomic, strong) NSDictionary *dogDictionary;
I hardcode information into the dogDictionary in this not very sophisticated way,
Dog *aDog;
// Dog one
aDog = [[Dog alloc]init] ;
aDog.licenseString = #"1";
aDog.dogName = #"Oscar";
aDog.whatMakesDogSpecial = #"This animal was found at the Mid-Penn humane society. He is super friendly, plays well with other dogs and likes people too. He enjoys fetching balls and frisbees too. He also goes to the park daily." ;
aDog.dogPhoto = [UIImage imageNamed:#"webVuMiniAppDogOscar.jpg"];
[self.dogDictionary setValue:aDog forKey:aDog.licenseString];
3) Then once I have several dog objects in my dogDictionary, I want to sort on the license tag values, so that I can populate a table view with dog names, but by order of their license tags.
BTW it seems that the compiler does recognize "vars.dogDictionary" which appears in the code snip below, because when I look at the debugger I can see that two valid instances are coming up from my dog dictionary. The debugger output is in an attachment
So, using ideas from a stackoverflow answer and the apple documentation, I write this
NSArray *sortedKeys = [vars.dogDictionary keysSortedByValueUsingComparator:
^NSComparisonResult(id obj1, id obj2) {
return [obj1 compare:obj2];
}];
NSLog(#" The sorted array is %#", sortedKeys);
And that's where my problem happens. I recognize that 0x1182f740 refers to "obj1" as shown in the debugger attachment
2013-08-06 15:13:58.276 SortDogLIcenseTags[3876:11303] -[Dog compare:]: unrecognized selector sent to instance 0x1182f740
(lldb)
Attachment is a picture showing debugger values - they don't like to paste very well
Here's how I resolved this challenge. It works and was pretty straightforward to integrate into my Master/Detail project
I know I found a tutorial on the web somewhere that led me to this solution , I'm sorry I can't find it now.
Note that sortedDogDictionaryArray and dogDictionaryArray are declared as properties in the .h file.
self.dogDictionaryArray = [vars.dogDictionary allValues];
// Sort
NSSortDescriptor *sortDescriptorDog =
[[NSSortDescriptor alloc] initWithKey:#"licenseString" ascending:YES];
NSArray *sortDescriptorsDogs =
[NSArray arrayWithObject:sortDescriptorDog];
self.sortedDogDictionaryArray =
[self.dogDictionaryArray sortedArrayUsingDescriptors:sortDescriptorsDogs];
NSLog(#"%#",self.sortedDogDictionaryArray );
int doggie;
Dog *someDogName;
NSLog(#"Sorted Order is...");
for (doggie = 0; doggie < [self.sortedDogDictionaryArray count]; doggie++) {
//NSLog(#"%#", [sortedArray objectAtIndex:i]);
//NSLog(#"%#", [sortedArrayDogs objectAtIndex:doggie]);
someDogName = [self.sortedDogDictionaryArray objectAtIndex:doggie];
//NSLog(#"name is %#", someDogName.dogName);
NSLog(#"name is %# tag is %#", someDogName.dogName, someDogName.licenseString);
}

Building up an array an element at a time

Currently I'm populating an array in one line, e.g.
self.monthMonths = [[NSArray alloc] initWithObjects:#"January", #"February", #"March", #"April", #"May", #"June",#"July",#"August",#"September",#"October",#"November",#"December", nil];
What is the syntax to add these elements one at a time as I want to pull the data from a database. I'm using the months of the year as an example.
while([results next]) {
NSString *months = [results stringForColumn:#"month"];
self.month = [[NSArray alloc] initWithObjects:#"month",nil];
//[NSArray
NSLog(#"Month: %#",month);
}
Create an NSMutableArray and add the objects to it one by one with addObject
You need to use NSMutableArray instead, and call -addObject:

componentsJoinedByString gives me EXC_BAD_ACCESS

I have an NSMutableArray i am trying to convert into a string.
Declaring my NSMutableArray...
NSMutableArray *listData;
And later inside a method...
NSString *foo = [listData componentsJoinedByString:#"|"];
NSLog(#"%#",foo);
It seems no matter what i try i keep getting EXC_BAD_ACCESS.
To make sure each element in my array was an NSString i also tried this...
NSMutableArray *mArray = [[NSMutableArray alloc] init];
for (id ln in listData) {
NSString *boo = [NSString stringWithFormat: #"%#",ln];
[mArray addObject:boo];
}
NSString *foo = [mArray componentsJoinedByString:#"|"];
NSLog(#"%#",foo);
I can manipulate my NSMutableArray by adding/deleting objects in the same method or other methods inside my class. But when i try "componentsJoinedByString" the error pops up. Does anyone have any advice or another way i can combine this array into a single NSString?
In the code you've given, there will never be an NSMutableArray for listData. At some point in your code, you'll need to create one, and presumably populate it.
Edit
Okay, so you may get into memory management problems here, so let's be a bit clearer:
You're synthesizing getters and setters for the instance variable, so it's good practice to use those to access it, they'll take care of retain and releasing appropriately.
To set listData you can simply use
self.listData = [listManage getList:[[NSUserDefaults standardUserDefaults] stringForKey:#"list_name"] list:#"LIST"];
or
[self setListData:[listManage getList:[[NSUserDefaults standardUserDefaults] stringForKey:#"list_name"] list:#"LIST"]];
if you prefer.

Renaming keys in NSMutableDictionary

Given an NSMutableDictionary *dict, is this a bad way to replace keys with a new name? Is there an easier way?
NSArray *originalField = [NSArray arrayWithObjects:#"oldkey", #"oldkey2", nil];
NSArray *replacedField = [NSArray arrayWithObjects:#"newkey", #"newkey2", nil];
for (int i=0; i<[originalField count]; ++i)
{
if ([dict objectForKey:[originalField objectAtIndex:i]] != nil) {
[dict setObject:[dict objectForKey:[originalField objectAtIndex:i]] forKey:[replacedField objectAtIndex:i]];
[dict removeObjectForKey:[originalField objectAtIndex:i]];
}
}
Thanks!
Nope, that's pretty much it. In general, you'd use fast enumeration and/or NSEnumerator to walk the arrays instead of going index-by-index, but since you're walking two parallel arrays, indexes are the clearest way to do it.
That's not a bad way per se, but you could certainly make it more elegant (and in my opinion, easier) by cleaning up the code a bit and eliminating a few redundant method calls. As #Peter suggested, fast enumeration (you can use it on Leopard+ or iPhone) would be much quicker and cleaner, and therefore generally preferable. Here's an example:
NSArray *originalField = [NSArray arrayWithObjects:#"oldkey", #"oldkey2", nil];
NSArray *replacedField = [NSArray arrayWithObjects:#"newkey", #"newkey2", nil];
id anObject;
NSEnumerator *replacementKeys = [replacedField objectEnumerator];
for (id originalKey in originalField) {
if ((anObject = [dict objectForKey:originalKey]) != nil) {
[dict removeObjectForKey:originalKey];
[dict setObject:anObject forKey:[replacementKeys nextObject]];
}
}
One note of warning: you'll want to make sure that the arrays originalField and replacedField are the same length. If the latter is shorter, you'll get an exception, either from -[NSEnumerator nextObject] or -[NSArray objectAtIndex:]. If the latter is longer, you may wonder why some of the replacement keys are never used. You could use an NSAssert macro to verify that during debugging, and it will be disabled automatically in release builds.
Alternatively, if there is truly a one-to-one relationship between the keys, perhaps you could use a dictionary to map from old key to new key, and enumerate over the result of -[NSDictionary allKeys].

NSArray to Core Data items

I have an method that reads an xml file and stores the xml nodes at a certain XPath-path in an NSArray called *nodes. What I want to do is take each one of the items in the array and add it to a core data entity called Category with the attribute of "name".
I have tried a number of different ways of creating the entity but I'm not sure about the correct way to do this effectively. This is the code used to create the NSArray, any ideas on how to implement this? (ignore the NSError, I will fix this in the final version)
- (IBAction)readCategories:(id)sender
{
NSString *xmlString = [resultView string];
NSData *xmlData = [xmlString dataUsingEncoding: NSASCIIStringEncoding];
NSXMLDocument *xmlDoc = [[NSXMLDocument alloc] initWithData:xmlData options:nil error:nil];
//XPath
NSError *err=nil;
NSArray *nodes = [xmlDoc nodesForXPath:#"//member[name='description']/value/string" error:&err];
}
EDIT - My loop code
NSArray *nodes = [xmlDoc nodesForXPath:#"//member[name='description']/value/string" error:&err];
int arrayCount = [nodes count];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSXMLElement *categoryEl;
NSString *new = [catArrayController newObject];
int i;
for (i = 0; i < arrayCount; i++)
{
[categoryEl = [nodes objectAtIndex:i]];
[new setValue:[categoryEl stringValue] forKey:#"name"];
[catArrayController addObject:new];
}
[pool release];
Here's how I'd write it:
for (NSXMLElement *categoryElement in nodes) {
NSManagedObject *newObject = [catArrayController newObject];
[newObject setValue:[categoryElement stringValue] forKey:#"name"];
[catArrayController addObject:newObject];
[newObject release];
}
First, I'm using the Objective-C 2.0 for-each syntax. This is simpler than using index variables. I eliminated i and arrayCount.
Next, I took out your NSAutoreleasePool. None of the objects in the loop are autoreleased, so it had no effect. (The newObject method returns a retained object which is, by convention, what methods with the word new in their name do) This is also why I release newObject after adding it to the array controller. Since I'm not going to be using it any more in this method, I need to release it.
Also, you had defined new (which I renamed newObject) as an NSString. Core Data objects are always either an instance of NSManagedObject or a subclass of NSManagedObject.
Your line [categoryEl = [nodes objectAtIndex:i]] won't compile. That's because the bracket syntax is used to send a message to an object. This is an assignment statement, so the bracket syntax is not needed here. (This line is also not necessary any more because of I've changed the loop to use the for-each syntax) But, for future reference, categoryEl = [nodes objectAtIndex:i]; would have worked.
What part are you having trouble with? There shouldn't be much more to it than looping through the array, creating a new managed object for each entry, and setting the correct attributes. You can create the managed object with NSEntityDescription's -insertNewObjectForEntityForName:inManagedObjectContext: method.

Resources