I am new to iphone development, I am trying to load a NSMutableArray values into a table view, I am using code below for this which generates error as specified. Can some one help me in rectifying this error.
code :-
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [ShowList count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
NSString *cellValue = [ShowList objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
return cell;
}
error :-
2011-02-25 07:22:24.470 iPhone[1032:207] -[__NSArrayM isEqualToString:]: unrecognized selector sent to instance 0xab15d30
2011-02-25 07:22:24.471 iPhone[1032:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM isEqualToString:]: unrecognized selector sent to instance 0xab15d30'
*** Call stack at first throw:
Print Description of My NSMutableArray :-
2011-02-25 07:21:54.806[1032:207] (
(
"viral_tweeter",
default1571546,
default1570056,
twilightsaga,
"wp-monetizer",
viraltweetbuild,
"building_a_list",
yourtwittertips,
"twitter_profit",
mikesbi,
mikesbizz,
default1164341,
incbizztest,
default1164319,
iprotv,
iwantafreecopy1,
tweeterbuilder,
trafficlists,
myadsensenews,
mysafelistnews,
myviralnews,
safelistology,
slmembers,
slpmembers,
twonderlandlist,
noseospider,
yseospider,
digitallockdown,
alistblueprint,
classifiedtips,
incbizzblog,
"xit-trafficbeta",
twwidget,
jvtrafficfunnel,
instantmlmspage,
listbuldingmax,
"incbizz_tips"
)
)
code for parsing HTTP Get response :-
- (void)requestDataFetcher:(GTMHTTPFetcher *)fetcher finishedWithData:(NSData *)data error:(NSError *)error {
// this is only for testing whether the data is coming or not
// NSDictionary *tempDict = [GTMOAuthAuthentication dictionaryWithResponseData:data];
if (error)
{
NSLog(#"Error: in getting data after authentication : %#",[error description]);
}
else
{
// NSLog(#"Succcess: in getting data after authentication \n data: %#",[tempDict description]);
NSString* aStr;
aStr = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSDictionary *dictionary = [aStr JSONValue];
NSArray *keys = [dictionary allKeys];
Names = [[NSMutableArray alloc]init];
int i = 0;
// values in foreach loop
for (NSString *key in keys)
{
i++;
NSArray *items = (NSArray *) [dictionary objectForKey:key];
// NSLog(#" test %#", items);
if (i==3)
{
for (NSString *item in items)
{
NSString* aStrs= item;
// NSLog(#" test %#", aStrs);
NSDictionary *dict = aStrs;
NSArray *k = [dict allKeys];
for (id *it in k)
{
// NSLog(#"the child item: %#", [NSString stringWithFormat:#"Child Item -> %# value %#", (NSDictionary *) it,[dict objectForKey:it]]);
NSString *value = [it description];
if ( [value isEqualToString:#"name"])
{
NSString * value = (NSString*)[[dict objectForKey:it] description];
NSLog(value);
[Names addObject:value];
[[MySingletonClass sharedMySingleton] SetAweberList: value];
}
}
}
}
}
mShowList.hidden = FALSE;
}
}
#Ravi your array is array of array that is the ShowList is an array which has first object as array and that array is that
"viral_tweeter",
default1571546,
default1570056,
twilightsaga,
"wp-monetizer",
viraltweetbuild,
"building_a_list",
yourtwittertips,
"twitter_profit",
mikesbi,
mikesbizz,
default1164341,
incbizztest,
default1164319,
iprotv,
iwantafreecopy1,
tweeterbuilder,
trafficlists,
myadsensenews,
mysafelistnews,
myviralnews,
safelistology,
slmembers,
slpmembers,
twonderlandlist,
noseospider,
yseospider,
digitallockdown,
alistblueprint,
classifiedtips,
incbizzblog,
"xit-trafficbeta",
twwidget,
jvtrafficfunnel,
instantmlmspage,
listbuldingmax,
"incbizz_tips"
so you can do something like this.
NSString *cellValue = [[ShowList objectAtIndex:0] objectAtIndex:indexPath.row];
I assume UILabel's setText calls isEqualToString for some reason, so it crashes for the very first object in your array which is not a NSString.
Related
The top 3 cells in my tableview have a label that says the word 'Squirrels'. Is there a way to make it so that if a UILabel says 'Squirrels' in more than one cell in my table, to only show the first cell of the three?
E.g. if UILabel userName in tableviewCell is equal to #"Squirrels", only show one table
view cell in the table that contains Squirrels in the UILabel
Hope this makes sense. Thanks in advance!
EDIT: I've successfully retrieved the first array containing more than one common 'name' value (see edit to code below). That said, when I try and display these values (firstFoundObject) in my tableview I get the following crash error:
-[__NSDictionaryI objectAtIndex:]: unrecognized selector sent to instance 0x1c01a5a20 2017-10-03 23:01:51.728128-0700
pawswap[623:85420] *** Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[__NSDictionaryI
objectAtIndex:]: unrecognized selector sent to instance 0x1c01a5a20'
ViewController.m
- (int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *nodeTitle = self.messages[0][#"name"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name == %#", nodeTitle];
NSArray *filteredArray = [self.messages filteredArrayUsingPredicate:predicate];
id firstFoundObject = nil;
firstFoundObject = filteredArray.count > 0 ? filteredArray.firstObject : nil;
NSMutableArray *firstObjects = firstFoundObject;
return [firstObjects count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *nodeTitle = self.messages[0][#"name"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name == %#", nodeTitle];
NSArray *filteredArray = [self.messages filteredArrayUsingPredicate:predicate];
id firstFoundObject = nil;
firstFoundObject = filteredArray.count > 0 ? filteredArray.firstObject : nil;
NSMutableArray *firstObjects = firstFoundObject;
static NSString *PointsTableIdentifier = #"MyMessagesCell";
MyMessagesCell *cell = (MyMessagesCell *)[tableView dequeueReusableCellWithIdentifier:PointsTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"MyMessagesCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
NSDictionary *receivedSubjectLine = [firstObjects objectAtIndex:indexPath.row];
NSString *messageSubject = [receivedSubjectLine objectForKey:#"node_title"];
[cell.subjectLine setText:messageSubject];
NSDictionary *fromUser = [firstObjects objectAtIndex:indexPath.row];
NSString *userName = [fromUser objectForKey:#"name"];
[cell.senderName setText:userName];
NSDictionary *receivedBody = [firstObjects objectAtIndex:indexPath.row];
NSString *messageBody = [receivedBody objectForKey:#"body"];
[cell.fullMessage setText:messageBody];
NSDictionary *messageReceived = [firstObjects objectAtIndex:indexPath.row];
NSString *timeReceived = [messageReceived objectForKey:#"published at"];
NSLog(#"Message Received at %#", timeReceived);
[cell.receivedStamp setText:timeReceived];
return cell;
}
PREVIOUS
ViewController.m
#pragma mark - Table view data source
- (int)numberOfSectionsInTableView: (UITableView *)tableview
{
return 1;
}
- (int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.messages count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *PointsTableIdentifier = #"MyMessagesCell";
MyMessagesCell *cell = (MyMessagesCell *)[tableView dequeueReusableCellWithIdentifier:PointsTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"MyMessagesCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
NSDictionary *receivedSubjectLine = [self.messages objectAtIndex:indexPath.row];
NSString *messageSubject = [receivedSubjectLine objectForKey:#"node_title"];
[cell.subjectLine setText:messageSubject];
NSDictionary *fromUser = [self.messages objectAtIndex:indexPath.row];
NSString *userName = [fromUser objectForKey:#"name"];
[cell.senderName setText:userName];
NSDictionary *receivedBody = [self.messages objectAtIndex:indexPath.row];
NSString *messageBody = [receivedBody objectForKey:#"body"];
[cell.fullMessage setText:messageBody];
NSDictionary *messageReceived = [self.messages objectAtIndex:indexPath.row];
NSString *timeReceived = [messageReceived objectForKey:#"published at"];
[cell.receivedStamp setText:timeReceived];
return cell;
}
Basically the problem you are getting is due to firstObject is of type Dictionary and you are type casting it to NSMutableArray. Please check below line:
id firstFoundObject = nil; firstFoundObject = filteredArray.count > 0
? filteredArray.firstObject : nil;
If you see you have filteredArray.firstObject as Dictionary in your application which you capture in firstFoundObject but later you are making it NSMutableArray type here:
NSMutableArray *firstObjects = firstFoundObject;
And later when you try to get here, it crashes
NSDictionary *receivedSubjectLine = [firstObjects
objectAtIndex:indexPath.row];
The correct - basic - version of your code should look like
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *PointsTableIdentifier = #"MyMessagesCell";
MyMessagesCell *cell = (MyMessagesCell *)[tableView dequeueReusableCellWithIdentifier:PointsTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"MyMessagesCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
[cell.subjectLine setText:[self.recvMessage objectForKey:#"node_title"]];
[cell.senderName setText:[self.recvMessage objectForKey:#"name"]];
[cell.fullMessage setText:[self.recvMessage objectForKey:#"body"]];
[cell.receivedStamp setText:[self.recvMessage objectForKey:#"published at"]];
return cell;
}
Though it is not optimised but still it can do work for you.
COUNT ISSUE:
NSMutableDictionary *firstObjects = firstFoundObject;
return [firstObjects count];
In your code above you have inside the numberOfRowsInSection since you have firstFoundObject as dictionary so when you call [firstObjects count] which is a valid call and it returns the number of key in the dictionary.
You have modify it like :
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
{
NSInteger rowCount = filteredArray.count;
self.recvMessage = rowCount? filteredArray.firstObject: nil;
return rowCount? 1: 0;
}
and you have new data which actually stores the filtered object.
#property (nonatomic) NSDictionary *recvMessage;
Hope this helps.
Yes you can do it easily,
You will do it before run tableView,
for example :
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableDictionary* NameDictionary=[[NSMutableDictionary alloc] init];
NSString* PreviousName;
int oneTime=0;
for(int i=0;i<[self.messages count];i++){
NSDictionary *fromUser = [self.messages objectAtIndex: i];
NSString *userName = [fromUser objectForKey:#"name"];
if(oneTime==0)
{
PreviousName=userName;
[NameDictionary addObject:[self.messages objectAtIndex: i]];
oneTime=1;
}
if(oneTime!=0)
{
if([PreviousName isEqualToString: userName])
{
}
else{
[NameDictionary addObject:[self.messages objectAtIndex: i]];
}
PreviousName=userName;
}
}
}
When you ask to filter out cells with a senderName property equal to #"Squirrels", you're effectively asking to change your datasource after it has been set. This will cause problems in your numberOfRowsInSection method, which will return more rows than you need if any filtering takes place after the datasource is set.
As one of the comments to your answer suggests, "make a secondary array which contains unique elements of self.messages and work with this array." The array that makes up the datasource of the tableview should require no filtering. The tableview should just be able to present it.
If I had enough reputation to comment on the above answer, I would say that you're right that it doesn't work because self.messages doesn't change. Instead of collecting the "non-duplicate" objects in NameDictionary, consider collecting them in an NSMutableArray. This new, filtered array should be the datasource for your array. You may want to filter this array outside of this ViewController so that once the array arrives at this view controller it can just be assigned to self.messages.
If you're looking to exclude all duplicates, as opposed to just duplicates that appear next to each other, consider this answer.
I am parsing a json to display the contents in the tableview. I have the array containing parsed json being populated in getReceivedData which is called after the UITAbleView Delegate methods. So it is problem in populating tableview as when the compiler attempts to populate it the array is not yet initialized.
- (void)getReceivedData:(NSMutableData *)data sender:(RestAPI *)sender{
NSError * error=nil;
NSArray *receivedData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
NSString *dictionaryKey=#"department";
NSString *predicateString=#"software";
NSPredicate *predicate=[NSPredicate predicateWithFormat:#" %K == %# ", dictionaryKey,predicateString];
NSArray *shortlisted=[receivedData filteredArrayUsingPredicate:predicate];
for(int i = 0; i<shortlisted.count; i++)
{
NSDictionary *detailItems=[shortlisted objectAtIndex:i];
NSString *name=[detailItems objectForKey:#"emp_name"];
NSString *designation=[detailItems objectForKey:#"designation"];
NSString *email=[detailItems objectForKey:#"email"];
NSString *phone_no=[detailItems objectForKey:#"phone_no"];
// NSString *image=[detailItems objectForKey:#"url_path"];
dictionary1=[NSMutableDictionary dictionaryWithObjectsAndKeys:
name, #"keyname",
designation, #"keydesignation",
email, #"keyid",
phone_no, #"keyphone",
nil];
[myObject1 addObject:dictionary1];
}
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:
(NSInteger)section{
if(isfiltered==YES){
return [filteredArray count];
}
else{
return [myObject1 count];
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
MyTableCell *cell=[tableView dequeueReusableCellWithIdentifier:#"myCell"];
if(!cell){
[tableView registerNib:[UINib nibWithNibName:#"MyTableCell" bundle:nil]
forCellReuseIdentifier:#"myCell"];
cell=[tableView dequeueReusableCellWithIdentifier:#"myCell"];
}
if(isfiltered==NO)
{
NSDictionary * tmpdict= [myObject objectAtIndex:indexPath.row];
cell.nameLabel.text=[NSMutableString stringWithFormat:#"%#",[tmpdict objectForKeyedSubscript:#"keyname"]];
cell.designationLabel.text=[NSMutableString stringWithFormat:#"%#",[tmpdict objectForKeyedSubscript:#"keydesignation"]];
cell.idLabel.text=[NSMutableString stringWithFormat:#"%#",[tmpdict objectForKeyedSubscript:#"keyid"]];
cell.phoneLabel.text=[NSMutableString stringWithFormat:#"%#",[tmpdict objectForKeyedSubscript:#"keyphone"]];
cell.mainImg.image = [UIImage imageNamed:[tmpdict objectForKeyedSubscript:#"keyimage"]];
}
else{
NSDictionary * tmpdict= [filteredArray objectAtIndex:indexPath.row];
cell.nameLabel.text=[NSMutableString stringWithFormat:#"%#",[tmpdict objectForKeyedSubscript:#"keyname"]];
cell.designationLabel.text=[NSMutableString stringWithFormat:#"%#",[tmpdict objectForKeyedSubscript:#"keydesignation"]];
cell.idLabel.text=[NSMutableString stringWithFormat:#"%#",[tmpdict objectForKeyedSubscript:#"keyid"]];
cell.phoneLabel.text=[NSMutableString stringWithFormat:#"%#",[tmpdict objectForKeyedSubscript:#"keyphone"]];
cell.mainImg.image = [UIImage imageNamed:[tmpdict objectForKeyedSubscript:#"keyimage"]];
}
return cell;
}
This window was supposed to view the table
In a mutable dictionary first you have to give object then its key. You are doing wrong
for(int i = 0; i<shortlisted.count; i++)
{
NSDictionary *detailItems=[shortlisted objectAtIndex:i];
NSString *name=[detailItems objectForKey:#"emp_name"];
NSString *designation=[detailItems objectForKey:#"designation"];
NSString *email=[detailItems objectForKey:#"email"];
NSString *phone_no=[detailItems objectForKey:#"phone_no"];
dictionary1=[NSMutableDictionary dictionaryWithObjectsAndKeys:
name,#"keyname",
designation,#"keydesignation",
email,#"keyid",
phone_no,#"keyphone",
nil];
[myObject1 addObject:dictionary1];
}
Actually this is not correct way to intialize dictionary as you did, #"%#" is used %# is a placeholder in a format string for any object.
dictionary1=[NSMutableDictionary dictionaryWithObjectsAndKeys:
name,#"keyname",
designation,#"keydesignation",
email,#"keyid",
phone_no,#"keyphone",
nil];
I'm very new to Obj-c and I'm now creating a tableview to show what I have parsed from Json. Here's the code:
#import "ClasstableViewController.h"
#interface ClasstableViewController ()
#end
#implementation ClasstableViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"JSONRead";
NSString *testUrl = #"example.com";
NSURL *url = [NSURL URLWithString:testUrl];
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10];
NSData *JSONData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSArray *jsonResult = [NSJSONSerialization JSONObjectWithData:JSONData options:kNilOptions error:nil];
self.data = jsonResult;
NSMutableArray *_names = [NSMutableArray array];
for (id item in jsonResult)
[_names addObject:[NSString stringWithFormat:#"%#", item[#"Mon"]]];
self.names = _names;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [self.names count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.textLabel.text = self.names[indexPath.row];
return cell;
}
and I have change my tableview to the correct class in the identity inspector to ClasstableViewController, I see others have resolve their issues with this solution.
but I'm still getting this:
-[__NSCFString objectForKeyedSubscript:]: unrecognized selector sent to instance 0x7fd8835691c0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString objectForKeyedSubscript:]: unrecognized selector sent to instance 0x7fd8835691c0'
anyone have any idea why?
Probably your NSArray *jsonResult is an array of NSStrings, or contain some NSStrings as objects. So when you do
for (id item in jsonResult)
[_names addObject:[NSString stringWithFormat:#"%#", item[#"Mon"]]];
you are supposing that item is a NSDictionary, but it isn't.
for (id item in jsonResult)
[_names addObject:[NSString stringWithFormat:#"%#", item[#"Mon"]]];
item is NSString not NSDictionary,use like below
for (id item in jsonResult)
[_names addObject:[NSString stringWithFormat:#"%#", item]];
Use JSONEditor to check the JSON.
I am recieving this error when i scroll to the bottom of my TableView, I dont think its any error with actually retrieving the pictures from the server.:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFArray objectAtIndex:]: index (15) beyond bounds (15)'
Here is my .m file I cut it to only the actually needed parts of the file:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[self entries] count] + tweets.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row % 2 == 0) {
NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];
NSString *created = [tweet objectForKey:#"created_at"];
NSLog(#"%#", created);
static NSString *CellIdentifier = #"TweetCell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSString *text = [tweet objectForKey:#"text"];
NSString *name = [[tweet objectForKey:#"user"] objectForKey:#"name"];
cell.textLabel.text = text;
cell.detailTextLabel.text = [NSString stringWithFormat:#"by %#", name];
return cell;
}else {
static NSString *CellIdentifier = #"InstagramCell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSDictionary *entry = [self entries][indexPath.row];
NSString *imageUrlString = entry[#"images"][#"low_resolution"][#"url"];
NSURL *url = [NSURL URLWithString:imageUrlString];
[cell.imageView setImageWithURL:url];
return cell;
}
}
- (void)fetchTweets {
self.twitterClient = [[AFOAuth1Client alloc] initWithBaseURL:[NSURL URLWithString:#"https://api.twitter.com/1.1/"] key:#"TWEETER_KEY" secret:#"TWEETER_SECRET"];
[self.twitterClient authorizeUsingOAuthWithRequestTokenPath:#"/oauth/request_token" userAuthorizationPath:#"/oauth/authorize" callbackURL:[NSURL URLWithString:#"floadt://success"] accessTokenPath:#"/oauth/access_token" accessMethod:#"POST" scope:nil success:^(AFOAuth1Token *accessToken, id responseObject) {
[self.twitterClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
[self.twitterClient getPath:#"statuses/home_timeline.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSArray *responseArray = (NSArray *)responseObject;
[responseArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(#"Success: %#", obj);
tweets = responseArray;
[self.tableView reloadData];
}];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
} failure:^(NSError *error) {
NSLog(#"Error: %#", error);
}];
}
There needs to be tight coordination between the return value from numberOfRowsInSection and the array access that the code does in cellForRowAtIndexPath.
Consider this, your entries array and tweets array each have 4 elements. So numberOfRowsInSection returns 8. The cellForRowAtIndexPath method gets called to configure row 6. Your code will do this: NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];
But wait... that array has only 4 elements, right? Asking for something at index 6 will generate the crash you see.
It might be simpler to write a methods to interleave the arrays into a single array, then answer the count of the combined array in numberOfRowsInSection. In cellForRowAtIndexPath, the array elements themselves should be able to tell you what kind of row you have (not the index). Dereference the combined array and configure the table accordingly.
EDIT - I'll try to make my advice more explicit in code: Let's say, for simplicity, that "entries" and "tweets" are both arrays of NSDictionaries and that your app wants to organize them in the UI entries first, then tweets.
// in interface:
#property (nonatomic, strong) NSArray *myModel;
// in code:
- (NSArray *)myModel {
if (!_myModel) {
NSMutableArray *array = [NSMutableArray arrayWithArray:[self entries]];
[array addObjectsFromArray:tweets];
_myModel = [NSArray arrayWithArray:array];
}
return _myModel;
}
We call this 'myModel' for a reason. It's the datasource of the table. The datasource protocol is asking explicitly about this array (and no other).
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.myModel.count;
}
Now cellForRowAtIndexPath is going to ask you to configure that many (myModel count) rows, numbered 0..count-1. You must dereference the same array -- myModel -- for all datasource methods:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *myModelForThisRow = self.myModel[indexPath.row];
// get the cell = deque...
cell.textLabel.text = myModelForThisRow[#"someKey"];
return cell;
}
What if your tweets or entries array changes? No problem, just rebuild the model like this:
- (IBAction)tweetsOrEntriesDidChange:(id)sender {
self.myModel = nil; // the "lazy" getter will rebuild it
[self.tableView reloadData]; // this will call the datasource which will call the lazy getter
}
You are trying to go read into an array outside of it's bounds.
That array access look very suspicious
if (indexPath.row % 2 == 0) {
NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];
as well as this one
NSDictionary *entry = [self entries][indexPath.row];
From what I've seen your array tweets and [self entries] don't contain as many object each as there is row in your table section.
I take my assomption from here :
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[self entries] count] + tweets.count;
}
NSRangeException is thrown because you are trying to access an index which is not within the valid range for your array. Try setting an "Exception breakpoint" in Xcode to see where it's coming from. Check here to know more about Exception breakpoints
This is typically caused by an off by one error.
I would have thought 'self.data=' would retain the autorelease NSMutableArray objects and the NSMutableDictionary objects it contains, but eventually I get EXC_BAD_ACCESS when the table's cellForRowAtIndexPath method tries to access the NSDictionaries in self.data.
#property (strong, nonatomic) NSMutableArray *data;
- (void) updateReceivedData:(NSData *) jsonData
{
NSMutableArray *fetchedData = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
self.data = [self convertDates:fetchedData withFormat:kMySQLDateTimeFormat];
[self.tableView reloadData];
}
}
- (NSMutableArray*) convertDates:(NSMutableArray *) array withFormat:(NSString *) format
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:format];
NSMutableArray *newArray = [NSMutableArray arrayWithArray:array];
for (NSMutableDictionary *dict in newArray)
{
for (id key in dict.allKeys)
{
if ([[dict objectForKey:key] isKindOfClass:[NSString class]])
{
NSString *value = [dict objectForKey:key];
NSDate *date = [dateFormatter dateFromString:value];
if (date) [dict setObject:date forKey:key];
}
}
}
[dateFormatter release];
return newArray;
}
BAD_ACCESS HERE thrown here between the NSLogs.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cell";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSLog (#"Cell was nil");
cell = [[[CustomCell alloc] init] autorelease];
}
NSDictionary *dict = [[NSDictionary alloc] init];
if (_isFiltered){
dict = [self.filteredData objectAtIndex:indexPath.row];
} else {
dict = [self.data objectAtIndex:indexPath.row];
}
NSLog (#"Filling Label 1");
cell.IDLabel.text = [[dict objectForKey:#"Id"] stringValue];
NSLog (#"Filling Label 2");
cell.firstNameLabel.text = [dict objectForKey:#"firstName"];
[dict release];
return cell;
}
Turn on zombies and see if it catches the problem (EXC_BAD_ACCESS does not necessarily mean an over-released object, but it might).
What happens to the absolute value of the retain count of an object is irrelevant.
However, a strong property implies that the object is retained, yes, if you assign through the setter (i.e. self.data = ... and not _data = ...).
Why are you releasing the dict in cellForRowAtIndexPath: . Eventhough you allocate dict, you are assigning another pointer which is an object from filteredData or data. Just remove the [data release] and while declaring data assign it as nil
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cell";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSLog (#"Cell was nil");
cell = [[[CustomCell alloc] init] autorelease];
}
// **As you will be assigning the object from filteredData/data, don't allocate here**
NSDictionary *dict = nil;
if (_isFiltered){
dict = [self.filteredData objectAtIndex:indexPath.row];
} else {
dict = [self.data objectAtIndex:indexPath.row];
}
NSLog (#"Filling Label 1");
cell.IDLabel.text = [[dict objectForKey:#"Id"] stringValue];
NSLog (#"Filling Label 2");
cell.firstNameLabel.text = [dict objectForKey:#"firstName"];
// **Release not required as you didn't allocate**
//[dict release];
return cell;
}