Obj-C - Can't access values in NSArray? - objective-c

I have a textView that displays the string: 255,34,7,4
I'm trying to use the following code to pull the string from my textView, and separate each number into an array:
NSArray *array = [self.textview.text componentsSeparatedByString:#","];
NSString *comp1 = array[0];
NSString *comp2 = array[1];
NSString *comp3 = array[2];
This works, and the following is returned to my array:
> 2020-07-11 15:21:58.110560-0700[10116:2311809] In the array you will
> find (
> 255,
> 34,
> 7,
> 4 )
However I'm unable to access the second and third values with array[1] and array[2]? My app crashes with the following error:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSSingleObjectArrayI objectAtIndex:]: index 1 beyond
bounds [0 .. 0]'
Why is this happening?

because the moment you try to access the expected objects do not exist.
It is much safer to ask for the amount of indexes available in an array before accessing indexes that may not exist at runtime.
NSArray *splitarray = [self.textview.text componentsSeparatedByString:#","];
NSLog(#"amount of indexes %lu", splitarray.count);
for (NSString *idxObject in splitarray) {
NSLog(#"content #%",idxObject);
}
or
for (NSUInteger i=0; i<splitarray.count; i++) {
NSLog(#"content #%",splitarray[i]);
}
NSArray and a lot of other indexed data types do not check if an index exists to speed up accessing and they are also not constructed to return nil in case the index does not exist.

Related

Strange change of variable's value

I have this simple piece of code when I am logging variable's value:
NSLog(#"set.nflag - %#", set.nflag1);
if (set.nflag1 == [NSNumber numberWithInt:1])
{
NSLog(#"set.nflag - %#", set.nflag1);
[sectionArray insertObject:_checkboxCell atIndex:set.nflag1];
}
at last row I have crash an log is:
2013-09-26 11:36:12.537 PharmaTouch[1325:c07] set.nflag - 1 2013-09-26 11:36:12.537 PharmaTouch[1325:c07] set.nflag - 1 2013-09-26 11:36:12.538 PharmaTouch[1325:c07] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM insertObject:atIndex:]: index 127347632 beyond bounds for empty array'
What can cause of changing value for
set.nflag1
?
The exception shows that sectionArray isn't allocated. Add this somewhere before this gets executed.
sectionArray = [NSMutableArray alloc] init];
Try adding:
NSInteger index = [set.nflag1 intValue];
[sectionArray insertObject:_checkboxCell atIndex:index];
In your code, the
set.nflag1
is of type NSNumber*. This is a pointer, not NSUInteger.
Do this:
[sectionArray insertObject:_checkboxCell atIndex:set.nflag1.unsignedIntegerValue];
Also, when comparing NSNumbers, use isEqualToNumber: method or just retrieve the int before the comparison.
Make sure you allocate the NSMutableArray before you try the insertion. Also, look out not to give it too big index
Raises an NSRangeException if index is greater than the number of elements in the array.
1 is beyond the bounds of an empty 0 indexed array.
Try adding a guard to check the array length before insertion.
Or try simply adding it to the end of the array or
Pad your array with instances of the NSNull singleton if you really need the NSNumber at the eponymous index.

Prevent duplicate printout of element in NSMutableArray

I am using a singleton class to transfer a NSMutableArray across views.
The issue I am having is my array is getting displayed multiple times.
Right now I am working with three UITextFields. Each is getting added to the array and outputted in a specific format. Here is what my output looks like:
A / B
C
A / B
C
A / B
C
All I need shown is:
A / B
C
Here is my code if someone can help me find what is missing or needs to be reworked:
To display the text:
UILabel * myLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 300, 200)];
[myLabel setFont:[UIFont fontWithName:#"Helvetica" size:10.0]];
myLabel.numberOfLines = 0;
NSMutableString * string = [NSMutableString string];
Education * myEducation = [Education sharedEducation];
for (Education * output in myEducation.educationOutputArray)
{
[string appendString:[NSString stringWithFormat:#"%# / %# \n%#\n", [myEducation.educationOutputArray objectAtIndex:0], [myEducation.educationOutputArray objectAtIndex:1], [myEducation.educationOutputArray objectAtIndex:2], nil]];
}
myLabel.text = string;
[self.view addSubview:myLabel];
Here is where I am saving the text:
-(void)saveButtonTapped:(id)sender
{
[_educationArray addObject:_aTextField.text];
[_educationArray addObject:_bTextField.text];
[_educationArray addObject:_cTextField.text];
Education * myEducation = [Education sharedEducation];
myEducation.educationOutputArray = _educationArray;
[self.navigationController popViewControllerAnimated:YES];
}
EDIT *
When a user is entering text into the text fields they can also add a new set of text using the same three text fields.
If I removed the for loop only the first is displayed. How can I get all of the text to display?
EDIT TWO *
I tried this:
[string appendString:[NSString stringWithFormat:#"%# / %# \n%#\n", [output major], [output university], [output timeAtSchool]]];
Results in this error:
2012-12-29 17:03:07.928 EasyTable[14501:c07] -[__NSCFString major]: unrecognized selector sent to instance 0x7176850
2012-12-29 17:03:07.941 EasyTable[14501:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString major]: unrecognized selector sent to instance 0x7176850'
*** First throw call stack:
(0x1c99012 0x10d6e7e 0x1d244bd 0x1c88bbc 0x1c8894e 0x6162 0xff817 0xff882 0xffb2a 0x116ef5 0x116fdb 0x117286 0x117381 0x117eab 0x1184a3 0x118098 0x2c10 0x10ea705 0x21920 0x218b8 0xe2671 0xe2bcf 0xe1d38 0x2e5213 0x1c61afe 0x1c61a3d 0x1c3f7c2 0x1c3ef44 0x1c3ee1b 0x1bf37e3 0x1bf3668 0x1e65c 0x240d 0x2335 0x1)
libc++abi.dylib: terminate called throwing an exception
You add three elements at a time to the array, and later you want to process them three at a time.
It would probably be better to create a container class that holds the three elements, and add instances of the container class to the array.
But if you really want to do it this way, you can't use a for/in loop. You have to use an index variable:
NSArray *array = myEducation.educationOutputArray;
for (NSUInteger i = 0, count = array.count; i < count; i += 3) {
[string appendFormat:#"%# / %#\n%#\n", array[i], array[i+1], array[i+2]];
}
you don't have duplicates in the array: the problem is in the for loop
for (Education * output in myEducation.educationOutputArray)
{
[string appendString:[NSString stringWithFormat:#"%# / %# \n%#\n", [myEducation.educationOutputArray objectAtIndex:0], [myEducation.educationOutputArray objectAtIndex:1], [myEducation.educationOutputArray objectAtIndex:2], nil]];
}
here you are looping through the array 3 times (because there are 3 objects in the array) and then printing each object each time. I think you should just do the appendString: line wihtout the for loop
Your for loop is really odd; You loop through each object in the array but then you hardcoded the indexes inside the for loop. I'm not sure what's going on there but it's certainly the source of the odd output. That pointer to an Education object is what you should access. Each time through the loop, use the value of output.
If you're also having uniqueness issues, consider using an NSSet instead of an NSMutableArray. If you care about order, use NSOrderedSet. Set collection types do not allow duplicated values.
Also one more point: If you know you're only going to ever access the values at index 0, 1, and 2, there's really no point to having an NSArray. Just store each value separately and access it directly. At the very least there's no reason for the for loop.
Edit:
You're crashing because you think your array has Education objects in it but it really has plain strings:
-[__NSCFString major]: unrecognized selector sent to instance 0x7176850
Notice that it's saying that you tried to call the method major on an __NSCFString (a private subclass of NSString that apple uses internally). This is a good indicator that your array doesn't contain what you think it does. Make sure you're loading your data into your array correctly by constructing Education objects with the three pieces of data.
You also suggested that you tried
[string appendString:[NSString stringWithFormat:#"%# / %# \n%#\n", output]];
Basically what stringWithFormat: does is take that format string and use it like a template and then it takes as many arguments as you need to fill up the placeholders in the template. %# is a placeholder for an object's description so stringWithFormat: is going to expect three parameters after the format string to fill each %#.

NSArray index 1 beyond bounds for empty array

-(IBAction)someMethod:(UIStepper *)sender{
int x=sender.value; //This is an integer from 0-8;
NSLog(#"%f",sender.value);
NSArray *rpmValues = [[NSArray alloc]initWithObjects:#"a",#"b",#"c",#"d",#"e",#"f",#"g",#"h",#"i", nil];
if (x<=[rpmValues count]) {
myLabel.text = [rpmValues objectAtIndex:x];
}
NSLog(#"%i",[rpmValues count]);
}
Above is my code, what I want to do is to change UILabel display by changing UIStepper. This is very straight forward. But when I change press the stepper value, it crashes:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** - [__NSArrayM objectAtIndex:]: index 1 beyond bounds for empty array'
*** First throw call stack:
And the [rpmValue count] is 9. I really got confused. Can anyone help me?
That code seems fine (see my comment on the question); your problem could arise from the use of
if (x<=[rpmValues count]) {
This will include the count of the array, which exceeds the index range by one. Use
if (x < [rpmValues count]) {
At the very least if (x<=[rpmValues count]) should be if (x<[rpmValues count]). Otherwise if you have an array with, say, two entities then you're allowing yourself to access indices 0, 1 and 2 — three possibilities in total.
Is it possible you've set a maximumValue on your stepper of '9' based on similar logic?

objective-c empty NSArray error

I'm using JSON to parse data into an NSArray 'courseArray'. I then filter this data using NSPredicate and store it into 'rows'. The problem is, i dont know how to determine if 'rows' is empty or not. For example : If a record exists, rows will contain the appropriate objects, but if the record doesnt exist then the application crashes (also when i use NSLog to see the contents of the array its blank, i believe its supposed to say its nil? if there are no objects). How can i fix this?
if (dict)
{
courseArray = [[dict objectForKey:#"lab"] retain];
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"labNumber== %#",labSelected]; //filter
rows = [[courseArray filteredArrayUsingPredicate:predicate]retain];
}
[jsonreturn release];
self.formattedTextView.opaque = NO;
self.formattedTextView.backgroundColor = [UIColor clearColor];
NSLog(#"array %#",rows);
**NSDictionary *currentSelection = [rows objectAtIndex:0];** (app crashes at this line - [NSArray objectAtIndex:]: index 0 beyond bounds for empty array')
NSString *labNumber = [currentSelection objectForKey:#"labNumber"];
-objectAtIndex: will raise an exception if there is no object at the nominated index. If rows is empty there won't be an object at index 0, hence the exception. As you don't catch the exception, the result is that your app is terminated.
You probably want to compare [rows count] to 0 to check that there's something in it and to react appropriately if not.
Try if([courseArray count] > 0) also another method that can be of help here is
[courseArray containsObject:(id)]

replaceObjectAtIndex error?

The following code:
NSMutableArray *kkk = [NSMutableArray arrayWithCapacity: 20];
[kkk replaceObjectAtIndex:10 withObject: #"cat"];
yields this
Terminating app due to uncaught exception 'NSRangeException', reason:
' - [NSMutableArray replaceObjectAtIndex:withObject:]: index 10
beyond bounds for empty array' Call stack at first throw:
arrayWithCapacity: allocates the required memory but it doesn't fill the array with objects. nil isn't a valid object to fill the array. So if you need an array with empty objects, you will have to do something like this,
int size = 20;
NSMutableArray *kkk = [NSMutableArray arrayWithCapacity:size];
for ( int i = 0; i < size; i++ ) {
[kkk addObject:[NSNull null]];
}
Now you can safely replace objects,
[kkk replaceObjectAtIndex:10 withObject: #"cat"];
Getting an array with that capacity does not fill it with elements; it's still an empty array when you try to replace the object at index 10. If you provide more detail as to the context in which this is happening, I can try to suggest a way around the problem.
EDIT: if you must have an array with objects right away, try this:
NSMutableArray *kkk = [NSMutableArray arraywithObjects: #"", #"", #"", #"", nil];
except with 20 #""'s instead of four. Then you get an array of 20 strings. Be sure to put retain on the end of it if you're using it outside the immediate scope, though, since arrayWithObjects returns an autoreleased array.