objectAtIndex returns SIGABRT error - objective-c

I have this line:
NSString *objectkey=[NSString stringWithFormat:#"%#",[line objectAtIndex:1]];
If objectAtIndex:0, it works fine. But if 1, it produces SIGABRT error at runtime.
However, I have another line to confirm that the array "line" has an object at index 1:
NSLog(#"%d",[line count]);
This returns 2 to the console.
Why would SIGABRT occur even though an index should exist there?
As for line, it is created like this:
for (int i=1;i<=[components count];i++){
NSArray*line=[[components objectAtIndex:(i-1)] componentsSeparatedByString:#"|"];
"line" is recreated during each loop iteration (I assume this is okay? no release is necessary, from what i understand using the "separated by string" method).
the array "components" contains lines such as:
Recipe Books|BOOKS
Recipe Photos|PHOTOS
I have created this little loop to verify that all are strings in "line":
for( NSObject* obj in line )
{
NSLog(#"%#",obj);
if ([obj isKindOfClass:[NSString class]]==YES) { NSLog(#"string"); }
}

Most likely the object contained at [line objectAtIndex:1] is not an NSString*. Why don't you try iterating over the set of objects in line and outputting them with NSLog. My guess is that the second one is going to print an address (of the form <Classname: 0x0>, not a string.
for( NSObject* obj in line )
{
NSLog(#"%#",obj);
}
Add an NSLog to the code where you create line:
for (int i=1;i<=[components count];i++){
NSLog(#"%#",[components objectAtIndex:(i-1)]);
NSArray*line=[[components objectAtIndex:(i-1)] componentsSeparatedByString:#"|"];
I have a strong feeling that your input data is bad, as you've excluded our prior answers as the solution with your responses. Your input data might have a <cr> somewhere it doesn't belong or missing data. How big is the input file for components?
Second answer based on gdb results
Try using [NSString stringWithString:[line objectAtIndex:1]] instead of stringWithFormat. Based on your use of gdb its likely that stringWithFormat is breaking on the unexpected control character (and trying to format it). stringWithString should copy the string character by character. Removing the control character(s) is another problem. :)

Assuming there is a valid object at index 1 of your line NSArray, the likely answer is that it's not a NSString, it's some other class that can't be translated using %# in your stringWithFormat: call. Look at the stack where it aborts and you could also check the type of the object before calling the stringWithFormat: call.

Related

Adding objects from another array

I have the following code:
for (int i = 1; i <= [nmaSpread count];)
{
[nmaUserName addObjectsFromArray:[nmaSpread objectAtIndex:i]];
[nmaSpread removeObjectAtIndex:i];
i += 2;
}
I have declared all variables as global, nmaUserName and nmaSpread are both NSMutableArrays, and have been allocated in viewDidLoad.
I want to store all the odd objects from nmaSpread into nmaUsername and then delete the active object at nmaSpread.
However it keeps crashing with this error:
[NSMutableArray addObjectsFromArray:]: array argument is not an NSArray
2011-12-11 21:08:55.123 appName[15671:f803] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSMutableArray addObjectsFromArray:]: array argument is not an NSArray'
nmaSpread itself is an NSMutableArray, but it looks like the objects it contains aren't. When you do [nmaSpread objectAtIndex:i], that returns an object from nmaSpread. This object isn't an array, so to add it, you'd just use addObject:, not addObjectsFromArray:.
There are a few problems with your code.
First off, you've miss-understood what -addObjectsFromArray: does. The actual method you want is just addObject:.
Second, it is dangerous to modify an array while looping through it. The official line from Apple is "this may work in some situations, but don't do it because it might stop working at any point in the future". You need to wait until after you have finished looping through the array, and then delete them. Your current code is definitely doing it wrong.
You could sit down with pen/paper and work out the math to keep it all intact, but it's easier and safer to just do this:
NSMutableIndexSet *indexesToRemove = [NSMutableIndexSet indexSet];
for (int i = 1; i <= [nmaSpread count];)
{
[nmaUserName addObject:[nmaSpread objectAtIndex:i]];
[indexesToRemove addIndex:i];
i += 2;
}
[mmaSpread removeObjectsAtIndexes:indexesToRemove];
NSMutableArray's addObjectsFromArray expects you to pass another array, but you are passing a single object (the one at index 'i')
You can try switching
[nmaUserName addObjectsFromArray:[nmaSpread objectAtIndex:i]];
to
[nmaUserName addObject:[nmaSpread objectAtIndex:i]];
and that will remove the error you are seeing, but then you are likely to run into another problem because you are removing objects from nmaSpread as you go and as a result the indexes for items later in the array get shifted. You should probably change your logic around to deal with that problem.

Problem with an Array, a Property and NSLog

So i have this block of code it adds players to an NSMutableArray in my ViewController playerList. For some reason i cannot print all the playernames to the log. Am I doing something wrong? I keep getting an error that says member refrence struc objc_object is a pointer. Can anyone see what im doing wrong?
p1,p2,p3,p4 are all NSString Objects that just have the players names.
the addPlayer method creates a new player object with a property named playerName.
- (IBAction)addPlayerButton:(id)sender {
[self.playerList addObject:[self addPlayer:p1]];
[self.playerList addObject:[self addPlayer:p2]];
[self.playerList addObject:[self addPlayer:p3]];
[self.playerList addObject:[self addPlayer:p4]];
for (id element in playerList) {
NSLog(element.playerName);
}
}
for (id element in playerList) {
NSLog(element.playerName);
}
The compiler warning/error is because element is of type id and you can't use the dot syntax with object references of type id (a specific design choice when creating that feature, btw).
Fixed code:
for (Player *element in playerList) {
NSLog(#"%#", element.playerName);
}
Two (unrelated) problems fixed:
explicitly type element to be a reference to your player class (I assumed the name). This'll allow the dot syntax to work.
Use a format string with NSLog. If a player's name were ever to contain a formatting sequence -- %#, for example -- then NSLog() would try to expand the next (non-existent) argument to NSLog and your app would crash or print garbage (say, if the player's name were "Bob %f %f %f").
doesnt look like they are getting
added to the array properly
Make sure you allocate an array and assign it to playerList somewhere:
self.playerList = [NSMutableArray array];
Use this instead:
NSLog(#"%#", element.playerName);
NSLog is sort of like printf() and friends, but not exactly. You must provide a first argument that is a string literal with the format you want to use, followed by any variables represented in the format. In Objective-C, the special format %# means "use the obeject's description method to fill in a value (if there is one)." Sometimes you get a debugger-like output for an object that does not have that method, e.g. or some such, which isn't too useful of course.
In your case, assuming playerName is an NSString, you'll see it's name output if you use the format %# in NSLog's first argument.
EDIT:
You should be able to use a for statement like this:
for(Player *p in playerList) {
NSLog(#"%#", p.playerName);
}
Just because you use addObject: to add the objects doesn't mean you have to give up using the objects' type when you look at them from the array.
If in fact the objects in playerList are just NSStrings, then your loop can simply be
for(NSString *name in playerList) {
NSLog(#"%#", name);
}

in statement in for loop

i have a for loop state ment as under:
for(NSString* name in nameArray)
nameArray is NSArray.
In the above statement, what does it mean for: NSString* name in nameArray
Iterate through all NSString* in nameArray.
Can be written less cleanly:
for (int i=0;i<[nameArray count];++i) {
NSString *name = [nameArray objectAtIndex:i];
// Do stuff
}
Keep in mind: Don't iterate a mutable array and mutate it (and make sure no other thread does). In such a case you need to call count every iteration like displayed above.
This is fast enumeration syntax introduced in Objective-C 2.0. Check this tutorial for the details. Also you can Google "objective c fast enumeration" for many other resources available online.
It means that the code inside the parenthesis will be executed for every object in the nameArray, which you will access through the NSString *name variable.

NSMutableArray from filterUsingPredicate error

I am trying to return a subset of my NSMutableArray (MessageArray) with the following code. MessageArray contains an NSDictionary, one of the keys being FriendStatus. I get a strange error which I know is a DUH syntax issue. "error. void value not ignored as it ought to be".
-(NSMutableArray*)FriendMessageArray {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"FriendStatus == 1"];
NSMutableArray *filtered = [MessageArray filterUsingPredicate:predicate];
return filtered;
}
"void value not ignored as it ought to be" means that a method with a signature that starts with (void) is being used to assign a value or object to a variable. What's the signature for filterUsingPredicate? does it start with (void) ?
I'm assuming "MessageArray" is an instance variable (never name instance variables this way; you should have a property called -messages and access it with self.messages). I'l further assume that it is an NSMutableArray or else you'd be getting warnings from the compiler.
NSMutableArray -filterUsingPredicate: modifies the array itself, returning void. The method you want is -filteredArrayUsingPredicate: which returns an array. The fact that the former is a verb and the latter is a noun indicates this fact even without reading the docs. Cocoa naming is extremely consistent, which is why I mention it in the first paragraph. Pay attention to the names and you will have far fewer bugs.

Is if (variable) the same as if (variable != nil) in Objective-C

I am getting a EXC_BAD_ACCESS (SIGBUS) on this line in my iPhone project:
if (timeoutTimer) [timeoutTimer invalidate];
The thing that has me stumped is that I don't understand how that line could crash, since the if statement is meant to be checking for nil. Am I misunderstanding the way Objective-C works, or do line numbers in crash statements sometime have the wrong line in them?
Just because a variable is set to a value other than nil doesn't mean it's pointing to a valid object. For example:
id object = [[NSObject alloc] init];
[object release];
NSLog(#"%#", object); // Not nil, but a deallocated object,
// meaning a likely crash
Your timer has probably already been gotten rid of (or possibly hasn't been created at all?) but the variable wasn't set to nil.
I just ran into a similar issue, so here's another example of what might cause a check such as yours to fail.
In my case, I was getting the value from a dictionary like this:
NSString *text = [dict objectForKey:#"text"];
Later on, I was using the variable like this:
if (text) {
// do something with "text"
}
This resulted in a EXC_BAD_ACCESS error and program crash.
The problem was that my dictionary used NSNull values in cases where an object had an empty value (it had been deserialized from JSON), since NSDictionary cannot hold nil values. I ended up working around it like this:
NSString *text = [dict objectForKey:#"text"];
if ([[NSNull null] isEqual:text]) {
text = nil;
}
They should be the same. Perhaps the line number is in fact incorrect.
Look for other possible errors near that in your code and see if you find anything.