I have implemented a UITableView in ViewController1,and I am passing the TableView cell content through the Array and display it.
_tableData=[[NSMutableArray alloc]initWithObjects:#"1",#"2" ,#"3",#"4",nil];
cell.detailTextLabel.text=[_tableData objectAtIndex:indexPath.row];
Now, that I have passed the data through statically, I want to implement it through a dynamic way by using Model Class.
How can I alter the Array through Model Class Array?
1) Create Model Class like this
#Interface SomeClass: NSObject
#property(nonatomic, Strong) NString* someValue;
2) Add model objects in the Datasource array ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
for(i=1,i<5,i++)
{
SomeClass *someObj = [SomeClass alloc]init];
someObj.someValue = [NSString stringWithFormat:#"%d",i];
[_tableData addObject:someObj];
}
}
3) In cell for Row set the data to textLabel
SomeClass *someObj = [_tableData objectAtIndex:indexPath.row];
cell.detailTextLabel.text = someObj.someValue
Note - I have the model objects with hard coded data. You can use the data from webservice or data from core data.
Only thing you need to do is to refresh your table view whenever your datasource array changes
_tableData = [....some value....];
[tableView reloadData];
Related
I'm new to Objective-C and iOS programming, using storyboards.
Scene 1: Contains a Table View. (ViewController.m)
Displaying a Table View populated by NSMutableArray from a singleton class.
Add button -> Scene 2.
Scene 2: Create and add object. (AddObjectViewController.m)
Creating and saving a custom object to NSMutableArray in a singleton class to access it from different Scenes/View Controllers.
Save button -> Scene 1.
Cancel button -> Scene 1.
Problem
Upon return to Scene 1, the Table View is blank.
At the time of - (void)viewDidLoad in Scene 1 (ViewController.m, where table is populated), array in singleton class is indeed empty.
However, shortly after, the array do contain the newly created object.
Leaving Scene 1 and returning to it will update the Table View and list the object that was just added.
It appears more time is needed to write data before initializing singleton class in ViewController.
To that end, I tried to add Wait/Sleep time after writing to the array in Scene 2 (AddObjectViewController.m) and before initializing singleton class in Scene 1 (ViewController.m).
It does not work. Seems like everything sleeps.
What to do? It should already be working by my logic, and from my research, a singleton class should be perfect for this scenario.
Edit: The important code.
Code
ViewController2.m
- (IBAction)saveButtonPressed:(id)sender {
// Custom initialization.
Computer *object = [[Computer alloc] initWithName:nameField.text IP:ipField.text Port:portField.text Password:passwordField.text];
// Add Computer to array of Computers via "Singleton" (shared array).
Computers *sharedComputers = [Computers sharedComputers];
[sharedComputers addComputer:object];
}
ViewController.m
#implementation ViewController{
NSMutableArray *tableData;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *tableIdentifier = #"TableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:tableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:tableIdentifier];
}
cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
cell.imageView.image = [UIImage imageNamed:#"Computer Filled-25.png"];
return cell;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Initialize table data
tableData = [[NSMutableArray alloc] init];
// Add objects to table
Computers *sharedComputers = [Computers sharedComputers];
for (Computer* item in [sharedComputers getArray]) {
[tableData addObject:item.name];
}
}
Computers.m (Singleton class)
- (void)addComputer:(Computer *)aComputer {
[computerArray addObject:aComputer];
}
If you are filling your dataSource array of table view in Scene 1 in viewDidLoad method then you need to know that viewDidLoad will not be called again once you return back to Scene 1 from Scene 2. The solution is to move the dataSource implementation to viewWillAppear method in Scene 1
-(void)viewDidLoad{
[super viewDidLoad];
dataSource = [[NSMutableArray alloc]init];
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[dataSource removeAllObjects];
dataSource = singletonClass.MutableArray; // fill dataSource from your singleton class
}
This will make sure your tableview data is refreshed every time you view Scene1
My app is currently generating random numbers (see code below). What I want is to save that number once the user hits the "Save" button and show it on a table view.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.clickyButton setTitle:#"Generate" forState:UIControlStateNormal];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)handleButtonClick:(id)sender {
// Generates numbers 1 to 49, without creating duplicate numbers.
NSMutableSet * numberSet = [NSMutableSet setWithCapacity:5];
while ([numberSet count] < 7 ) {
NSNumber * randomNumber = [NSNumber numberWithInt:(arc4random() % 49 + 1)];
[numberSet addObject:randomNumber];
}
NSArray * numbers = [numberSet allObjects];
self.n1.text = [NSString stringWithFormat:#"%#", [numbers objectAtIndex:0]];
self.n2.text = [NSString stringWithFormat:#"%#", [numbers objectAtIndex:2]];
self.n3.text = [NSString stringWithFormat:#"%#", [numbers objectAtIndex:3]];
self.n4.text = [NSString stringWithFormat:#"%#", [numbers objectAtIndex:4]];
self.n5.text = [NSString stringWithFormat:#"%#", [numbers objectAtIndex:5]];
self.n6.text = [NSString stringWithFormat:#"%#", [numbers objectAtIndex:6]];
}
#end
Please explain me how I can save it on a table view. xcode beginner.
You should create a variable that's accessible within the scope of the whole class rather than just the specific -handleButtonClick: method, and then add the generated numbers to that variable - an array, set, etc...
From there, you can implement the table view to read the values from the variable via var[indexPath.row] (assuming it's an array), and display it. You will need to call [tableView reloadData]; once the array has been filled with objects to make sure that the tableview displays the data.
create a NSMutableArray for UITableViewDataSource and cache the number.
when a number created by the user,add this number into NSMutableArray.
reload UITableView and show all numbers.
If you use only one number you should think about displaying it in another UI element, preferably a UILabel I would say.
If you want to use a UITableView you will either have to create it with static cells (e.g. in a Storyboard) or configure the data source and delegate object for it (which doesn't really seem what you want right now, unless maybe if you wanted to display multiple random numbers in a list...)
Before anything you should make the array numbers as a variable. In that way it is much easier than creating n1,n2,n3,.... I will show you how to solve your problem based on an existing numbers NSArray variable defined.
You need to implement the UITableView delegates in your header file. So let's suppose this is your header file after implementing the delegates:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#end
Then take your tableview (IBOutlet or programatically) and set the dataSource and delegate in the implementation file. You should do this in the viewDidLoad: method like this:
[_tableView setDelegate:self];
[_tableView setDataSource:self];
After you have done this you need to implement the delegate methods for the UITableView. This ones:
This method will tell the Table View how many rows it needs to show. In your case is the size of the NSArray called numbers:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return numbers.count;
}
This method will tell the Table View what to show on each cell (DON'T FORGET TO ASSING THE CELL IDENTIFIER OF THE CELL IN THE INTERFACE BUILDER TO "Cell")
- (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];
}
cell.textLabel.text = [numbers objectAtIndex:indexPath.row];
return cell;
}
Use this method if you want to do something when the user touches a cell in the table view:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
Finally to add numbers to the list as the user touches the button you just need to add these lines of code to your method triggered by the button:
- (IBAction)handleButtonClick:(id)sender {
// Generates numbers 1 to 49, without creating duplicate numbers.
NSMutableSet * numberSet = [NSMutableSet setWithCapacity:5];
while ([numberSet count] < 7 ) {
NSNumber * randomNumber = [NSNumber numberWithInt:(arc4random() % 49 + 1)];
[numberSet addObject:randomNumber];
}
//In case you want to delete previous numbers
[numbers removeAllObjects];
numbers = [numberSet allObjects];
[_tableView reloadData];
}
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.
I am using singletone class for fetch json data and i want to show in tableview but when i am click view first time then data not showing, on second time it's shows and cell repeating data on every click.
- (void)viewDidLoad
{
[super viewDidLoad];
singCls = [SingletoneClass sharedInstanceMethod]; // Declared Class for instance method of singletone class
webserviceclas = [[WebserviceUtility alloc] init];
[webserviceclas getorchardslist];
}
#pragma mark - TableView Delegates
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return singCls.orcharsList.count; // Get json data of orchards list in array
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *orchardscell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(orchardscell == nil)
{
orchardscell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
orchardscell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
NSString *strcell = [singCls.orcharsList objectAtIndex:indexPath.row];
orchardscell.textLabel.text = strcell;
// Display Orchards list pass from json
return orchardscell;
}
Your tableview controller was not notified when actual data was fetched by WebserviceUtility class. I'm assuming that your WebserviceUtility class calls webservices and once the data is received in this class, the singleton class' orcharsList array will be updated. So if I'm correct till this point, then you need to notify the tableviewcontroller after updating orcharsList. And on receiving notification here, the tableView need to be reloaded and then your tableview delegates will be called.
What you need to do is:
Add protocol method in your WebserviceUtility class.
#protocol WebServiceDelegate
-(void)fetchedData:(WebserviceUtility*) self;
#end
Add a delegate property to which notifications need to be send
#interface WebserviceUtility {
id<WebServiceDelegate>delegate;
}
#property (nonatomic, assign) id <WebServiceDelegate> delegate;
Then notify the delegate once data is available
if ([delegate respondsToSelector:#selector(fetchedData:)]) {
[delegate fetchedData:self];
}
Implement those protocols in your tableviewcontroller class and add this class as delegate to WebserviceUtility
In .h file
#interface YourTableViewController: UITableViewController<WebServiceDelegate>
In .m file, assign your tableviewcontroller as delegate for WebserviceUtility
webserviceclas = [[WebserviceUtility alloc] init];
webserviceclas.delegate = self;
Implement the protocol method in your controller
-(void)fetchedData:(WebserviceUtility*) self{
//Reload your tableview here
}
Hope this helps.
I assume that you did not embed a callback that notifies your UITableViewController to reload data when your singleton finished loading data. Right now there is no data available when first presenting the tableView and it does not refresh automatically.
I have this code:
#interface MyBusinessesController : UIViewController
{
NSDictionary *businesses;
NSArray *items_array;
}
#property (weak, nonatomic) IBOutlet UILabel *messageLabel;
- (IBAction)plan:(id)sender;
#property (weak, nonatomic) IBOutlet UITableView *itemList;
#end
and I set the UITableView and the NSArray in the header area of the .m file. Then I have a remote server call and get back JSON. I get the JSON data into an array like this:
items_array = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
Then I loop through the items like this:
for (int i = 0; i<= items_array.count - 1; i++)
{
NSDictionary *dict = [items_array objectAtIndex:i];
NSString *item_title = [dict objectForKey:#"item_title"];
NSString *item_id = [dict objectForKey:#"item_id"];
...
and then I would like to add it as a row in my UITableView, but I am struggling with how to do it now.
What I would want is to display the item_title to the user, and when the user presses the title that I would be able to know how to get the item_id of that item_title.
Thank you!
You need to implement the required methods in the UITableViewDataSource protocol, and set the dataSource property of the tableView to self.
Accordingly, implement the appropriate UITableViewDelegate methods, and set the delegate property of your tableView to self.
See the documentation for details on which methods are required, and which optional methods you might want to implement.
Don't forget to advertise in your .h file that your Class conforms to both protocols:
#interface MyBusinessesController : UIViewController <UITableViewDataSource, UITableViewDelegate>
You can make the tableView refresh its content by calling [itemList reloadData].
Table views work differently to what you appear to be used. You don't loop over your data and fill the table. Instead, you set yourself as table's delegate and then the table will ask you:"How much data do you have, what data do you want at row 5" and so on.
I'd really suggest you go over this great tutorial here:
http://kurrytran.blogspot.com/2011/10/ios-5-storyboard-uitableview-tutorial.html
Instead of looping through the array and pulling out the string values you can let the data source methods for UITableView handle this. So in cellForRowAtIndexPath method you would index your items_array with the index path as such:
NSDictionary *dict = [items_array objectAtIndex:[indexPath row]];
Then you would pull the strings out of the dictionary like you did in the loop and set the title for the cell to the string. For selecting the cell, you can write your code in the didSelectRowAtIndexPath method.
Here is an example from a project I was working on:
#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 [items_array count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault)
reuseIdentifier:#"cell"];
NSDictionary *dict = [items_array objectAtIndex:[indexPath row]];
cell.textLabel.text = [dict objectForKey:#"item_name"];
return cell;
}
The first method specifies the number of sections you want in your table. If you want a very simple table this will be 1. The second method is the number of rows. This will be the number of items in your items_array so: [items_array count]. The third method creates a cell based on the index. It will go from section 0 to the number of sections you specify and from row 0 to number of rows per section you specify. So now instead of looping you can just index out your array. [indexPath section] gives the section number and [indexPath row] gives the row number.
*I know I should probably dequeue cells before making new ones but my array is very small.