Application crashing on numberOfRowsSection - objective-c

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [array count]; // <--- Crashes here
}
I'm not sure why it is crashing considering the array is a simple NSArray.

Your "array" must not be an NSArray. Can you provide some context for where array is defined? Are you using ARC?
A simple test would be to put the following line before that return statement:
NSLog(#"array = %#; array class = %#", array, array.class)
Paste the output from that and I can help you further! My guess currently is that array is being deallocated, and there's some other (or garbage) property in that memory. I wouldn't be surprised if you saw that array.class was an NSNumber...

Related

DFS algorithm implementation at Objective C

I am trying to implement the Objective C realization of this algorithm. Here the implementation of it:
#implementation DFSAlgorithm
-(void)dfs:(Graph*)g andStartingPosition:(int)s{
[self performDFS:g andPosition:s];
}
-(void)markedArrayInit:(int)capacity{
//0 is for unmarked vertices
//1 is form marked ones
self.marked=[[NSMutableArray alloc]initWithCapacity:capacity];
for(int i=0;i<[self.marked count];i++)
[self.marked replaceObjectAtIndex:i withObject:[NSNumber numberWithInt:0]];
}
-(void)performDFS:(Graph *)g andPosition:(int)v{
[self markedArrayInit:(int)[g numberOfVertices]];
[self.marked replaceObjectAtIndex:v withObject:[NSNumber numberWithInt:1]];
for (NSNumber *vertex in [g.vertices objectAtIndex:v]){
if(1==[self isMarked:v atGraph:g]){
NSLog(#"%d",(int)vertex);
[self performDFS:g andPosition:(int)vertex];
}
}
}
-(int)isMarked:(int)v atGraph:(Graph *)g{
return [self.marked objectAtIndex:v];
}
#end
However, I don't understand why the following error occurs:
[__NSArrayM replaceObjectAtIndex:withObject:]: index 0 beyond bounds for empty array'
How can I correctly initialize the marked array?
Thank you.
An NSMutableArray is created empty, the capacity value you pass is just a hint to the implementation about how large you expect the array to become.
Therefore replaceObjectAtIndex:withObject: does not work for you, as the array is empty you have no objects to replace.
Instead just use addObject: capacity times.
In your markedArrayInit method you create empty mutable array and reserve memory for it to hold at least capasity number of items. But you do not actually add anything to it (for loop in that method does not actually do anything at all). To fix your problem you can add enough number of items in for loop:
for (int i=0;i< initWithCapacity:capacity;i++)
[self.marked addObject: #0];
}
Edit:
Your implementation has several other problems:
you initialize marked array on each call to performDFS:andPosition:, and call that method recursively. You should move initialization to dfs:andStartingPosition: method
In isMarked:atGraph: method you return object from array, not the numeric value it holds - so it will never be 1, you might want to replace it with the following implementation (Note that method name implies we return some boolean value, not an integer that we'll need to interpret later):
-(BOOL)isMarked:(int)v atGraph:(Graph *)g {
return [self.marked[v] intValue] == 1;
}
...
if([self isMarked:v atGraph:g]){
...
}
There're better data structures to store indices of marked nodes, e.g. NSSet or NSIndexSet
You try to replace not existing object inside array. In markedArrayInit use addObject: method from NSMutableArray. [self.marked count] is always 0 in for cycle.

TableView doesn't allow for 'section' in dictionary

I want to loop through a list of json items to use in my sectioned tableView. For this I would like to restructure the data to have a section->array setup, where array contains an array of sessions.
First of all, I don't know if this is the preferred way to go, there may be easier ways. I keep getting the error that I am not allowed to use 'section' as an identifier in the dictionary. Moreover, when I use something else than a 'section' the dictionary keeps getting overridden.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSString *day = _json[#"days"][3];
NSString *key;
NSUInteger count = 0;
NSMutableArray *sessionList = [[NSMutableArray alloc] init];
NSArray *timeslotsSorted = [[_json[#"schedule"][day] allKeys]
sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSArray *locationsSorted = [[_json[#"schedule"][day][timeslotsSorted[section]] allKeys]
sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
for (key in locationsSorted) {
NSDictionary *temp = _json[#"schedule"][day][timeslotsSorted[section]][key];
if ([temp isKindOfClass:[NSDictionary class]]) {
[sessionList addObject:temp[#"title"]]; //test array
count++;
}
}
_sessionDict = #{
section: sessionList
};
return count;
}
You are doing all the work to build your data structure in the wrong place. Lets say there are 10 sections in your data. This will call the tableView: numberOfRowsInSection method 10 times which makes this a pretty inefficient place to do much work. You will also have to implement the method that returns the number of sections to show, and the method to display each individual row.
I would build my data structures in the viewWillLoad method and then store it locallaly and reuse it in all the tableView methods.
First, this is what NSInteger is:
typedef int NSInteger;
You must wrap it into an object. Something like:
[NSNumber numberWithInteger:section]
And than add it to your dictionary.
i don't really know that your timeslotsSorted and locationsSorted contain right items, but lets say they do. I would recommend you to have this sorting before - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section and - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; are called.
Lets say, you received JSON, so you have to parse it as you do, and then call [tableView reloadData] or reload visible cells with animations.
and then your tableView data source methods will be called and you will do something like:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [sessionList count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSString* key = [self.sessionList objectAtIndex:section];
return [[self.secions objectForKey:key] count];
}
and don't forget to make strong properties for self.sections and self.sessionList

EXC_BAD_ACCESS error when removing object from NSMutableDictionary

I have a NSMutableDictionary as the datasource for my UITableView. I am trying to implement the delete mode and having an issue.
I am logging the key I am trying to remove as well as the object that it corresponds to as this issue seems like it might be related to my trying to access unallocated memory or something. Here is my implementation of tableView:commitEditionStyle:forRowAtIndexPath:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source.
NSArray * keys = [userList allKeys];
NSNumber *keyToRemove = [keys objectAtIndex:indexPath.row];
NSLog(#"Key to remove: %#",keyToRemove);
NSLog(#"Object at key: %#",[userList objectForKey:keyToRemove]);
[userList removeObjectForKey:keyToRemove];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[keys release];
[keyToRemove release];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
This method runs and then I get the error. The two NSLog statements output the correct key and it's corresponding value.
Can someone tell me what I'm doing wrong?
Thanks
You don't own keys or keysToRemove, so you should not be releasing them. I strongly suggest reading up on the Cocoa memory management rules.
Here's your problem:
[keys release];
[keyToRemove release];
You are releasing keys and keyToRemove, even though you never allocated it, retained it, or copied it, so it's reference count is decreasing more than it should.
As a general rule, you should only release an object if you called alloc, retain (not init, sorry) or copy on it, I recommend you read on reference counting here: Practical Memory Management

NCSFDictionary, Mutating method sent to immutable object

I have just started to jump into the realm of Objective-C and am slowly getting it all. I have been working on unarchiving a file that was a NSMutableArray and then initializing in my model with that array. The array is filled with various NSMutableDicationary's. From what I have seen it will add those dictionaries as non-mutable, so I went ahead and copied the regular and put them in a mutable and remove the old one. This solution seems to work for every instance except the very first.
I am at a loss as to why it would work for all but the first.
Here is how I am initializing it all
-(id) initWithList:(NSMutableArray *)savedList
{
self = [super init];
if (self)
{
int size=0;
serverList=[[NSMutableArray alloc] initWithArray:savedList copyItems:YES];
size=[serverList count];
for(int i=0;i<size;i++)
{
loginList=[NSMutableDictionary dictionaryWithDictionary:[serverList objectAtIndex:i]];
[serverList addObject:loginList];
[serverList removeObjectAtIndex:i];
}
}
return self;
}
Here is the code that is throwing the error, The value is being read off of a checkbox in a tableview and passed here to change the value.
-(void)setMount:(int)row value:(NSNumber*)boolAsNumber
{
[[serverList objectAtIndex:row] setObject:boolAsNumber forKey:#"mountshare"];
}
Here is the error that it shows when I try and change the first element
2010-12-01 13:38:54.445 Network Share[35992:a0f] *** -[NSCFDictionary setObject:forKey:]: mutating method sent to immutable object
Thanks for your help. If there is a better way please let me know.
This loop code is wrong:
size=[serverList count];
for(int i=0;i<size;i++)
{
loginList=[NSMutableDictionary dictionaryWithDictionary:[serverList objectAtIndex:i]];
[serverList addObject:loginList];
[serverList removeObjectAtIndex:i];
}
When you remove an object, the array is renumbered. After you've processed the 1st object at index 0, the original 2nd object is becoming the 1st object at index 0, but i is now set to index 1, which is where the original 3rd object is! This means you're only processing alternate items from the original array, and the 2nd, 4th, etc items never get swapped, and that's why you get the errors you're seeing.
One way to solve this would be to replace the "i" in the objectAtIndex: and removeObjectAtIndex: calls with "0", so you're always taking items off the front of the array.
The alternate solution would be to create a separate newServerList array and insert your new objects into that. At the end of the loop, release the old serverList and set the variable to point to newServerList.
Your indexes are messed up. As soon as you remove the object at index 0, the next one will take it's place and you will never replace that, because you then carry on with index 1.
{immutable0, immutable1}
i = 0:
addObject:
{immutable0, immutable1, mutable0}
removeObjectAtIndex:
{immutable1, mutable0}
i = 1:
addObject:
{immutable0, mutable0, mutable02}
removeObjectAtIndex:
{immutable0, mutable02}
--> still got the immutable there. Remember to never remove objects from a mutable array you are looping through at the same time.
You could condense the code a bit:
NSMutableArray *serverList = [NSMutableArray arrayWithCapacity:[savedList count]];
for (NSDictionary *dictionary in savedList)
{
mutable = [dictionary mutableCopy];
[serverList addObject:mutable];
[mutable release];
}
Unrelated to your problem: the argument is obviously wrong (NSMutableArray), if you expect an immutable array there; and if you create your serverList that way, there is no need for a deep copy (copyItems:YES).

UITableView titleForHeaderInSection prints headers to console twice then crashes

In the method below titleForHeaderInSection, for some reason the NSLog prints out the headers twice and then the app crashes in objc_msgSend. I can't understand why this would cause the app to crash?
It would seem from research that crashes in objc_msgSend are caused by sending messages to already freed objects, but is that the case here?
My sectionNames array is populated in viewDidLoad.
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSString *title = nil;
title=[sectionNames objectAtIndex:section];
NSLog(title);
return title;
}
Thanks
How are you populating your sectionNames array? It's possible that the array, not the string, is getting released prematurely.
UPDATE:
Your problem is that +arrayWithArray: creates an autoreleased array, which gets released when the current run loop finishes. You need to either retain sectionNames or use -initWithArray: