What we are actually doing with property in code? - ios

First of all I am very new in Objective C and iOS development.
Currently I am trying to use TableView
I have property
#property (strong, nonatomic) IBOutlet UITableView *tableView;//for table view
Now I seen something like this,
-(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
{
return [data count];
}
What is exact meaning of the code. What I am doing with tableView here, and how name of property and name of message is same, i.e. tableView.

In first line you are declaring property of an tableview which you create by storyboard.
The goal of the #property directive is to make it easy to create and configure properties by automatically generating these accessor methods. It allows you to specify the behavior of a public property on a semantic level, and it takes care of the implementation details for you.
-(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
{
return [data count];
}
This is a tableview delegate method which define the no of row in a particular section in table view
data is your array name contain element which you want to show in tableview cell
[data count] return the number of row in your table view
for more detail check
property
table view

What I am doing with tableView here
tableView:numberOfRowsInSection: is a method from the UITableViewDatasource Protocole to do simple, the object of type UITableView will do something like it :
[self.delegate tableView:self numberOfRowsInSection:section]
and so, if you do tableView.datasource = self in your viewController, it's this object which will receive the message and so, need to answer to the tableview.
and how name of property and name of message is same, i.e. tableView.
#property is just an indication for the compiler to create accessors and iVar in your class, that why it seems to do many things at the same time.

Related

The nuances of UITableView

I have been using objective c for a few months now, using different foundation classes and generally playing around with the language.
In my own experience nothing has been more confusing than UITableView; Below is a bit of code that does not do much.
//the header file
#interface SLDataBankListTableViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource>
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#end
//implementation
#interface SLDataBankListTableViewController ()
#property (strong, nonatomic) SLDataSourceObject* dataSource;
#end
#implementation SLDataBankListTableViewController
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:YES];
_dataSource = [[SLDataSourceObject alloc] init];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _dataSource.dataBankNames.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"reuse"];
cell.textLabel.text = [_dataSource.dataBankNames objectAtIndex:indexPath.row];
return cell;
}
#end
I have successfully used this class for over a dozen times and every time I make some stupid mistake like now. Finally I gathered some courage and decided to ask for help.
What are the subtle things, nuances of this class that I don't seem to grasp?
Edit: this is a part of a small program, other parts of it work fine, but the table displays nothing; Some changes have been recommended that are important but did not solve the problem.
It is a little hard to debug without known what is not working, but I see some things which might help you out.
UITableViewController has its own tableview but you seem to have another tableview wired up in a nib. Either use the UITableViewController tableview, or create your own, don't do both.
in cellForRowAtIndexPath you are creating a new cell every time instead of reusing the cells you have.
The delegate methods for the tableview can be called before viewWillAppear. You should create your datasource object earlier. I suggest viewDidLoad:. (Another reason viewWillAppear is a bad choice is that it can be call multiple times, and you can end up creating and destroying many datasource objects for no reason)
Hope that helps.
The big thing to remember about a table view is that it's a way for user to interact with an array of objects. The array is represented by a datasource, and the datasource methods describe what the view needs to know:
how many objects are in the array (called numberOfRowsInSection:)
how to display each one of the objects (called cellForRowAtIndexPath:)
To answer the latter question, the datasource must answer a view. That view's job -- like any view -- is to represent an object for the user. In row the table view uses a UITableViewCell.
The datasource array can be arbitrarily large, so directly mapping UITableViewCells to its elements can get arbitrarily expensive in memory terms. Rather than create a cell for every object in the array, the table view reuses cells.
When a cell scrolls off the top, the "new" one that appears at the bottom isn't new, it's the old cell handed back to the datasource to be reconfigured for the new row. To accomplish this, your datasource is expected to not allocate a new cell, as #JonRose correctly points out, but to ask the table view for a reused cell using dequeueReusableCellWithIdentifier.

Populate UITableView with Array not working

I am trying to embed a UITableView in my View Controller (not a TableViewController).
I am unable to get any of my data to show.
Here is the relevant code:
M file:
#interface ViewController () <CBCentralManagerDelegate, CBPeripheralDelegate, UITableViewDelegate, UITableViewDataSource>
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) NSMutableArray *Device_array_name;
#end
.
.
.
- (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=self.Device_array_name[indexPath.row];
return cell;
}
I've also defined number of sections and rows, and my array does indeed have content. I'm pretty new to iOS development so I've no doubt missed something.
Thanks
Delegates & Datasources should be defined for UI Controls to get called their respective delegates.
For Instance : In your viewDidLoad function define
tableView.delegate = self
tableView.datasource = self
It will work.
Set the array allocation in your view did load.
Device_array_name=[NSMutableArray alloc]init];
Set the tableview delegates in viewdidLoad
tableview.delegate=self;
tableview.datasource=self;
After give the count of an array in Number of rows in section
return Device_array_name.count;
In your cellForRow AtIndexpath method
cell.textLabel.text=[self.Device_array_name objectAtIndex:indexPath.row];
There could be 4 reason (most probably)
1> You delegate and datasource are not set
tableView.delegate = self
tableView.datasource = self
2> Your datasource array is nil (Device_array_name)
3> Your IBOutlet is not connected with tableview
4> Your tableview frame is becoming zero due to autloayout or something else (check console at runtime)
I think you just need to initialize the delegate and dataSource for your tableView property to your ViewController.
If you embed this way, you don't have default setting for the UITableView like you have when you use UITableViewController directly. You will need to set it up by yourself. Most likely, it's because you have not wired up your delegation object. Second will be, your UITableView is invisible. That also causes the problem because the delegate methods will not be called.
i think go to storyborad and set delegate,datasource in there.if you using by storyborad.i hope will work.
Here is my list of the possible problems:
The #IBOutlet for the table view is not connected in Interface Builder. Solution: check connection in Interface Builder.
The outlet is set, but the view controller placed in the storyboard is not of your custom UIViewController subclass, but the default UIViewController. In this case, none of your code will be executed. Solution: specify the view controller's class is the identity inspector (center tab).
The dataSource property of the table view is not set to your view controller. Solution: Assign it in either Interface Builder (storyboard) or programmatically inside viewDidLoad() or later.
You are not implementing the UITableviewDataSource protocol method:
tableView(_:numberOfRowsInSection:) (i.e., the table view "thinks" it has 0 rows to display). In this case, tableView(_:cellForRowAtIndexPath:) will not be called (you can confirm this by placing a break point). Solution: Implement the method and return the count property of your model object array.
The array that serves as the data source for your table view is empty (has zero elements). Solution: Make sure the array contains your model objects.
I might have left some other common mistake out... Let me know.
Addendum: Unless you have a compelling reason not to, I would strongly suggest that you use a stock UITableViewController instead of manually adding a UITableView to a plain UIViewController. You get a lot of functionality and setup for free.

How can I allocate and initialize a custom UITableViewCell NOT in cellForRowAtIndexPath?

I won't go into the WHY on this one, I'll just explain what I need.
I have a property in my implementatioon file like so...
#property (nonatomic, strong) MyCustomCell *customCell;
I need to initialize this on viewDidLoad. I return it as a row in cellForRowAtIndexPath always for the same indexPath, by returning "self.customCell".
However it doesn't work, I don't appear to be allocating and initializing the custom cell correctly in viewDidLoad. How can I do this? If you know the answer, save yourself time and don't read any further.
Ok, I'll put the why here in case people are curious.
I had a table view which was 2 sections. The first section would always show 1 row (Call it A). The second section always shows 3 rows (Call them X, Y, Z).
If you tap on row A (which is S0R0[Section 0 Row]), a new cell would appear in S0R1. A cell with a UIPickerView. The user could pick data from the UIPickerView and this would update the chosen value in cell A.
Cell X, Y & Z all worked the same way. Each could be tapped, and they would open up another cell underneath with their own respective UIPickerView.
The way I WAS doing this, was all these cell's were created in the Storyboard in the TableView, and then dragged out of the View. IBOutlets were created for all. Then in cellForRAIP, I would just returned self.myCustomCellA, or self.myCustomCellY.
Now, this worked great, but I need something more custom than this. I need to use a custom cell, and not just a UITableViewCell. So instead of using IBOutlets for all the cells (8 cells, 4 (A,X,Y,Z) and their 4 hidden/toggle-able UIPickerView Cell's), I created #properties for them in my implementation file. But it's not working like it did before with the standard UITableViewCell.
I'm not sure I'm initializing them correctly? How can I properly initialize them in/off viewDidLoad so I can use them?
.m
#interface MyViewController ()
#property (strong, nonatomic) MyCustomCell *myCustomCellA;
...
viewDidLoad
...
self.myCustomCellA = [[MyCustomCell alloc] init];
...
cellForRowAtIndexPath
...
return self.myCustomCellA;
...
If only I understood your question correctly, you have 3 options:
I would try really hard to implement table view data source with regular dynamic cells lifecycle in code and not statically – this approach usually pays off when you inevitably want to modify your business logic.
If you are certain static table view is enough, you can mix this method with overriding data source / delegate methods in your subclass of table view controller to add minor customisation (e.g. hiding certain cell when needed)
Alternatively, you can create cells using designated initialiser initWithStyle:reuseIdentifier: to instantiate them outside of table view life cycle and implement completely custom logic. There is nothing particular that you should do in viewDidLoad, that you wouldn't do elsewhere.
If you have a particular problem with your code, please post a snippet so community can help you
I suggest you to declare all your cells in storyboard (with date picker at right position) as static table and then override tableView:heightForRowAtIndexPath:
Define BOOL for determine picker visibility and its position in table
#define DATE_PICKER_INDEXPATH [NSIndexPath indexPathForRow:1 inSection:0]
#interface YourViewController ()
#property (assign, nonatomic) BOOL isPickerVisible;
#end
Then setup initial value
- (void)viewDidLoad {
[super viewDidLoad];
self.isPickerVisible = YES;
}
Override tableView delegate method
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([indexPath isEqual:DATE_PICKER_INDEXPATH] && !self.isPickerVisible) {
return 0;
} else {
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
}
And finally create method for toggling picker
- (void)togglePicker:(id)sender {
self.isPickerVisible = !self.isPickerVisible;
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
which you can call in tableView:didSelectRowAtIndexPath:
According to your problem, you can create pairs (NSDictionary) of index path and bool if its visible and show/hide them according to that.
Here's what I was looking for:
MyCustomCell *cell = (MyCustomCell *)[[[UINib nibWithNibName:#"MyNibName" bundle:nil] instantiateWithOwner:self options:nil] firstObject];

How to create UITableViewController as reusable module?

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.

Overriding of Tableview Datasource/Delegate Methods

I have one parent class with one tableview.
That class is the delegate and datasource of that tableview as well.
Now I subclassed (derived) that class and made a child class.
I have one tableview in child class too.
Then I defined delegate and datasource functions in that child class, but it overrides parent class tableview data source/delegate methods.
But I want both of them to be separate.
However my Requirement is as Follows :
I want to retain a search bar and side button, on the top of all the viewControllers that search bar includes , a recent searches terms table underneath that.
So i thought of defining parent class for that and subclass other viewControllers from that class.
Am i doing it the right way ?
I assume you are talking about a view controller class. If I understood you right, then you are about to mess it up. Delegation is a way to avoid subclassing. Of course you can subclass the delegate - no problem. But you want a table view in the super class that owns a table in its view. And you want a subclass that has another table in its view plus the table that the superclass owns.
That is not impossible. But from your subclass' point of view, your subclass owns two table views. Even that is possible. Your view controller is the delegate of two tables (regardless of where in the view hierarchy they are declared and instanciated). When you now override the delegate and data source methods theny your subclass must either:
Determine which table it is dealing with/being called from. And then serve both tables appropriately.
Determine wich table it is dealing with/being called from. And then serve "its own" table appropriately and calls [super sameMehtod:withSamePamaters] to ensure that the superclas can still provide the data and server as delegate.
Which of both is smarter depends on the context and what you are about to achieve in detail.
A way of determinnig which table's delegate was called can be done by tagging the table views (do not use 0 as tag) or by comparing the tableView parameter of the delegate method with the corresponding properties (IBOutlets in this case). (In other cases you can compare the sender parameter with the IBOutlets. But tagging is probably easier to understand when reading the code later.)
Let's look at an example of the UITableViewDataSourceDelegat:
Your superclass implements:
#interface MySuperTableViewController:UITableViewController <UITableViewDelegate>
// There will be something in here.
// But it inherits self.tableView from UITableViewController anyway. We leave it with that.
#end
#implementation MySuperTableViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// This method creates or re-uses a cell object and sets its properties accordingly.
}
#end
And your subclass:
#interface MySubTableViewController : MySuperTableViewController // no need to declare the delegate here, it is inherited anyway
#property (weak, nonatomic) IBOutlet UITableView *mySecondTableView; // self.table will be used by the superclass already.
#end
#implementation MySubTableViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == self.table) { // This call refers to the one talbe that is managed by super
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
// This method now creates or re-uses a cell object and sets its properties accordingly.
// You may want to check wether tableView == self.mySecondTableView etc.
}
#end
(This comes from scratch, not syntax checked etc. Do not expect this to run properly right away :)
BUT ... please re-consider your class structure. I am afraid you are getting lost in some rather unlogical class hierarchy. There is nothing wrong with having two talbes managed by a common view controller even without this subclassing-thing. And there is nothing wrong with using multiple tables in a view where each of the tables has its own delegate (can be a view controller). Since iOS 5 (or was it introduces with 6) we can use the UIContainerView for that purpose and nicely build it up in IB/storyboard.
try this,
ViewController.h
IBOutlet UITableView *firstTable;
IBOutlet UITableView *secondTable;
ViewController.m
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
if (tableView == firstTable) {
return 1;
}
else if(tableView == secondTable)
{
return 1;
}
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
if (tableView == firstTable) {
return [arrItems count];
} else if(tableView == secondTable)
{
return [arrData count];
}
return 0;
}
etc etc ....

Resources