Largely curious really. In the provided Apple UITableViewDataSource method tableView:cellForRowAtIndexPath:, the name given to the static NSString variable used for the cell identifier is always capitalised, like so:
- (UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TableViewCell"; // CAPITALISED VARIABLE NAME
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier];
// Configure cell
return cell;
}
Whilst I realise it makes no difference to the program when it runs, Objective-C naming conventions state that variables should have their first letter lower case and classes should have theirs uppercase. Why is this not the case here?
Capitalizing the first letter is used to denote that CellIdentifier is a constant.
Now, you may wonder, why can't you just do this...
static const NSString *cellIdentifier = #"TableViewCell";
The answer is because const does not work with NSString as the programmer would expect. The string value of NSString can still be changed even if it is marked as const, so the following series of expressions...
static const NSString *cellIdentifier = #"TableViewCell";
cellIdentifier = #"Changed!"
NSLog(#"%#", cellIdentifier);
Would log "Changed!" to the console, NOT "TableViewCell". Because of this, a capital letter is used to imply that CellIdentifier is a constant, although it can technically still be altered, it is just "not supposed" to be altered.
The cell identifier here is effectively a constant, which by convention are capitalised
Related
Currently I fill a UITableView using this method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CharNameCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
MyObject *obj = (MyObject*)[self.characters objectAtIndex:indexPath.row];
cell.textLabel.text = obj.name;
return cell;
}
But what could one do if you had two different arrays from two different types and you wanted to display a property from each in the cells?
Pseudocode:
MyObject1
MyObject2
cellTextLabel.text = Myobject1.name;
cellTextLabel.text = MyObject2.name;
Assuming that each object has a name property. I know my syntax above isn't correct, but I think you should get the drift.
I would suggest then that you store all of your objects in an NSMutableArray. This will be your data model. Then you can just iterate through the array to display the data in the UITableView. If need be, use introspection to find out what kind of class your object is.
id currentObject = [myArray objectAtIndex:indexPath.row];
if ([currentObject isKindOfClass:[MyObject1 class]]){
//set properties or do stuff with MyObject1
}else if ([currentObject isKindOfClass:[MyObject2 class]]){
//do stuff with Object2
}
This is just one suggestion. There are many ways to do this, but it will all depend on your app and what kind of persistence you are using, etc. Hope this helps.
What's the difference (if indeed there is a difference) between:
UITableViewCell *cell;
...
cell.textLabel.text = [self.adviceData objectAtIndex:indexPath.row];
and
UITableViewCell *cell;
...
NSString *text = [self.adviceData objectAtIndex:indexPath.row];
[cell.textLabel setText:text];
They both seem to do the same thing, but one has more brackets. Do the brackets do something?
The first one is just using the dot-notation syntax added in Objective-C 2.0. They both call the setText: method on the textLabel.
By the way, here's an article which will help you decide whether to use dot-notation syntax or not in your code.
They both do exactly the same thing, but the first one uses the alternative syntax for calling a setter (I'm ignoring the difference due to introduction of the NSString *text variable). Behind the scene, the compiler generates identical code for the two calls.
I am trying to fetch data from core data, it works fine. But when I try to fill a Table Cell then it gives me warning at the following line
cell.textLabel.text = [fetchedObjects objectAtIndex:indexPath.row];
Warning : passing argument 1 of 'objectsAtIndexes:' makes pointer from integer without a cast.
fetchedObjects is an NSArray object declared in header file. Kindly guide me where I am doing wrong. I can provide whole method for more understanding.
Regards.
EDIT
Here is my complete method code:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"] autorelease];
cell.textLabel.text = [fetchedObjects objectAtIndex:indexPath.row];
return cell;
}
Your posted code says you're calling objectAtIndex, which does indeed take an integer parameter. However, your error says you're using objectAtIndexes, which takes a pointer to an NSIndexSet. As indexPath.row is not an NSIndexSet pointer, you're getting that warning (saying that you're trying to use a raw integer as a pointer).
Check your actual code. Almost certainly, you're using objectAtIndexes by mistake.
Following the documentation on custom cells from a NIB (the Dynamic option), I have this method. (The view itself is not a UITableViewController, but it's hooked up properly.)
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"ReusableCell";
UITableViewCell *cell = (LoadGameCell *)
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[NSBundle mainBundle]
loadNibNamed:#"LoadGameCell" owner:self options:nil];
cell = loadGameCell;
self.loadGameCell = nil;
}
/*
cell setup
*/
return cell;
}
The first line in the if statement is the bit I'm having trouble with.
Incompatible pointer types assigning to 'UITableViewCell *' from 'NSArray *'
Incompatible Objective-C types assigning 'struct NSArray *',
expected 'struct UITableViewCell *'
No errors/crashes running the app with these warnings, but I'd rather not ignore/suppress them. It'll hurt a whole lot more later on.
If it isn't a direct result of the warnings above, there's another problem. I can't get the method to take views, only labels. (That is, I can customize a label, but not the image view it's sitting next to.)
As the documentation will tell you, loadNibNamed:owner:options: returns an array. To access the cell in the NIB (assuming it is the only root-level object in the NIB), call objectAtIndex:0 on the result of loadNibNamed:owner:options.
I have a memory leak that displays UICachedDeviceWhiteColor. I'm not using UICachedDeviceWhiteColor anywhere and a search on it turns up people saying this is a bug in the iPhone-SDK. I found this blog entry:
http://piezoelectrics.blogspot.com/2009/02/uicacheddevicewhitecolor-leak-in-iphone.html
but I can't find
#import "NSAutoreleasePool.h"
I get an "error: NSAutoReleasePool.h: no such file or directory". Is there a fix for this memory leak or a correct way to allocate table cells from nibs?
Here's how I'm currently doing it:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"CellNameIdentifier"];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"CellName" owner:self options:nil];
//cellName is IBOutlet to XIB's tablecell. I reference it several times in this calss
cell = cellName;
}
return cell;
}
I don't see an alloc here so why would there be a mem leak? Could this be a problem:
#property (nonatomic, retain) IBOutlet UITableViewCell *cellName;
Because of your property declaration, the sythesized setter for your cellName property will retain the object passed to it.
You should send a release message to cellName in your dealloc method.
Furthermore, there is no need to load the nib every time the cellView is requested. Either check if cellName != nil and return it or set the reuseIdentifier on the cellView so that it can be found by dequeueReusableCellWithIdentifier.
Actually, if you're using a NIB for your table view cell (not normally necessary unless you're doing something really custom) you will have to load it each time you didn't get a hit on the reusable table view cell. I think the following code looks a bit cleaner:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyID"];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CellName"
owner:self options:nil];
cell = [nib objectAtIndex:1];
}
The objectAtIndex:1 trick works if the cell is the first object in the NIB (the zero object is the file owner).
Some notes for doing table view cells:
Don't retain your cell objects either implicitly by assigning to a property or manually. This will make the the reusable table cell functionality not work properly since it can't free the cell memory.
Don't forget to set the cell reuse identifier in interface builder since you can't do it in code if you're using a NIB.
Always make sure the cell is autoreleased. Either do it manually, or ensure you're using a cocoa function that returns autoreleased memory (as the objectAtIndex: method does).