NSArray elements which have from NSSet not displayed in TableViewCell - objective-c

I have NSArray elements which is implemented from NSSet and if i tried to display the elements in Table View Cell i'm getting BAD ACCESS issue at tableView numberOfRowsInSection part.Here is my code
- (void)viewDidLoad
{
[super viewDidLoad];
jsonurl=[NSURL URLWithString:#"http://www.sample.net/products.php"];//NSURL
jsondata=[[NSString alloc]initWithContentsOfURL:jsonurl];//NSString
jsonarray=[[NSMutableArray alloc]init];//NSMutableArray
self.jsonarray=[jsondata JSONValue];
array=[jsonarray valueForKey:#"post_title"];
set = [NSSet setWithArray:array];//NSMutableSet
array=[set allObjects];//NSArray
NSLog(#"%#",array);
}
#pragma mark - Table view data source
- (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 [array count];
}
- (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...
cell.textLabel.text = [self.array objectAtIndex: [indexPath row]];
return cell;
}
Kindly help please.Thanks in advance.

In your code you are not allocating the array. You are setting an autoreleased object to that array that's why you are getting this error.
Replace array=[set allObjects]; with array=[[set allObjects] retain];

I think this is because you are setting your instance variables to autoreleased objects without retaining them.
Either make "set" and "array" retained properties and do
self.set = [NSSet setWithArray:self.array];
// This is already a bit weird... If the set is made from the array, the array will be unchanged.
self.array = [self.set allObjects];
Or just retain them:
set = [[NSSet setWithArray:array] retain];
etc.
Since setWithArray and allObjects return autoreleased objects, you are left with dangling pointers as soon as you leave the scope of viewDidLoad.

Related

Convert NSString to NSMutableArray to added in tableview

Hi I wanted convert NSString into NSMutable array and in the final added into Tableview my String is this
result=Vlad,Mama,Papa,Son
I wanted to do something this
Anarray=(Vlad,Mama,Papa,Son)
And added to Tableview. Can anathing help me.What I do
NSArray *arr = [result componentsSeparatedByString:#","];
dataArray=[[NSArray alloc]initWithObjects:arr ,nil];
And try to added into
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [dataArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString*cellid=#"Cell";
UITableViewCell*cell=[tableView dequeueReusableCellWithIdentifier:cellid];
if(cell==Nil){
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellid];
}
cell.textLabel.text=[dataArray objectAtIndex:indexPath.row];
return cell;
}
But I have mistake
enter image description here
componentsSeparatedByString returns you the array, if you want a mutable array you can use the following code.
NSArray *arrComponents = [str componentsSeparatedByString:#","];
NSMutableArray *arrmFilter = [[NSMutableArray alloc] init];
for(int i = 0; i < [arrComponents count] ;i++)
{
NSString *str = [arrComponents objectAtIndex:i];
[arrmFilter addObject:str];
}
you've added your "arr" as element inside your "dataArray".
in case dataArray is NSMutableArray :
dataArray = [NSMutableArray arrayWithArray:arr];
in case dataArray is NSArray :
datatArray = [NSArray arrayWithArray:arr];
May be you didn't alloc and init dataArray.
You can try below code.
#import "ViewController.h"
#import "MyTableViewCell.h"
#interface ViewController ()
#end
#implementation ViewController
{
NSMutableArray *arrData;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSString *str = #"objective c,swift,java";
arrData = [[NSMutableArray alloc]initWithArray:[str componentsSeparatedByString:#","]];
NSLog(#"%#",arrData);
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return arrData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
cell.lblData.text = [arrData objectAtIndex:indexPath.row];
return cell;
}
componentsSeparatedByString gives you an array. Which is what you want.
[[NSArray alloc]initWithObjects:arr ,nil] gives you an array containing just one element, an array containing your strings. Which is totally wrong. An array containing four strings is absolutely not the same as an array containing an array containing four strings.
dataArray.count will be 1 - because there is one element which is itself an array. And dataArray [0] will be that array, not a string.

Displaying data retrieved from Parse in UITableView

After all progress i made with your answers, my issue changed. So i am changing my question with clearer way. I have an UITableView which is showing my retrieved data from Parse.com. So i made a NSMutableArray for adding objects to that array when they are retrieved. But my problem is even i add objects to NSMutableArray, my table does not show anything but default screen of UITableView. I thing the issue is UITableView is formed before my NSMutableArray got its objects. Here is my code:
Note: The PropertyClass is the class which has the properties of my objects.
At MyTableViewController.h
#interface MyTableViewController : UITableViewController <CLLocationManagerDelegate> {
PFObject *object;
}
#property (strong, nonatomic) IBOutlet UITableView *MyTableView;
#end
At UITableViewController.m
#interface MyTableViewController ()
#property(strong)NSMutableArray *myNSMutableArray;
#end
#implementation MyTableViewController
#synthesize myNSMutableArray,MyTableView;
-(void) retrievingDataFromParse{
PFQuery *query = [PFQuery queryWithClassName:#"MyObjectsClass"];
[query whereKey:#"ObjectsNumber" lessThanOrEqualTo:10];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %d scores.", objects.count);
if (objects.count==0) {
NSString *objectError = #"There no object retrieved from Parse";
PropertiesClass *PC = [[PropertiesClass alloc]initWithPropert1:objectError Propert2:nil Propert3:nil Propert4:nil];
[myNSMutableArray addObject:PC];
}
for (int i = 0; i < objects.count; i++) {
object = [objects objectAtIndex:i];
NSString *Propert1 = [object objectForKey:#"Propert1"];
NSNumber *Propert2 = [object objectForKey:#"Propert2"];
NSNumber *Propert3 = [object objectForKey:#"Propert3"];
NSString *Propert4 = [object objectForKey:#"Propert4"];
PropertiesClass *PC = [[PropertiesClass alloc]initWithPropert1:Propert1 Propert2:Propert2 Propert3:Propert3 Propert4:Propert4];
[myNSMutableArray addObject:PC];
};
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.myNSMutableArray = [NSMutableArray array];
[self retrievingDataFromParse];
[MyTableView reloadData];
}
- (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 [myNSMutableArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
PropertiesClass *PC= [myNSMutableArray objectAtIndex:indexPath.row];
cell.textLabel.text=PC.Propert1;
return cell;
}
Looking at your code i see that you never create a UITableViewCell, you should change this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
PropertyClass *PC = [myMutableArray objectAtIndex:indexPath.row];
cell.textLabel.text = PC.x;
return cell;
}
with this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (nil == cell){
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
PropertyClass *PC = [myMutableArray objectAtIndex:indexPath.row];
cell.textLabel.text = PC.x;
return cell;
}
the method dequeueReusableCellWithIdentifier:forIndexPath: return a UITableViewCell only if there are unused, but already allocated, cells in your table view. otherwise it returns nil.
Also when you update the mutable array containing all your data you should call [yourTableView reloadData] to force the table view to reload its content.
Your code is quite cryptic. Few suggestions here.
First, rename variables and methods with camelCaseNotation (camel case notation). For example, MyMutableArray should be myMutableArray. RetrievingDataFromParse should be retrievingDataFromParse (and so on). Start upper case letter are for classes.
Second, what does this code mean (I put comment on your code)?
for (int i = 0; i < objects.count; i++) {
// where do you have defined object?
object = [objects objectAtIndex:i];
NSString *x = [object objectForKey:#"x"];
NSNumber *y = [object objectForKey:#"y"];
NSNumber *z = [object objectForKey:#"z"];
NSString *t = [object objectForKey:#"t"];
// is Mekan a subclass of PropertiyClass or what else?
PropertiyClass *Properties = [[Mekan alloc]initWithx:x y:y z:z t:t]
// what's MekanKalibi? Maybe you need to add Properties
[MyMutableArray addObject:MekanKalibi];
}
Edit
If you don't use iOS6 - (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifier you should alloc-init cells.
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if(!cell) {
// alloc-init a new cell here...
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// or if you don't use ARC
// cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
PropertyClass *PC = [myMutableArray objectAtIndex:indexPath.row];
cell.textLabel.text = PC.x;
return cell;
Edit 2
I don't know how parse works but I suppose it manages async requests. So, at the end of your for loop, just call reload data in the table.
Parse states:
The InBackground methods are asynchronous, so any code after this will run immediately. Any code that depends on the query result should be moved inside the completion block above.
I had the same problem. When you reload the table, you need to move it so it is inside the block. Worked for me.
I'm not 100% sure how the asynchronous parts affect it so. I know that the start of my viewDidload and the end occured then this block, hence the problem.
People should probably up this as this solves the issue.
Cheers.
All you have to do is reload tableView in the block... this will show data.
for (int i = 0; i < objects.count; i++) {
object = [objects objectAtIndex:i];
NSString *Propert1 = [object objectForKey:#"Propert1"];
NSNumber *Propert2 = [object objectForKey:#"Propert2"];
NSNumber *Propert3 = [object objectForKey:#"Propert3"];
NSString *Propert4 = [object objectForKey:#"Propert4"];
PropertiesClass *PC = [[PropertiesClass alloc]initWithPropert1:Propert1 Propert2:Propert2 Propert3:Propert3 Propert4:Propert4];
[myNSMutableArray addObject:PC];
};
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
**[MyTableView reloadData];**
}];

EXC_BAD_ACCESS scrolling TableView

im getting EXC_BAD_ACCESS when i scroll my TableView. I heard something like alloc being called wrong, I dont know. Here's my code:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[resultsDictionary objectForKey: #"bills"] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Identifier for retrieving reusable cells.
static NSString *cellIdentifier = #"MyCellIdentifier";
// Attempt to request the reusable cell.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
// No cell available - create one.
if(cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:cellIdentifier];
}
NSArray *billsArray = [resultsDictionary objectForKey:#"bills"];
cell.textLabel.text = [NSString stringWithFormat:#"%#", [[billsArray objectAtIndex:indexPath.row] objectForKey:#"name"]];
return cell;
}
EDIT
I think the error is here:
* -[JKArray objectAtIndex:]: message sent to deallocated instance 0x6a5d030
NSString *cellName = [NSString stringWithFormat:#"%#", [[billsArray objectAtIndex:indexPath.row] objectForKey:#"name"]];
It looks like resultsDictionary is a dangling pointer. If you are using ARC, you need a strong reference to it somewhere. If you are not using ARC, you need to retain it somewhere.
Fixed. My billsArray was missing 'self' instance, as inside of cellForRowAtIndexPath method. Thanks to everyone.

Howto fill UITableView with sections and rows dynamically?

I have some problems with UITableView and sections/rows.
Iam parsing the section names, all row names and row count per section from a xml.
I have 3 NSMutableArrays:
nameArray (with all row names)
sectionArray (all section names)
secCountArray (row count per section)
For the cellForRowAtindexPath to work, do I have to return the rows for the displayed section?
The next step I would do is to build an 2d Array with sections and all rows for each section.
Does anyone knows any better solution?
Here comes the code:
// 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];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Set up the cell
int xmlEntryIndex = [indexPath indexAtPosition: [indexPath length] -1];
//???
cell.textLabel.text = [[theParser.nameArray objectAtIndex: 1]valueForKey:#"name"];
return cell;
}
Thanks!
You could have one _section array and one _row array for the whole tableview.
like your view controller.h file declare array
NSMutableArray *arrSection, *arrRow;
then your view controller.m file paste below code..
- (void)viewDidLoad
{
[super viewDidLoad];
arrSection = [[NSMutableArray alloc] initWithObjects:#"section1", #"section2", #"section3", #"section4", nil];
arrRow = [[NSMutableArray alloc] init];
[arrSection enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSMutableArray *tempSection = [[NSMutableArray alloc] init];
[arrSection enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[tempSection addObject:[NSString stringWithFormat:#"row%d", idx]];
}];
[arrRow addObject:tempSection];
}];
NSLog(#"arrRow:%#", arrRow);
}
#pragma mark - Table view data source
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [arrSection count];
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [arrSection objectAtIndex:section];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[arrRow objectAtIndex:section] count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:nil];
if(!cell)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil];
cell.textLabel.text = [[arrRow objectAtIndex:[indexPath section]] objectAtIndex:[indexPath row]];
return cell;
}
This method does not involve defining and creating your own custom view. In iOS 6 and up, you can easily change the background color and the text color by defining the
- (void)tableView:(UITableView *)tableView
willDisplayHeaderView:(UIView *)view
forSection:(NSInteger)section
delegate method.
For example:
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
// Background color
view.tintColor = [UIColor blackColor];
// Text Color
UITableViewHeaderFooterView *header = (UITableViewHeaderFooterView *)view;
[header.textLabel setTextColor:[UIColor whiteColor]];
// Another way to set the background color
// Note: does not preserve gradient effect of original header
// header.contentView.backgroundColor = [UIColor blackColor];
}
you can see display dynamic section and row
May be helpful for you..
You could have one array for the whole table view. The array contains arrays for every section. Then the cellForRowAtIndexPath could look like:
- (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];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
[[cell textLabel] setText: [[[myArray objectAtIndex: indexPath.section] objectAtIndex: indexPath.row]];
return cell;
}
I hope this help you in your problem.
Edit: With the modern Objective-C and ARC I would write this as
- (void)viewDidLoad {
....
[self.tableView registerClass:[MyCellClass class] forCellReuseIdentifier:kMyCellIdentifier];
}
...
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
MyCellClass *cell = [tableView dequeueReusableCellWithIdentifier:kMyCellIdentifier forIndexPath:indexPath];
cell.textLabel.text = myArray[indexPath.section][indexPath.row];
return cell;
}

How to load a tableView with an array of dictionaries?

I want to load a table view with an array which itself has multiple dictionaries. Each of these dictionaries has items which I need to put into a row, one dictionary per row. All of these dictionaries are stored in an array.
How should I perform this task?
Thanks,
See the code below, projects is my array.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
return self.projects.count;
}
- (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.
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
cell.textLabel.text = [self.projects objectAtIndex:indexPath.row];
}
You can do this with pretty much what you have. You'll just need to change your configureCell:atIndexPath: method to look something like this:
cell.textLabel.text = [[self.projects objectAtIndex:indexPath.row] objectForKey:#"some_key"];
Just change some_key to the key in your NSDictionary that you want to display in your UITableViewCell.
You can also change your UITableViewCell style to UITableViewCellStyleSubtitle and then you can add another key from your NSDictionary to cell.detailTextLabel.
In addition to edc1591,
In case if the dictionaries in the array have different keys then
if([[self.projects objectAtIndex:indexPath.row] count]==1)
{
id key= [[[self.projects objectAtIndex:indexPath.row] allKeys] objectAtIndex:0];
cell.textLabel.text = [[self.projects objectAtIndex:indexPath.row] objectForKey:key];
}