NSMutableArray EXC_BAD_ACCESS (code=1) - objective-c

I have no idea why, but my NSMutableArray 'items' will not take more than 5 elements.
Can someone please help? I'm following the Big Nerd Ranch iOS Programming book.
This code works fine:
NSMutableArray *items = [[NSMutableArray alloc] init];
for (int i = 5; i < 10; i++) {
BNRItem *p = [BNRItem randomItem];
[items addObject:p];
}
However if I change the initial value of i to 4 or less the program crashes when exiting the for loop:
NSMutableArray *items = [[NSMutableArray alloc] init];
for (int i = 4; i < 10; i++) {
BNRItem *p = [BNRItem randomItem];
[items addObject:p];
}
Error screenshot: http://db.tt/3CdueSYh

Change your
NSArray *randomNounList = [NSArray arrayWithObjects:#"Bear", #"Spork", "Mac", nil];
to:
NSArray *randomNounList = [NSArray arrayWithObjects:#"Bear", #"Spork", #"Mac", nil];
You forgot # before "Mac"
Hope it helps

In the screenshot you posted in your comments you are adding a C string, "Mac", to your randomNounList array. You need to make this an NSString with an # symbol.
I suspect the crash is occurring when this entry is randomly selected.
I'm surprised this compiled, I suspect you are ignoring some warnings.

Related

NSMutableArrays and memory in loops

Apologies first of all for the rather vague title but I'm not entirely sure how to categorise the question.
I'm using Xcode 8.1 on High Sierra and I've been banging my head against what really ought to be a simple piece of code. I think I'm failing to grasp something key about Objective-C memory allocation.
So, first something I seem to have sorted.
I tried the following code:
fullDetails = [[NSArray alloc] init];
for( lineContent in fileByLine)
{
fullDetails = [lineContent componentsSeparatedByString:#"\t"];
}
When I run this I get 27 entries in fileByLine and fullDetails correctly gets populated, line by line. However, nothing goes into fullDetails, despite the fact that it has been initialised. I worried that it is somehow nil until an initial value is inserted, so I also tried populating by index, with the index starting at zero. Same effect.
However, the following code works fine:
for( lineContent in fileByLine)
{
fullDetails = [[NSArray alloc] initWithArray:[lineContent componentsSeparatedByString:#"\t"]];
}
(I did say it ought to be really simple.)
So, I understand how to get the result I want but I really don't see why the first gobbet doesn't work. I guess it's something about the scope of the variable inside and outside the for loop - but why?
I now come to the real problem (for me). In the expanded gobbet:
NSString *newEntry = [[NSString alloc] init];
NSMutableArray *workingArray = [[NSMutableArray alloc] init];
for( lineContent in fileByLine)
{
fullDetails = [[NSArray alloc] initWithArray:[lineContent componentsSeparatedByString:#"\t"]];
newEntry = [fullDetails objectAtIndex:1];
[workingArray addObject:newEntry];
}
everything works fine (including newEntry) but I am unable to add the iterated newEntry items to the workingArray: I don't get an error; just 0 entries.
I've tried various mods to the addObject line. In particular, I worried that it was simply overwriting a single NSString store (although, even then, I should have had one item). So I tried:
NSString *newEntry = [[NSString alloc] init];
NSMutableArray *workingArray = [[NSMutableArray alloc] init];
for( lineContent in fileByLine)
{
fullDetails = [[NSArray alloc] initWithArray:[lineContent componentsSeparatedByString:#"\t"]];
newEntry = [fullDetails objectAtIndex:1];
[workingArray addObject:[[NSString alloc] initWithString:newEntry]];
}
and
NSMutableArray *workingArray = [[NSMutableArray alloc] init];
for( lineContent in fileByLine)
{
fullDetails = [[NSArray alloc] initWithArray:[lineContent componentsSeparatedByString:#"\t"]];
NSString *newEntry = [[NSString alloc] initWithString:[fullDetails objectAtIndex:1]];
[workingArray addObject:[[NSString alloc] initWithString:newEntry]];
}
and
NSMutableArray *workingArray = [[NSMutableArray alloc] init];
for( lineContent in fileByLine)
{
fullDetails = [[NSArray alloc] initWithArray:[lineContent componentsSeparatedByString:#"\t"]];
[workingArray addObject:[[NSString alloc] initWithString:[fullDetails objectAtIndex:1]]];
}
So, please tell me what I'm missing. I'm sure it's something pretty obvious but I can't see it.
I upgraded Xcode (to version 9.4.1) and it now works fine. So, it appears to have been a bug in the old version (although I'm loathe to cry, "bug!": it's too easy a solution). Anyway, one answer that ought to have been obvious: make sure I'm using the latest version.

Twodimensional array into a UILabel

I have a twodimensional array where i i would like to print all second values of the objects into an UIlabel homePlayersFouls. the problem is i do not know how to this.
I have tried following things:
componentsJoinedByString:#"\n".
This will just print (
The other thing ive tried is this:
[[homePlayersArray objectAtIndex:i] objectAtIndex:1];
this just prints 0 since it looping and deleting the content inside label
i've checked wether there is something wrong the the array, but when i do this inside the loop:
nslog(#"%#",[[homePlayersArray objectAtIndex:i] objectAtIndex:1];);
It prints all 0 0 0 which is the 3 second values in my objects.
The question is then how can i print all my second values in all the objects in the array into an UIlabel?
here is the complete code:
for (int i=0;i<[homeNumbersArray count];i++){
NSArray *tempArray = [[NSArray alloc] initWithObjects:[homeNumbersArray objectAtIndex:i],[NSNumber numberWithInt:0], nil];
[homePlayersArray addObject:tempArray];
NSObject* someObject = [[homePlayersArray objectAtIndex:i] objectAtIndex:1];
homePlayersFouls.text = [NSString stringWithFormat:#"%#", someObject];
}
You need:
homePlayersFouls.text = [homePlayersFouls.text stringByAppendingString:[NSString stringWithFormat:#"%#", someObject]];
NSMutableString *fouls = [NSMutableString string];
for (int i=0;i<[homeNumbersArray count];i++){
NSArray *tempArray = [[NSArray alloc] initWithObjects:[homeNumbersArray objectAtIndex:i],[NSNumber numberWithInt:0], nil];
[homePlayersArray addObject:tempArray];
NSObject* someObject = [[homePlayersArray objectAtIndex:i] objectAtIndex:1];
[fouls appendFormat:#"%#", someObject];
}
homePlayersFouls.text = fouls;

Memory issue with NSArray and ARC

I try to write a program in Objective C that calculates some stuff. Unfortunately there is a lot to calculate and the Program is running a loop with 10000 iterations. The total running time is around 5 minutes.
This isn't an issue but while it is running the memory the program uses goes up dramatically (above to 2GB) and I figure it is because of some Values that are not released. I narrowed the problem down to a creation of a NSArray inside a loop. The problematic code (changed it to concentrate on the problem) is this:
for (NSInteger k = 0; k<100000; k++) {
NSMutableArray *mutableTestArray = [NSMutableArray new];
for (NSInteger i=0; i<200; i++){
NSMutableArray *subArray = [NSMutableArray new];
for (NSInteger j=0; j<200; j++) {
//simplified version, normally the valus for sub array are dependent on some other factors
[subArray addObject:[NSArray arrayWithObjects:#"test", #"test", nil]];
}
[mutableTestArray addObject:subArray];
}
//do stuff with mutableTestArray
//change parameters that go into sub array
}
If I replace:
[subArray addObject:[NSArray arrayWithObjects:#"test", #"test", nil]];
with:
[subArray addObject:#"test"];
it works fine. So I guess I somehow have to release the Array I created. But how?
I have ARC enabled and as far as I know if it is enabled I can't release objects manually. It would be great if someone could help me with how to change the code or hint me somewhere where I can learn how to do memory management correctly.
Thanks
Just throw in some autoreleasepools :
#autoreleasepool {
NSMutableArray *subArray = [NSMutableArray new];
for (NSInteger j=0; j<200; j++) {
#autoreleasepool {
//simplified version, normally the valus for sub array are dependent on some other factors
[subArray addObject:[NSArray arrayWithObjects:#"test", #"test", nil]];
}
}
[mutableTestArray addObject:subArray];
}
[NSArray arrayWithObjects:#"test", #"test", nil]; returns with an autoreleased object and it will be released somewhere in the future, but not immediatelly.
Use [[NSArray alloc] initWithObjects:#"test", #"test", nil]; and the array will be released almost immediatelly, because of ARC.
If you wouldn't use ARC the code could be the following:
NSArray* tempArr = [[NSArray alloc] initWithObjects:#"test", #"test", nil];
// use the temporary variable
[subArray addObject:tempArr];
[tempArr release];
Because you are using ARC, you should remove the release.

Method Creates an Array with 11 objects, All Out of Scope, Unrecognized Selector Results

Okay, so, I'm doing a simple lookup. I have an array of NSString objects and a string to search for in the array's elements.
It all seems to work up until I try to add a match to a new mutable array made to hold the search results. The stringHolder variable gets the string, and resultsCollectorArray even get the right number of new elements, but each element is empty and "out of range". Here's the method:
#implementation NSArray (checkForString)
-(NSMutableArray *) checkForString: (NSString *) matchSought
{
long unsigned numberofArrayElements;
long unsigned loop = 0;
NSRange searchResults;
NSMutableArray * resultCollectorArray = [[NSMutableSet alloc] init];
id stringHolder;
numberofArrayElements = [self count];
while (loop < numberofArrayElements) {
searchResults.length = 0;
searchResults = [[self objectAtIndex: loop] rangeOfString: matchSought options:NSCaseInsensitiveSearch];
if (searchResults.length > 0) {
stringHolder = [self objectAtIndex: loop];
[resultCollectorArray addObject: stringHolder];
}
loop++;
}
return [resultCollectorArray autorelease];
}
Once we get back to the main portion of the program, I get an unrecognized selector sent to the mutable array that was supposed to receive the result of the method. Here's the main section:
#import <Foundation/Foundation.h>
#import "LookupInArray.h"
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *testString = [[NSString alloc] initWithString: #"ab"];
NSMutableString * resultString = [[NSString alloc] init];
NSArray * theArray = [[NSArray alloc] initWithObjects: ..., nil]; // Actual code has the objects
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSUInteger arrayCount = 0;
unsigned long loops = 0;
resultArray = [theArray checkForString: testString];
arrayCount = [resultArray count];
while (loops < arrayCount){
resultString = [resultArray objectAtIndex: loops]; // Here's where we get the unrecognized selector.
NSLog(#"%#", resultString);
loops++;
}
[pool drain]; // Also, I'll release the objects later. I just want to get what's above working first.
return 0;
}
I've searched the other answers (for hours now), but didn't seen anything that solved the issue.
Any and all help would be really appreciated.
And thanks beforehand.
NSMutableArray * resultCollectorArray = [[NSMutableSet alloc] init]; is so incorrect. You are creating a mutable set and assigning it to a mutable array.
You are getting unrecognized selector because objectAtIndex: is not a valid selector for NSMutableSet. Make that statement,
NSMutableArray * resultCollectorArray = [[NSMutableArray alloc] init];
A Better way
NSArray * filteredArray = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF contains[cd] %#", searchString]];
You can directly filter the array using predicates. This way you do this in a single step. :)

Objective-C memory leak confusion

Obviously the following in the main method should lead to a leak:
NSMutableArray *strings = [[NSMutableArray alloc] init];
[strings addObject:#"Hello"];
[strings addObject:#"Howdy"];
return 0;
and the clang LLVM reports the leak. However, working through the Hillegass book, I tried analyzing the following code, which again does not release the NSMutableArray object:
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *array = [[NSMutableArray alloc] init];
NSCalendarDate *now = [[NSCalendarDate alloc] init];
for (int i=0; i < 3; i++) {
LotteryEntry *newEntry = [[LotteryEntry alloc] init];
NSCalendarDate *iweeksFromNow = [now dateByAddingYears:0
months:0
days:(i*7)
hours:0
minutes:0
seconds:0];
[newEntry setEntryDate:iweeksFromNow];
[array addObject:newEntry];
[newEntry release];
}
[now release];
for (LotteryEntry *entry in array) {
NSLog(#"%#", entry);
}
[pool drain];
return 0;
This time there was no leak reported. Am I missing something obvious?
I don't think you areā€”the static analyzer's just missing it. array does end with a retain count of 1; if the line were
NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
then the enclosing autorelease pool would take care of it, but as it stands the array's definitely still leaking.
I've asked this on the cfe-dev list and the answer is analysis in loops is halted at a given threshold (only 2 loop iterations are walked through).
If you change your exit condition (for (int i=0; i < 2; i++)) the static analyzer will signal the leak.