My array contains more than 100 names and I just want to show the first 50 array.
I have read this topic (How do I get first x elements of an NSArray in Cocoa?) but is there a better solution instead of adding two arrays?
I'm adding the array like this
-(void)test{
_myArray = [[NSMutableArray alloc] init];
[_myArray addObject:usersName];
}
If you want to limit how much of the array can be seen within a tableview, where the array is the datasource of the tableview, then you just need to use the MIN macro with the tableview datasource
- tableView:numberOfRowsInSection: method:
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return MIN([_array count], 50);
}
The best way is to use subarrayWithRange:
Related
How to iterate from this multi-dimensional array in iOS ?
This data is coming from JSON
(
(
"burger meal",
"getImage.ashx?id=1",
150,
300,
"get a free burger"
),
(
"chinese combo",
"getImage.ashx?id=2",
350,
700,
"get a combo free"
),
(
"cheeese cake",
"getImage.ashx?id=3",
350,
700,
"get a cake free with meal"
)
)
I need to use object at index 3 e.g. = 150,350,350 in UITableView .
I have tried this
NSArray *array = jsonArray;
for (NSArray *newArray in array) {
[newArray addObjectFromArray:array];
}
Try This, In this code arrResult contain all values have you required at particular position.
NSArray *array = jsonArray;
NSMutableArray *arrResult = [[NSMutableArray alloc]init];
for (NSArray *newArray in array) {
[arrResult addObject:[newArray objectAtIndex:2]];
}
This is simple. Let TableView iterate the arrays for you. Your tableView is already iterating, don't add to overhead by iterating over the array yourself. You will just waste processing power if you do.
First, modify your numberOfRowsInSection delegate method like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [jsonArray count]; //Provide your json array here.
}
Then you have to do this in your cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Do everything that you need to do to get the cell. Here we will deal with only string retrieval from json array.
if(jsonArray count]>indexPath.row){
NSArray *innerArray = [jsonArray objectAtIndex:indexPath.row]; //You got the inner array
if(innerArray count]>2){
NSString *yourDesiredString = [innerArray objectAtIndex:2]; //You got the string. Use it now as you wish. It will be 150 for the first cell, 350 for the second and 350 for the third one as well.
}
}
}
I have not added any exception checks here, that's what you have to do yourself. I have added basic checks to prevent crashes in case of irrelevant data, you should expand on that.
This is with the assumption that you wish to set this string to each cell. If I have misunderstood your question or you need to ask something, leave a comment
I am populating a tableview with the contents of an array. Right now, I create the array in viewdidload and I calculate the number of rows in the delegate method
//in viewdidload
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL: kItemsURL];
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:data waitUntilDone:YES];
});
[self.tableView reloadData];
//method called in viewdidload to create array...
- (void)fetchedData:(NSData *)responseData {
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData //1
options:kNilOptions
error:&error];
NSLog(#" %#",json);
NSArray* latestItems = [json objectForKey:#"items"];
NSLog(#" array:%#",latestItems);
//getItems is a property in .h file
self.getItems = latestItems;
NSLog(#"getItems %#",_getItems); //logs out array ok
int size = [_getItems count];
NSLog(#"there are %d objects in the array", size);//provides correct number
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"getItems %#",_getItems); //logs (null)
int size = [_getItems count];
NSLog(#" %d objects in the array", size);//logs 0
When I count rows in viewdidload after creating the array, I get the correct number, however, when I call count on the array in the delegate method, it returns zero possibly because the tableview is created before Viewdidload is called.
Where should I create the array so that is known by the time numberofrows counts the number of rows in the array?
Edit:
After constructing the array, I save it to a property. However, I have discovered that this property is empty when I then log it to console in the numberofrowsinsection method so the problem seems to lie in how I am storing this array.
Right now, I have a property in the .h file and I've also tried it in the implementation but either way it is not persisting for some reason.
I'm not to familiar with obj-C, but I know you need to initialize your array outside your viewDidLoad() function. The reason why your .count is returning zero, is because your array is acting as a local variable to your viewDidLoad() function. Instead you could initialize the array as field in your UITableViewController class. This is how you would do so in swift, but it applies to obj-C as well:
class YourTableViewController: UITableViewController {
var yourArray = [AnyObject]()
override func viewDidLoad() {
//You can still do any programming to set up values and elements in yourArray[] here
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return yourArray.count
}
//Plus all your other tableView functions...
}
Also if you are passing information to your array between other UIViewController's you can add this function to your class, so every time you come back to your table view it loads the correct table cell count:
override func viewWillAppear(animated: Bool) {
self.tableView.reloadData()
}
I suggest to load the content of your array in viewDidLoad(), that is called once and before the table view use the array. The table view do not load the items before viewDidLoad. Are you doing something much different than this example structure below?
#implementation ViewController {
NSArray *arrayList;
}
- (void)viewDidLoad {
[super viewDidLoad];
arrayList = #[#"item 1", #"item 2"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cell.textLabel.text = [arrayList objectAtIndex:indexPath.row];
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return arrayList.count;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
Consider abstracting the creation of your data - the array instantiated in your tableview, into a model instead. This is generally considered to be a better software engineering practice (read : https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html ).
What I would do is have another file as a Class or Struct, and populate the data for the array used in your table view in there. I would also recommend having setter/getter methods in your array class/struct as well. When loading the tableview, we would then grab the data from the class/struct in your tableview viewDidLoad() method. The data from your array would also be available at any other point of your application as well, as it is no longer dependant on the tableview.
Side note : You can consider making the class/struct a singleton as well, if the model is supposed to only get instantiated once.
I Have a one table view and i have two array. My arrays name AllItems and SpecialItems. I Use segment control. I wantto if segment value is 0 tableview load AllItems Array, When change segment value and value is = 1 than mytableview reload tada but SpecialItems array. Can u help me please. Thanks.
I solved this problem with table tag.
- (IBAction)segmentControlChanged:(UISegmentedControl *)sender {
if (sender.selectedSegmentIndex == 1) {
mytable.tag = 1;
}
else
{
mytable.tag = 0;
}
[mytable reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(tableView.tag==1)
{
return [specialItems count];
}
else
return [allItems count];
}
You could create two data source classes that implement all the UITableViewDataSource methods: one for AllItems and one for SpecialItems. To switch between the two, connect a valueChanged action. In the method that is called, set the data source and reload the table view.
- (void)valueChange:(UISegmentedControl *)sender
{
if (/* condition for all items */) {
self.tableView.dataSource = self.allItemsDataSource;
} else {
self.tableView.dataSource = self.specialItemsDataSource;
}
[self.tableView reloadData];
}
I would personally create an array which the data is loaded from. Put this in your implementation:
NSArray * _tableData
Then in your viewDidLoad just allocate this for the array which we want it to start on.
_tableData = [[NSArray alloc] initWithArray:allItems];
This initially loads the data we will always see as the segment control starts on index 0. We have to set the initial data somewhere so the tableView loads with some data in it.
Then set the number of rows and the cellForRowAtIndex to pick up from the _tableData array
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _tableData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView_ cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell * cell = [tableView_ dequeueReusableCellWithIdentifier:bCell];
// Here we use the specific array as we would normally
return cell;
}
This step means the tableView will load with the array. Even if the array is empty the view will still load as the number of cells will be zero.
Now in our value changed function we can reset the array as we need to:
- (IBAction)segmentControlChanged:(UISegmentedControl *)sender {
if (sender.selectedSegmentIndex == 1) {
_tableData = allItems;
}
else {
_tableData = specialItems;
}
[self.tableView reloadData];
}
You just need to make sure the segment control changed is linked up in the XIB file (or programatically) and that you reload the table after choosing the array.
This kind of thing is actually really easy to do. I would definitely recommend working it through step by step if you're having trouble. Make sure each step is working before applying the next:
Get the tableView loading with both sets of data individually
Confirm that the segment control is calling the change function when clicked
Then that should do it
I am new to iOS development. I have created two classes of UITableViewController. One is list of Tasks and second one is the list of Notes.
Now the problem is both of these UITableViewController are needed on many screens (on some screens both simultaneously). I don't want to re-write all code for UITableView delegates and datasource on every screen. I want to re-use both UITableViewController with some mechanism of inheritance or module system.
So that on every UIViewController where i need to display list, i just have to add a UITableView in nib file, sets its custom class and it should start displaying data.
Is it possible with some kind of inheritance, component or module system?
Any help is appreciated.
Create subclass of UITableViewController add all of the required delegate methods and in .h file add:
#property(nonatomic, strong) NSArray *myData;
All of the method set up base on that array, for example:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.myData;
}
When you want to use this just create object and pass your data:
MYTable *tableViewController = [[MYTable alloc] init];
tableViewController.myData = DATA YOU WANT TO DISPLAY;
It will work but you have to pass exactly the same data structure to your NSArray to handle it right in cellForRowAtIndexPath: method.
Hey mate you need to maintain two array and create a toggle button ex. a/b
if a is pressed then fetch the count of one array, if b is pressed count the array of other dictionary. And do this by maintaining a BOOL variable.
ex.
BOOL checkvalue;
-(UIButton *)a:(id)button
{
checkvalue = TRUE;
[tableview reloadData];
}
-(UIButton *)b:(id)button
{
checkvalue = FALSE;
[tableview reloadData];
}
now put the condition in the tableview counting number of rows, and cellforrowatindexpath method.
like,
// for numberOfRowsInTableview
if(checkvalue == TRUE)
{
return [arr1 count];
}
else
{
return [arr2 count];
}
and similarly for cellForRowAtIndexPath
Thanks and have a nice day.
After using [UITableView deleteSections:withRowAnimation:] on a section which is out of view - the section header remains visible.
On this image, we see the visible part of the tableview
On the next image, we see the whole tableview - AISLE 2 is hidden until the user scrolls down, it contains only one row:
When I scroll down and delete the last row, AISLE 2 section header remains visible, even though I used deleteSections. if I delete a row from AISLE 1, the section header remains on the same place, and by scrolling down I can still see it.
Furthermore, when trying to scroll down so that AISLE 2 header is in the view, the UI acts as AISLE2 is NOT part of the tableview, and immediately scrolls me back up. Which means - this is a garbage view that is obviously not part of the table, since I removed it. for some reason, iOS doesn't remove this view, but de-associates it from the table.
Any ideas?
Try [tableview reload] with making numberofsections as 1.
Where is your data coming from and how do you know how many sections there are at the start? I think your problem can easily be resolved by explaining this.
It looks like you may have a multidimentional nsmutablearray where each index is an aisle and each object contains the products for that isle? Or you may have a different array for each aisle?
When you delete a cell, simply check how many cells are left, and call [self.tableView reloadData];
For (hypothetical) example;
if you have arrays of your Aisles:
NSMutableArray *aisleOne = [[NSMutableArray alloc] initWithObjects:#"Product1", #"Product2", nil];
NSMutableArray *aisleTwo = [[NSMutableArray alloc] initWithObjects:#"Product1", #"Product2", nil];
NSMutableArray *aisleThree = [[NSMutableArray alloc] initWithObjects:#"Product1", #"Product2", nil];
NSMutableArray *aisleFour = [[NSMutableArray alloc] initWithObjects:#"Product1", #"Product2", nil];
and you add them to one array:
NSMutableArray *aisleArray = [[NSMutableArray alloc] initWithObjects:aisleOne, aisleTwo, aisleThree, aisleFour, nil];
then, call this code when you delete a cell. It will remove all empty Aisles from the aisleArray (which needs to be globally defined):
NSMutableArray *tempArray = [[NSMutableArray alloc] initWithArray:aisleArray];
for (int i=0; i<[tempArray count]; i++) {
if ([[tempArray objectAtIndex:i] count] == 0) {
[aisleArray removeObjectAtIndex:i];
}
}
[self.tableView reloadData];
For this to work, these two methods should be:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [aisleArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[aisleArray objectAtIndex:section] count];
}
(untested)
Just get the table haderview for that section and remove it from it's superview and tableView is not managing it.
UIView *mysteriousView = [tableView headerViewForSection:indexPath.section];
[tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationAutomatic];
[mysteriousView removeFromSuperview];
Hope this helps!
Few yers later I'm facing same issue... Deleting last section doesn't remove last section header from table view.
I noticed however that the remaining header has frame exactly just below normal table view content.
So the workaround (in swift but you can easily translate it to Objective C) that worked for me is something like this:
DispatchQueue.main.async {
let unwantedViews = self.tableView.subviews.filter{ $0.frame.minY >= self.tableView.contentSize.height}
unwantedViews.forEach{ $0.isHidden = true }
}