First of All Thanks for the iCarousel. I am trying the iCarousel in custom TableView Cell, but it crashes by saying "Unrecognized selector sent in numberOfItemsInCarousel". Please help me on this. Thanks in advance..!
-(nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
TimelineCell *cell = (TimelineCell *)[tableView dequeueReusableCellWithIdentifier:#"timelineCell"];
if (cell == nil) {
NSArray *cellItem = [[NSBundle mainBundle]loadNibNamed:#"TimelineCell" owner:self options:nil];
cell = [cellItem firstObject];
}
cell.images = imageArray;
return cell;
}
- (NSInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
[carousel setType:iCarouselTypeTimeMachine];
return [_images count];
}
Sounds like the delegate for the iCarousel is set to something else than the class implementing the method numberOfItemsInCarousel:(….
Make sure you've set the delegate to the correct instance.
You probably want the TimelineCell to be the carousel delegate, so make sure that you do set it (either in your xib-file or programatically). Put the numberOfItemsInCarousel(…-method implementation in the TimelineCell class and it should work.
Another tip is to not set the carousel type in the method numberOfItemsInCarousel(…. Not a pretty place for it. Instead do it in some initialisation method.
Related
I have a project where I need to use a custom UITableViewCell. I'm designing the cell as a prototype in storyboard and it looks fine there. I assign the prototype to my custom UITableViewCell subclass, give it the same reuse identifier I'm using in my UITableView and link the UILabel on the prototype cell to an IBOutlet in my UITableViewCell subclass.
When I call it from the UITableView the cell is created and if I add labels and buttons in the code of that class (create them with a CGRect and all) they all work but the labels I've added in the storyboard never show up.
I don't understand how my subclass can be called and created successfully but its layout and subviews from the storyboard don't seem to exist as far as my app is concerned. What am I doing wrong?
Here's my cellForRowAtIndexPath code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
// Configure the cell...
return cell;
}
I've run into this issue before, and in my case, the problem was that the auto-generated code for the view controller included a call to:
[UITableView registerClass:forCellReuseIdentifier:]
I would suggest checking for and removing any calls to the above, or to
[UITableView registerNib:forCellReuseIdentifier:]
and trying your original code again.
acreichman, add casting in cellForRow and put an NSLog in you cell's awakeFromNib to see if you get there. Let me know...
Your cellForIndexViewPath should look like this, to create a simple custom cell with label,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = (SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.nameLabel.text = [tableData objectAtIndex:indexPath.row];
return cell;
}
Make sure that you have made all connections well, set datasource and delegate to table and then set the “Identifier” of the custom cell to "MyTableViewCell" in “Attributes Inspector” like this,
For storyboard:
Add "MyTableViewCell" instead of "SimpleTableCell" as shown in above screenshot.
I've read all the relevant other questions on this topic and tried the fixes, none of which have worked. My app crashes/hangs to the extent that I have to force quit Xcode in order to restart working, when dequeueReusableCellWithIdentifier: is called.
It makes no difference if I use dequeueReusableCellWithIdentifier:, or dequeueReusableCellWithIdentifier:forIndexPath: , and I HAVE set the class with registerClass:forCellReuseIdentifier: , as you can see in the code below.
Registering the class in my ViewController:
#implementation LWSFlavourMatchesViewController
-(void)viewDidLoad
{
[super viewDidLoad];
_flavourMatchesView = [LWSFlavourMatchesView flavourMatchesViewWithDataSource:self.flavourMatchesDataSource andDelegate:self.flavourMatchesDelegate];
self.tableView = _flavourMatchesView;
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"flavourCell"];
}
And trying to dequeue cell in tableView:cellForRowAtIndexPath in my dataSource:
#implementation LWSFlavourMatchesDataSource
// other methods...
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *flavourCellIdentifier = #"flavourCell";
NSString *currentSelectedFlavour = [self.flavourWheel selectedFlavour];
UITableViewCell *tableViewCell = [tableView dequeueReusableCellWithIdentifier:flavourCellIdentifier forIndexPath:indexPath];
if(tableViewCell == nil)
{
tableViewCell = [[UITableViewCell alloc ]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:flavourCellIdentifier];
}
[tableViewCell.textLabel setText: currentSelectedFlavour];
return tableViewCell;
// return [UITableViewCell new];
}
If I remove all other code but un-comment out return [UITableViewCell new]; then the app does not crash. What is it about my dequeuing that is causing this problem?!
I refactored your tableview delegate. You do not need to check if the cell is nil because you registered the class with [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"flavourCell"];.
I made your cellIdentifier static. But to remove the duplication on the registerClass function may you make a #define REUSE_IDENTIFIER #"flavourCell".
If this is still slow, than is the [self.flavourWheel selectedFlavour]; the cause. Check out the instruments tutorial for performance improvements: http://www.raywenderlich.com/23037/how-to-use-instruments-in-xcode
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *flavourCellIdentifier = #"flavourCell";
NSString *currentSelectedFlavour = [self.flavourWheel selectedFlavour];
UITableViewCell *tableViewCell = [tableView dequeueReusableCellWithIdentifier:flavourCellIdentifier forIndexPath:indexPath];
[tableViewCell.textLabel setText: currentSelectedFlavour];
return tableViewCell;
}
try removing the class registration:
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"flavourCell"];
You shouldn't need to register the class if you are instantiating a generic UITableViewCell class cell from a storyboard
Another cause for this error can be-
invalid nib registered for identifier (Cell) - nib must contain exactly one top level object which must be a UICollectionReusableView instance
I had a UIView in my xib instead of a collectionViewCell. Of course, if you have multiple top level objects in the .xib, the same crash will show. Hope this helps.
Take care that if your cell is an object in a XIB, and you are using something like :
[self.tableView registerNib:[UINib nibWithNibName:#"cell_class_name" bundle:nil] forCellReuseIdentifier:#"cell_reuse_name"];
to register the cell, be sure the identifier in the attributes inspector in Interface Builder is correct, in this case #"cell_reuse_name".
If the identifier isn't the same, you may be stuck with an odd situation where creating new cells from the nib each time, i.e.
NSArray *objects = [bundle loadNibNamed:#"cell_nib_name"
owner:nil
options:nil];
cell = (UITableViewCell *)[objects safeObjectAtIndex:0];
seems to work fine, but trying to use
[tableView dequeueReusableCellWithIdentifier:#"cell_reuse_name"];
crashes.
In practice it's often easiest to use the same name for the XIB, custom class, and reuse identifier. Then if there are issues, you can just make sure they are all the same.
I had completely different issue. Mismatch between String/XIB based localization. It did help to enable/disable+remove unneeded localizations.
Try this:
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"NIB_NAME" owner:self options:nil];
If it hangs, there's something wrong with your XIB (like in my case).
Try this:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"flavourCellIdentifier"]; }
I have a few UITableViewCells that I am loading from an XIB file. Everything is great until I call the [UITableView reloadRowsAtIndexPaths:withRowAnimation:] method when the cell disappears. When I call [UITableView reloadData] everything loads find, when I scroll the cell on and off the view it will also reappear also. Weird.
I've also noticed that when I call [UITableView reloadRowsAtIndexPaths:withRowAnimation:] the UITableView will not try to reuse a cached cell and will try to get a new one with cell = [tableViewCells objectAtIndex:cellId];
Here is my code:
- (void)viewDidLoad
{
...
// the objects from the XIB files are loaded onto an NSArray instance variable at viewDidLoad
tableViewCells = [[NSBundle mainBundle] loadNibNamed:#"ProfileTableViewCell" owner:nil options:nil];
...
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
int cellId = /* some logic to get the correct cellID */
NSString *CellIdentifier = [NSString stringWithFormat:#"ProfileTableViewCell_%d", cellId];
ProfileTableViewCell *cell = (ProfileTableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [tableViewCells objectAtIndex:cellId];
// additional work to setup subviews for the cell
[cell prepareSubviews];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
}
and just in case here is some of the stuff I'm doing in [ProfileTableViewCell prepareSubviews]
- (void)prepareSubviews
{
...
[self.containerView.layer setCornerRadius:3];
[self.containerView.layer setBorderColor:UIColorFromRGB(0xCDCDCD).CGColor];
[self.containerView.layer setBorderWidth:2.0];
[self.containerView.layer setMasksToBounds:YES];
[self.containerView.layer setShouldRasterize:NO];
[self.containerView.layer setRasterizationScale:[UIScreen mainScreen].scale];
...
}
Thanks in advance to the awesome person that can help me out.
I'm not sure this is your problem, but the way you get your cells is not the normal way. You should make each type of cell in its own nib (with a unique identifier), and then register the nibs with registerNib:forCellReuseIdentifier:. In cellForRowAtIndexPath, just dequeue the cell you need based on the index path, and don't put anything in an if (cell == nil) clause, because that will not be invoked when you do it this way.
It seams that reloadRowsAtIndexPaths: doesn't work when you only need to change the height for a static cell.
Try to call just
[tableView beginUpdates];
[tableView endUpdates];
As the documentation says:
You can also use this method followed by the endUpdates method to
animate the change in the row heights without reloading the cell.
I have a UICollectionView that contains custom UICollectionViewCells (TestReceiptCell is the class name).
I was not having any problems getting the UICollectionView to appear and load the custom cells when the custom cells only contained a UILabel.
I then added a UITableView via IB into the TestReceiptCell NIB file. I set a referencing outlet in TestReceiptCell.h for the UITableView and synthesized in the .m file. I set the delegate and datasource for the UITableView to the ViewController containing the UICollectionView.
Now when running the app I get a EXC_ BAD_ ACCESS exception in this block on the third line:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"TestReceiptCell";
TestReceiptCell *cell = (TestReceiptCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath]; //exception thrown here
return cell;
}
I ran the Zombie Instrument test and found that the deallocated memory call originates here. This is my first time using that instrument so I am not exactly sure how to investigate from here.
For reference, here are some more relevant parts of the code:
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.myCollectionView registerNib:[UINib nibWithNibName:#"TestReceiptCell" bundle:nil] forCellWithReuseIdentifier:#"TestReceiptCell"];
// Setup flowlayout
myCollectionViewFlowLayout = [[UICollectionViewFlowLayout alloc] init];
[myCollectionViewFlowLayout setItemSize:CGSizeMake(310, 410)];
[myCollectionViewFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.myCollectionView setCollectionViewLayout:myCollectionViewFlowLayout];
self.myCollectionView.pagingEnabled = YES;
}
I am implementing the UITableView datasource and delegate methods in the ViewController.m file as well but I am not sure if the problem lies here given the origination of the EXC_BAD_ACCESS exception:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"eventCell"];
if(!cell){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"eventCell"];
}
return cell;
}
UPDATE:
I am able to get this to run if I change cellForItemAtIndexPath to:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"TestReceiptCell";
//TestReceiptCell *cell = (TestReceiptCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
TestReceiptCell *cell = [NSBundle.mainBundle loadNibNamed:#"TestReceiptCell" owner:self options:nil][0];
return cell;
}
However, I am not dequeuing cells and know this is not the correct way. There seems to be an issue somewhere in the initWithFrame method that gets called when dequeueReusableCellWithResueIdentifier creates a new cell. Here is that method currently:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
NSArray *arrayOfViews = [[NSBundle mainBundle] loadNibNamed:#"TestReceiptCell" owner:self options:nil];
if ([arrayOfViews count] < 1) {
return nil;
}
if (![[arrayOfViews objectAtIndex:0] isKindOfClass:[UICollectionViewCell class]]) {
return nil;
}
self = [arrayOfViews objectAtIndex:0];
}
return self;
}
EDIT:
If I do not select a delegate or a datasource for the tableview, the collectionview with tableviews will load. Something in attaching the delegate/datasource to File's Owner is causing the error.
When you register a UINib for cell reuse, dequeueReusableCellWithReuseIdentifier:forIndexPath: is what calls instantiateWithOwner:options: on the UINib that you registered. Whatever it passes for owner, is what becomes the File's Owner outlet in your nib.
It appears that you are expecting the File's Owner to be the UICollectionView, but I don't think that it is.
Even if it were, I don't think you should use the UICollectionView for the delegate of the UITableView contained within each collection cell. That would require your UICollectionView to keep track of the tableViews and contents within each cell.
I'd suggest setting the delegate of the contained tableView to the collection cell itself and have each cell manage its own tableview.
EDIT:
You can define a delegate protocol for your collection view cells to communicate the relevant table view events to the collection view. With this approach, you would set the delegate property you define for each collection cell in the collectionView:cellForItemAtIndexPath method of your collection view datasource.
When the user, for example, selects an item from the table, you can call the cell delegate to inform the collection view which item was selected.
This approach allows you to abstract the fact that your collection cell is using a table view to display the cell information. Later, if you decide you want to use, for example, an embedded UICollectionView to display those items, the delegate protocol can remain unchanged and you can isolate your changes to the collection cell.
I have a problem with my cell textfield values when scrolling on a UITableView. When I scroll down and hide a custom cell, the value of the textField is deleted. The dequeueReusableCellWithIdentifier method doesn't work. I have this:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SectionsTableIdentifier = #"MyCustomCell";
MyCustomCell *cell = (MyCustomCell *) [tableView dequeueReusableCellWithIdentifier:SectionsTableIdentifier];
if (cell == nil) {
NSArray *objects = [[NSBundle mainBundle] loadNibNamed:#"MyCustomCell" owner:self options:nil];
cell = [objects objectAtIndex:0];
}
cell.labelCustomAttribute.text= #"Attribute Name";
cell.textFieldCustomAttribute.delegate = self;
return cell;
}
I find it easier to register the custom cell with the tableView in the viewDidLoad method and then simply use dequeueReusableCellWithIdentifier. If you register the cell, the dequeue method will automatically pick up a reusable cell OR allocate a new custom cell (if none is available).
Example:
-(void)viewDidLoad
{
[super viewDidLoad];
// Get a point to the customized table view cell for MyCustomCell
UINib *myCustomCellNib = [UINib nibWithNibName:#"MyCustomCell" bundle:nil];
// Register the MyCustomCell with tableview
[[self tableView] registerNib:myCustomCellNib forCellReuseIdentifier:#"MyCustomCell"];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SectionsTableIdentifier = #"MyCustomCell";
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:SectionsTableIdentifier];
cell.labelCustomAttribute.text= #"Attribute Name";
cell.textFieldCustomAttribute.delegate = self;
return cell;
}
Normally the reuseIdentifier is assigned in the UITableViewCell's initWithStyle:reuseIdentifier: method, which you are not using because you are loading your view from a Nib.
You cannot set this property after because it is read only.
Maybe you can try instanciating the cell using the standard initWithStyle:reuseIdentifier: and add the view from your Nib as a subview of the cell's ContentView...
Now what is happening in your case is that you create a new cell every time that the Table View needs to display one. Clearly, this is not going to work. Actually, if you were reusing cells, you would have to also store the content of your text field somewhere (preferably in your data source) and put it when you reuse the cell. If you do not store it, when the cell is going to be reused, it will contain the data from the previous row in which it was displayed.