I want to only show some of the items in an array, but can't figure out how to do it.
This is the code I have that currently shows all objects in the array:
#property (strong, nonatomic) NSArray *springs;
#property (strong, nonatomic) NSMutableArray *leafs;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"standardCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Spring *spring = [springs objectAtIndex:indexPath.section]; // 13 objects
Leaf *leaf = [spring.leafs objectAtIndex:indexPath.row]; // 30 objects
cell.textLabel.text = league.shortName;
return cell;
}
So I would like to only show 5 of the 30 leaf objects from that array I created, and not show all of them. Is there any way to do that?
(I'm using an API to pull the items into the Array)
Thanks for the help, will post any specific code or other info needed!
EDIT
Added per request:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
Spring *spring = [springs objectAtIndex:section];
return spring.leafs.count;
}
I'm using RestKit for the object mapping.
Use [NSArray objectsAtIndexes:] (reference) to get a subset of the array.
Leaf *leaf = [spring.leafs objectAtIndex:indexPath.row];
// This will include objects 0-4:
NSRange range = NSMakeRange(0, 5);
NSArray *subset = [leaf objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range]];
Just adjust range to whatever start/length you want in the subset.
EDIT: Of course any subset logic in this method will also have to be duplicated in the numberOfRowsInSection: delegate method, else your app with throw an exception.
How about in your tableView:numberOfRowsInSection, don't return a full count full spring.leafs? For instance,
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 5;
}
Are you trying to lazy load them, or do the rest of them just not matter? Good luck.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
Unfortunatly I dont currently have internet on my laptop so I will have to describe my code, I have a mutable array of alphabetically sorted song titles. I have a uitableview that is currently displaying these however I want to have section heads and an alphabet index at the side of the table so I need to put these songs into an nsdictionary to display it, however I cant work out an an efficent method of sorting the array into the alphabetical sections (also has a # section, ive made a nsarray of section heads) in the nsdictionary.
There are many possibilities to prepare your data. But since your songs are already sorted your view controller could look something like this:
#interface TableViewController ()
#property (strong, nonatomic) NSArray *sectionTitles;
#property (strong, nonatomic) NSArray *songsInSections;
#end
#implementation TableViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *songs = #[#"A song", #"Another song", #"Some other song", #"Yet another song"];
// store all the needed section titles
NSMutableArray *sectionTitles = [NSMutableArray array];
// store the songs in sections (arrays in array)
NSMutableArray *songsInSections = [NSMutableArray array];
// prepare the data for the table view
for (NSString *song in songs) {
// get the song's section title (first letter localized and uppercased)
NSString *sectionTitle = [[song substringToIndex:1] localizedUppercaseString];
// check if a section for the song's section title has already been created and create one if needed
if (sectionTitles.count == 0 || ![sectionTitle isEqualToString:sectionTitles[sectionTitles.count - 1]]) {
// add the section title to the section titles array
[sectionTitles addObject:sectionTitle];
// create an (inner) array for the new section
[songsInSections addObject:[NSMutableArray array]];
}
// add the song to the last (inner) array
[songsInSections[songsInSections.count - 1] addObject:song];
}
// "store" the created data to use it as the table view's data source
self.sectionTitles = sectionTitles;
self.songsInSections = songsInSections;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [self.songsInSections count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return self.sectionTitles[section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.songsInSections[section] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = self.songsInSections[indexPath.section][indexPath.row];
return cell;
}
- (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return self.sectionTitles;
}
#end
I have 2 UITableViewControllers in my project.
The problem I am having is that I am getting blank cell entries in the tableView opposite to the tableView where the data is entered.
I can't seem to figure out why this is the case.
It's creating blank rows in this tableView even though the information is from the other UITableViewController.
Here's the main tableView part from the one of the 2 UITableViewControllers:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSLog(#"number of addedSpaceObjects %lu",(unsigned long)[self.diaryoptions count]);
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"number of sections %ld",(long)section);
// Return the number of rows in the section.
return [self.diaryoptions count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentification = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentification
forIndexPath:indexPath];
Data2 *diary = [self.diaryoptions objectAtIndex:indexPath.row];
cell.textLabel.text = diary.diaryname;
cell.detailTextLabel.text = diary.diaryWeight;
return cell;
}
And from other UITableViewController:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSLog(#"number of addedSpaceObjects %lu",(unsigned long)[self.addedSpaceObjects count]);
// Return the number of sections.
if ([self.addedSpaceObjects count]) {
return 2;
}
else {
return 1;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"number of sections %ld",(long)section);
// Return the number of rows in the section.
if (section == 1) {
return [self.addedSpaceObjects count];
}
else {
return [self.recipes count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentification = #"Josh";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentification
forIndexPath:indexPath];
if (indexPath.section == 1) {
Data *recipe = [self.addedSpaceObjects objectAtIndex:indexPath.row];
cell.textLabel.text = recipe.name;
}
else {
// Configure the cell...
Data *recipe = [self.recipes objectAtIndex:indexPath.row];
cell.textLabel.text = recipe.name;
}
return cell;
}
Here is the full project on GitHub. https://github.com/josher32/Plant-Diet
Appreciate any help anyone can offer!
Ok, so I checked out the app and I'll try my best to explain the problem as precisely as I can to cover it adequately.
Firstly, the classes in question are:
RecipesTableTableViewController
AddRecipeViewController
Data
DiaryTableViewController
AddDiaryViewController
Data2
Secondly, we'll need to look into your
#define ADDED_SPACE_OBJECTS2 #"Added Space Objects Array"
AddRecipeViewController
So... AddRecipeViewController basically creates a Data object that is kept in an array and eventually stored in NSUserDefaults under the key name Added Space Objects Array.
Great!! So you now have got recipe related stuff in some Data object.
AddDiaryViewController
Same thing here.
AddDiaryViewController creates a Data2 object that is eventually stored in NSUserDefaults under the same key name Added Space Objects Array.
But before storing this, you're taking the old value of the key Added Space Objects Array, which is an array, and adding a new object to it before placing it back into NSUserDefaults.
But now... this array will now have a combination of Data as well as Data2 objects!
RecipesTableTableViewController
When we come here, things get real.
- (void)viewDidLoad
{
//...
NSArray *myRecipeAsPropertyLists = [[NSUserDefaults standardUserDefaults] arrayForKey:ADDED_SPACE_OBJECTS_KEY];
for (NSDictionary *dictionary in myRecipeAsPropertyLists) {
Data *spaceObject = [self spaceObjectForDictionary:dictionary];
[self.addedSpaceObjects addObject:spaceObject];
}
}
Since we already realized that self.addedSpaceObjects can contain Data as well as Data2 objects, in the case whendictionary is containing stuff specific to type Data2, spaceObjectForDictionary will not be able to translate it properly to the required Data object.
We're expecting name, title, ingredients, directions but we're getting diaryentry, diaryname,diaryWeight.
So (in this scenario):
The values of name, title, ingredients, directions will be nil
The section-row count will be incorrect because it will give count of both Data as well as Data2 objects (and we don't care about Data2 objects in the RecipesTableTableViewController class... right?... well anyways, I assumed)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//...
if (indexPath.section == 1) {
Data *recipe = [self.addedSpaceObjects objectAtIndex:indexPath.row];
cell.textLabel.text = recipe.name;
}
//...
}
We see recipe.name is nil, for some indexPaths, ergo blank rows and vice versa in DiaryTableViewController.
Solution:
Firstly, I wouldn't recommend NSUserDefaults for your purposes but anyways...
Basically, don't use a single #"Added Space Objects Array" key for your NSUserDefaults stuff.
I'd suggest you use 2 separate keys.
//replace
//#define ADDED_SPACE_OBJECTS2 #"Added Space Objects Array"
//with
#define ADDED_SPACE_OBJECTS2 #"RecipeEntries" //in RecipesTableTableViewController
//and
#define ADDED_SPACE_OBJECTS2 #"DiaryEntries" //in DiaryTableViewController
Basically, segregate the entries instead of mixing them up under a single key name.
This seems like the quickest way to solve your problem without changing your logic.
I am creating an app where users can store an object in Core Data. I have the Objects being pulled into a UITableView and everything is working correctly there. I now want to separate the objects into a possible of 1-3 different sections based on choices in a UISegmentedControl.
Currently I have this to create the 1 section and populate the cells of that section with my objects
#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 self.fetchedDiscs.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"DiscCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//Configure Cell
Disc *currentDisc = [self.fetchedDiscs objectAtIndex:indexPath.row];
cell.textLabel.text = currentDisc.name;
cell.detailTextLabel.text = currentDisc.brand;
return cell;
}
So the main question is how to dynamically change the number of sections and number of rows in section?
The Segmented control returns values such as Option 1, Option 2, Option 3. The only way I can think of is to loop through my fetchedDiscs array and separate that into an array for each section. Then I can return the number of arrays if they exists and I can get the count of each array to get the number of rows in each section. But then I get to the problem of How to get the CellForRowAtIndextPath to work correctly with three arrays.
Basically there has to be a better more logical way to do this. I am just not sure how.
Let, you have a dictionary named dataSource that contains 'x' number of array as value for key "key1", "key2", .. "keyX". You can do this:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[dataSource allKeys] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//Get the array object form key. I am considering 'keySection' as an example
return [[dataSource objectForKey:#"keySection"] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"DiscCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = [[dataSource objectForKey:keySection] objectAtIndex:indexPath.row]
return cell;
}
Note: I wrote the code in this editor, excuse any mistakes, I just tried to share the idea. Hope this helps.. :)
I've seen a number of people who have asked a similar thing, but answers to their questions are not the answers to mine.
1) I have created a single view application with an empty View Controller. In that, I dragged a new Table View (style Plain) with a single prototype cell of style Basic.
2) I am trying to learn about dynamically changing the behaviour of TableViews, so I have a mutable array called sectionRows, which will contain the number of rows per section. At the moment, a single section with a number of rows would be an achievement :)
3) In my ViewController.h I have set the delegates
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#end
I have also control-dragged from the TableView to the ViewController Yellow-Circle and set the datasource and delegate outlets.
4) In my ViewController.m, I have defined some global variables
#interface ViewController ()
{
NSMutableArray *sectionRows;
UITableView *myTableView;
}
The first is my data array (containing the number of rows per section and the second is a pointer to my TableView, which I have identified using a numeric View tag of '1'.
5) In my viewDidLoad, I initialize everything:
- (void)viewDidLoad
{
[super viewDidLoad];
myTableView = (UITableView *)[self.view viewWithTag:1];
sectionRows = [[NSMutableArray alloc] init]; // Create sectionarray
[sectionRows addObject:[NSNumber numberWithInteger:1]];
myTableView.dataSource = self;
myTableView.delegate = self;
[myTableView reloadData];
}
As you can see, I even make sure that I set the datasource and delegate again but this hasn't made any difference.
5) I have overloaded 3 methods.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"Returning %# rows", [sectionRows objectAtIndex:section]);
return (NSInteger)[sectionRows objectAtIndex:section]; // the number referenced in the array...
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSLog(#"Returning %li sections", sectionRows.count);
return sectionRows.count; // the size of the sectionRows array
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = #"xxx";
NSLog(#"Setting cell to %#", cell);
return cell;
}
Now, when I run this, I am getting NSLog returning confirmation that there is a single section and a single row:
2014-07-27 19:58:34.599 TableViewTests[12877:60b] Returning 1 sections
2014-07-27 19:58:34.600 TableViewTests[12877:60b] Returning 1 rows
However, as you can see cellForRowAtIndexPath is not being called.
None of the other things I have seen point to what I am doing wrong. I am doing what I thought I did successfully in another simple project (to learn) but I must be doing something else differently.
Any ideas what I am missing?
Thanks in advance
Jon
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"Returning %# rows", [sectionRows objectAtIndex:section]);
return (NSInteger)[sectionRows objectAtIndex:section]; // the number referenced in the array...
}
This is incorrect. You cannot cast what you get from your array to an NSInteger. It's a pointer. Assuming you store NSNumbers into the array:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"Returning %# rows", [sectionRows objectAtIndex:section]);
return [[sectionRows objectAtIndex:section] integerValue]; // the number referenced in the array...
}
I am from C# background and now learning objective C.
I created two NSArrays 1.optionsLabelArray and 2.optionsLabelSubtitleArray initially with two elements each (optionsLabelArray=>Yes & No) and optionsLabelSubtitleArray(acceptable and action). Now requirement changed and I have to add one more item and I am doing it like below. But It still shows only two elements.
I tried using NSMutableArray , no luck. Looks like it's a small issue but couldn't figure it out.. any ideas will be appreciated.
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
optionsLabelArray = [[NSArray alloc] initWithObjects:#"Yes", #"No",#"No" ,nil]; // here is problem
optionsLabelSubtitleArray = [[NSArray alloc] initWithObjects:#"Acceptable",#"Action required",#"No", nil]; // here to
static NSString *CellIdentifier = #"CheckerCell";
CustomCell *cell =[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.optionLabel.text = [optionsLabelArray objectAtIndex:indexPath.row];
cell.optionLabelSubtitle.text = [optionsLabelSubtitleArray objectAtIndex:indexPath.row];
return cell;
}
You need to update the implementation of your - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section method to support more rows. To do so you probably want to have an implementation where the array is either an instance variable of the class or otherwise consistent between the two methods.
you need implement following method and return 3 when you increase cell count
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
see more on https://developer.apple.com/library/ios/documentation/uikit/reference/UITableViewDataSource_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UITableViewDataSource/tableView:numberOfRowsInSection: