EXC_BAD_ACCES in NSArray - ios

getting a "Thread 1: EXC_BAD_ACCES(code=2, adress=0xbf7fffffc)" error at
NSArray *tempArray ] [lijstString componentsSeperatedByString:#","];
What can i do about this?
This is the whole codepart:
-(NSMutableArray *)lijstArray{
NSString *lijstString = self.details[#"lijst"];
NSArray *tempArray = [lijstString componentsSeparatedByString:#", "];
self.lijstArray = [NSMutableArray array];
for (NSString *lijstValue in tempArray) {
[self.lijstArray addObject:[lijstValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
return self.lijstArray;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;
}

Your lijstArray getter function is infinitely recursive. Assuming lijstArray is an #property, every time you use self.lijstArray you are calling the instance method lijstArray if used as a getter or setLijstArray if used as a setter.
You are using self.lijstArray three times. The first use on the left part of the assignment operator is only calling [self setLijstArray: ... ] so while that will trample the _lijstArray iVar, it will not cause recursion.
You cause recursion in two places, though once is enough. First is with [self.lijstArray addObject: ... ] which is the same as [[self lijstArray] addObject: ... ]. This causes infinite recursion.
And then with return self.lijstArray which is the same as return [self lijstArray] -- again the lijstArray instance method is calling itself. This also causes infinite recursion.
Incidentally the stack trace would be informative-- you'd have a very deep stack.

try this:
-(NSMutableArray *)lijstArray{
if(!_lijstArray){ //If you need get new lijstArray always, comment this line, and below "}"
NSString *lijstString = self.details[#"lijst"];
NSArray *tempArray = [lijstString componentsSeparatedByString:#", "];
_lijstArray = [NSMutableArray array];
for (NSString *lijstValue in tempArray) {
[_lijstArray addObject:[lijstValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
}
return _lijstArray;
}

Check to make sure the line:
self.details[#"list"];
Is not null. Also check to make sure tempArray and lijstString are being allocated and initialized.

Related

replacing an NSDecimalNumbers with another in NSArray crashes

I have a NSMutabelArray and I want to do some additions inside of it. I do this by calling a functions with then create a subarray with the items where the calculations have to be done on.
- (NSDecimalNumber *)calculate:(NSMutableArray *)arrayToCalculate {
while ([arrayToCalculate containsObject:(#"+")]) {
NSUInteger signeLocation = [arrayToCalculate indexOfObject:(#"+")];
[arrayToCalculate replaceObjectAtIndex:(signeLocation-1)
withObject:([[arrayToCalculate objectAtIndex:(signeLocation-1)]
decimalNumberByAdding:[arrayToCalculate objectAtIndex:(signeLocation+1)]])];
[arrayToCalculate removeObjectsAtIndexes:
[NSIndexSet indexSetWithIndexesInRange:NSMakeRange((signeLocation), 2)]];
}
return [arrayToCalculate lastObject];
}
I initialised the arrayToCalculate by:
NSMutableArray *subArray =
[inputArray subarrayWithRange:(rangeOfCalculationItems)];
Every time I run this code it crashes. I am pretty sure it is bc I used subarray on an NSMutableArray and initialised it as NSMutableArray even when the message gives me back a NSArray, but I don't know how I could fix it or it is even the problem.
I copied your method and tested it like this:
NSArray *items = #[
[[NSDecimalNumber alloc] initWithString:#"1"],
#"+",
[[NSDecimalNumber alloc] initWithString:#"2"]
];
NSLog(#"%g", [self calculate: [items mutableCopy]].floatValue);
The code works and the printed result was 3. Your issue must be somewhere else. Are you sure your array is in fact mutable? Note [items mutableCopy].

NSMutableArray addObject returns nil

There are some similar questions that already exist on StackOverflow. I did check them out, and in most cases it returns nil because the NSMutableArray has not been initialised. But in my case I did initialise it.
Here's part of my code :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.storedTimeZones = [[NSMutableArray alloc] init];
NSData *storedData = [[NSUserDefaults standardUserDefaults] dataForKey:#"timeZones"];
if (storedData != nil ) {
self.storedTimeZones = [NSKeyedUnarchiver unarchiveObjectWithData:storedData];
}
NSString *str = [self.smallRegionArray[indexPath.row] stringByReplacingOccurrencesOfString:#"_" withString:#" "];
[self.storedTimeZones addObject: str];
NSLog(str); //the string was printed successfully.
NSLog(#"%lu", (unsigned long)self.storedTimeZones.count); //'0' was printed
}
update
#Caleb was right, [NSKeyedUnarchiver unarchiveObjectWithData:storedData returned nil. I solved it by doing this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.storedTimeZones = [[NSMutableArray alloc] init];
NSData *storedData = [[NSUserDefaults standardUserDefaults] dataForKey:#"timeZones"];
NSMutableArray *ary = [NSKeyedUnarchiver unarchiveObjectWithData:storedData];
if (ary != nil ) {
self.storedTimeZones = ary;
}
NSString *str = [self.smallRegionArray[indexPath.row] stringByReplacingOccurrencesOfString:#"_" withString:#" "];
[self.storedTimeZones addObject: str];
NSLog(str);
NSLog(#"%lu", (unsigned long)self.storedTimeZones.count); //Now it prints `1`
}
But in my case I did initialise it.
You did, but then you replaced it. Here's the initializing line:
self.storedTimeZones = [[NSMutableArray alloc] init];
but then you assign a different value:
self.storedTimeZones = [NSKeyedUnarchiver unarchiveObjectWithData:storedData];
and at this point, self.storedTimeZones may be either a non-mutable instance of NSArray, or some entirely different object, or nil. I'd guess it's the latter since no exception is thrown when you call -addObject:. That the count is 0 also makes sense if self.storedTimeZones is nil, since the result of messaging nil is nil or 0 or NO, depending on what type you expect.
All you really need to do to properly diagnose the problem is to examine self.storedTimeZones near your last NSLog statement. Set a breakpoint and look at the contents of that property. Useful commands will be:
po self.storedTimeZones
po [self.storedTimeZones class]
You're trying to assign the object to the entire mutable array, you're not adding a object to it.
That's not the way it works.
Try this:
[self.storedTimeZones addObject:
[NSKeyedUnarchiver unarchiveObjectWithData:storedData]];
Or this
[self.storedTimeZones addObjectsFromArray:[NSKeyedUnarchiver unarchiveObjectWithData:storedData]];
Or this
self.storedTimeZones = [NSArray alloc]; // Note: not a mutable array
[self.storedTimeZones initWithArray:[NSKeyedUnarchiver unarchiveObjectWithData:storedData]];
You've never told us if the contents of the keyedUnarchiver is an array, but we expect it is.
In either case, if this is the only time you add info to the array, you don't need to make it mutable.
Good luck.

Returning an NSMutableArray in objective C

I have been trying to work out how to return an MSMutableArray in objective c, I have this code here.
- (NSMutableArray*)generateRandomNumber{
NSMutableArray *unqArray=[[NSMutableArray alloc]init];
int randNum;
int counter = 0;
while (counter< 6) {
randNum = arc4random_uniform(40.0);
if (![unqArray containsObject:[NSNumber numberWithInt:randNum]]) {
[unqArray addObject:[NSNumber numberWithInt:randNum]];
counter++;
}
}
return unqArray;
}
- (IBAction)button:(id)sender {
NSMutableArray *results = [[NSMutableArray alloc]init];
*results = generateRandomNumber();
}
This is my code at the moment, where it says,
NSMutableArray *results = [[NSMutableArray alloc]init];
I get the following errors...
Implicit declaration of function 'generateRandomNumber' is invalid in C99
Assigning to 'NSMutableArray' from incompatible type 'int'
If anybody is willing to show me my mistake and help me out as well as many others I will appreciate it as much as possible.
Thanks to all who help me out!!!
generateRandomNumber is a method, not a C function, so use [self generateRandomNumber] to call it, and you are assigning results incorrectly, so:
results = [self generateRandomNumber];
Alternatively if you want to define it as a C function, use:
NSMutableArray *generateRandomNumber() {
...
}
Also, as pointed-out by #Larme, there is no need to allocate results before assigning it from generateRandomNumber.
- (IBAction)button:(id)sender {
NSMutableArray *results = [[NSMutableArray alloc]init];
results = [self generateRandomNumber];
}
Or more simply:
- (IBAction)button:(id)sender {
NSMutableArray *results = [self generateRandomNumber];
// Do something with this Array
}
Though you should consider a different name for that method as currently it sounds like it is returning one number, not an array of random numbers.
When calling/using a function in Objective-C
it's [self generateRandomNumber]
When you declare a variables it's NSMutableArray *results = [[NSMutableArray alloc]init]; and use if like results = mutableArry, * before it is not needed..
about your problem, you better do it like this:
- (IBAction)button:(id)sender
{
NSMutableArray *results = [self generateRandomNumber];
}
you dont need to allocate anymore, because you are passing an mutable array that is already allocated..
Your method generateRandomNumbers should work as expect the problem is here:
- (IBAction)button:(id)sender {
NSMutableArray *results = [[NSMutableArray alloc]init];
*results = generateRandomNumber();
}
The first thing is that you are creating an unneeded mutable array, second your are trying to substitute the value of the pointer that points to result array, third generateRandonNumber is a method not a function you should call it like [self generateRandomNumber].
Also I would implement a optimization since I'm pretty sure that you are not going to modify the random number array, the returned instance should be an immutable copy.
Here the final code:
- (NSArray*)generateRandomNumber{
NSMutableArray *unqArray=[[NSMutableArray alloc]init];
int randNum;
int counter = 0;
while (counter< 6) {
randNum = arc4random_uniform(40.0);
if (![unqArray containsObject:[NSNumber numberWithInt:randNum]]) {
[unqArray addObject:[NSNumber numberWithInt:randNum]];
counter++;
}
}
return unqArray.copy;
}
- (IBAction)button:(id)sender {
NSArray *results = nil;
results = [self generateRandomNumber];
}
Your generateRandomNumbers method should work with no problem, but in the IBAction there you try to put an INT directly into the array, you need to wrap it in an NSNumber like you have in the other method there
Your method is correct.
What you are doing wrong is here: *results = generateRandomNumber();
There is no need of an * here,because in this way you are trying to assign the pointer address of your array to results object.
Secondly you are trying to call an Objective-C method in C syntax.
So the correct syntax would be: results = [self generateRandomNumber];

Looping thru NSArray of NSString logic

I need help with the following:
I have an NSArray with NSStrings, I want to loop thru these strings and find a matching string, when match is found the strings after this match will be extracted into an NSDictionary until a certain other match is hit.
Here is an example:
NSArray *array = #[#"Fruit",#"Apple",#"Vegtable",#"Tomato",#"Fruit",#"Banana",#"Vegtable",#"Cucumber"];
So I want to loop thru this array and split it in 2 arrays one for fruit and one for vegetable.
Anyone can help with the logic?
Thanks
This is probably the simplest way to solve the problem:
NSArray *array = #[#"Chair",#"Fruit",#"Apple",#"Orange",#"Vegetable",#"Tomato",#"Fruit",#"Banana",#"Vegetable",#"Cucumber"];
NSMutableArray *fruitArray = [NSMutableArray array];
NSMutableArray *vegetableArray = [NSMutableArray array];
NSMutableArray *currentTarget = nil;
for (NSString *item in array)
{
if ([item isEqualToString: #"Fruit"])
{
currentTarget = fruitArray;
}
else if ([item isEqualToString: #"Vegetable"])
{
currentTarget = vegetableArray;
}
else
{
[currentTarget addObject: item];
}
}
In one iteration over the array, you just keep adding items to a result array using a pointer to one of two result arrays according to the last occurrence of the #"Fruit" or #"Vegetable" string.
This algorithm ignores all items before the first occurrence of the #"Fruit" or #"Vegetable" string, because the currentTarget is initialized to nil, which ignores the addObject: messages. If you want different behaviour, just change the initialization.
You said you wanted the results in a NSDictionary, but didn't specify what should be the key. If you want one NSDictionary with two keys, Fruit and Vegetable, and values NSArrays containing the items, just use the arrays previously created:
NSDictionary *dict = #{ #"Fruit": fruitArray, #"Vegetable": vegetableArray };
PS: You have a typo in your example, Vegtable instead of Vegetable. I corrected it in my code, so keep it in mind.
If I completely understand you:
NSArray *array = #[#"Fruit",#"Apple",#"Vegtable",#"Tomato",#"Fruit",#"Banana",#"Vegtable",#"Cucumber"];
NSMutableArray *fruits = [NSMutableArray array];
NSMutableArray *vegtables = [NSMutableArray array];
for (NSInteger i = 0; i < array.count; ++i){
if ([array[i] isEqualToString:#"Fruit"]){
++i;
[fruits addObject:array[i]];
}
else if ([array[i] isEqualToString:#"Vegtable"]){
++i;
[vegtables addObject:array[i]];
}
}

getting a "NSOrderedSetArrayProxy was mutated while being enumerated" error without mutation

I have two functions:
one that returns an array that is filled in a block
- (NSArray *)getArray {
NSArray *someValues = #[#0, #42, #23, #5, #8, #2013];
NSArray *filter = #[#42, #23, #5];
//replacing this NSMutableOrderedSet with a NSMutableArray
//and return just matched then, resolves the problem.
//so the exception has to do something with that set.
NSMutableOrderedSet *matched = [[NSMutableOrderedSet alloc] init];
for (id value in someValues) {
[filter enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isEqual:value])
[matched addObject:value];
}];
}
return [matched array];
}
and another one that enumerates the returned array from the first method
- (void)enumArray:(NSArray *)array {
NSEnumerator *enumerator = [array objectEnumerator];
for (id obj in enumerator) {
if ([obj isEqual:#42])
[enumerator nextObject]; // <== this line causes the error!
}
}
If i now do something like that
NSArray *array = [foo getArray];
[foo enumArray:array];
i will get a NSGenericException with following message:
Collection <__NSOrderedSetArrayProxy: 0x123456> was mutated while
being enumerated
where the hell is something mutated. i don't get it. returning a copy from that array solves the problem, but i still don't get it.
The error has do something with the NSMutableOrderedSet, if i replace the set with an array i don't get an exception.
some screenshots, of exception thrown
You are using fast enumeration while altering an enumerator instance.
Basically it is a big no-no to modify an object that you fast enumerate over (that form of the for loop you are using uses fast enumeration). However, you use [enumerator nextObject]; to access the next object from the enumerator, but this modifies the enumerator by removing the current object from it. So it is your use of nextObject within a for...in loop that is mutating the enumerator.
Get past this problem quickly by using a while loop instead of the for loop, a bit like this:
- (void)enumArray:(NSArray *)array {
NSEnumerator *enumerator = [array objectEnumerator];
while ((id obj = [enumerator nextObject])) {
if ([obj isEqual:#42])
[enumerator nextObject];
}
}
This should get past the fast enumeration/mutation problem. Note, I have absolutely no idea why you want to move the enumerator on a step when obj is equal to 42, but am presuming within the context of the entire code-base that this makes sense!
The basic reason is, you can't edit/modify a mutable array while you're going through it.
So here are the two solutions,
1.Please use #synchronized() directive to lock the array while you mutate it.
- (void)enumArray:(NSArray *)array {
NSEnumerator *enumerator = [array objectEnumerator];
for (id obj in enumerator)
{
if ([obj isEqual:#42])
{
#synchronized(enumerator)
{
[enumerator nextObject]; // <== this line causes the error!
}
}
}
}
2.Just do a copy of you NSArray and use it
- (void)enumArray:(NSArray *)array {
NSEnumerator *enumerator = [[array copy] objectEnumerator];
for (id obj in enumerator)
{
if ([obj isEqual:#42])
{
[enumerator nextObject]; // <== this line causes the error!
}
}
}

Resources