UPDATE: I decided to start over since I was still in the early stages of this app. I repeated everything and for whatever reason, the custom cell took the second time around. I will keep the old files around to confirm another answer, as I imagine I am not the only one who will have this problem.
I am building a tabbed application that requires custom cells in its table views. I have done this a few times and I always seem to hit a speed bump when hooking up these custom cells. The app booted up fine until I started using the custom cell in my table view controller titled SongsTVC. I am receiving a termination with a reason of:
[<SongsTVC 0x6831330> setValue:forUndefinedKey:]:
this class is not key value coding-compliant for the key albumLabel.
I am using this tutorial and have used it before (changed a few things for ARC and iOS 5) with success. In fact, the code and IB layout I am using is based off of an already working project I have. I am aware of this error commonly presenting itself when you hook up your outlets to the file's owner and not the cell itself. I am not making this mistake but it is still giving me this error. So far, I have removed the label it has a problem with and even deleted the cell's files entirely in order to start over. Any help would be appreciated.
SongCell.h
#import <UIKit/UIKit.h>
#interface SongCell : UITableViewCell{
}
#property(nonatomic, assign) IBOutlet UILabel *titleLabel;
#property(nonatomic, assign) IBOutlet UILabel *artistLabel;
#property(nonatomic, assign) IBOutlet UILabel *albumLabel;
#end
SongCell.m
#import "SongCell.h"
#interface SongCell ()
#end
#implementation SongCell
#synthesize titleLabel, artistLabel, albumLabel;
#end
SongsTVC.h - Header of the TableViewController
#import <UIKit/UIKit.h>
#interface SongsTVC : UITableViewController{
UINib *cellLoader;
}
#end
SongsTVC.m - Relevant TableViewController methods
#import "SongsTVC.h"
#import "SongCell.h"
#interface SongsTVC ()
#end
static NSString *CellClassName = #"SongCell";
#implementation SongsTVC
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
cellLoader = [UINib nibWithNibName:CellClassName bundle:[NSBundle mainBundle]];
}
return self;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
SongCell *cell = (SongCell *)[tableView dequeueReusableCellWithIdentifier:CellClassName];
if (!cell)
{
//CRASH ERROR POINTS HERE
NSArray *topLevelItems = [cellLoader instantiateWithOwner:self options:nil];
cell = [topLevelItems objectAtIndex:0];
}
// Configure the cell...
cell.titleLabel.text = #"SONG";
cell.artistLabel.text = #"Artist";
cell.albumLabel.text = #"Album";
return cell;
}
Interface Builder
NOTE: The cell identifier has been set to "SongCell" in IB and the file owner is UITableViewController because multiple tables will be using this cell. As long as the view is a table, it should work (it has in the past).
UPDATE: The xib file in XML format has been pasted here.
I had this exact problem today, while making a sample project for another SO answer! It looks like your xib is trying to connect an outlet to your view controller instead of your cell. In your screenshot, the outlets look correctly defined, but occasionally an old outlet definition can get left in the underlying XML and cause this type of crash.
If you've changed the files owner class after connecting some outlets, for example, this could confuse it.
You may be able to find it by opening the xib as "source code", look for the element and check there are only the entries you expect. Perhaps search the XML file for albumLabel as well.
If that doesn't work, you may have to scrap the xib and start again.
Unfortunately, the only solution that I have found was to start over. I did everything exactly as I did before and it worked the second time around. It was quite a chore having to scrap the entire thing and start over but it was the only way I could get it to work. I'm leaving this as the answer unless somebody can figure out what happened. (See original post and its update)
I had a similar issue and was able to solve it by rebuilding the Storyboard/NIB.
Related
I'm developing an iOS-App and therefore I use a UITableViewController. Within "cellForRowAtIndexPath" I use cells with reuse identifiers:
[[[UITableViewCell alloc] initWithStyle:UITableViewCellStyle1 reuseIdentifier:textFieldIdentifier];
The problem is that some cells have a dependecy on each other, e.g. if the user enters text in one cell another cell changes its value.
So what is the best way to safe a reference to the cell that has to be changed? The problem is, that if I safe the reference within "cellForRowAtIndexPath", during the callback for "textFieldDidChange" the reference might be broken, e.g. if the cell is not visible or another cell has the adress due to the reuse identifier?!
Don't try to save references to cached cells. Update whatever you need to display in the table's data source and then call reloadData. That way, the table takes care of refreshing visible cells and dealing with the cache...so you don't need to.
I would make an protocol for the cells
Example
#protocol MyProtocol <NSobject>
- (void) changeText:(NSString)theText;
#end
#interface TableViewCell1 : UITableViewCell
#property (nonatomic, weak) id<MyProtocol> delegate;
#end
#implementation TableViewCell1
//put this in the method where you get the value of the textfield
[self.delegate chageText:#"Hello"];
#end
#interface TableViewCell2 : UITableViewCell <MyProtocol>
#end
#implementation TableViewCell2
- (void) chageText:(NSString *)text {
self.textLabel.text = text;
}
#end
I have a trouble when set custom cell into UICollectionViewController.
This is my code.
KidsDetailViewController.h
#import <UIKit/UIKit.h>
#interface KidsDetailViewController : UICollectionViewController <UICollectionViewDataSource>
#property NSNumber *idCampana;
#property (weak, nonatomic) IBOutlet UICollectionView *grid;
#end
KidsDetailViewController.m
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [grid_kid count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
GridCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"MY_CELL" forIndexPath:indexPath];
cell.imageView.image = [UIImage imageNamed:self.truckImages[0]];
cell.prd_img.image = [UIImage imageNamed:#"ic_launcher_58x58"];
return cell;
}
GridCell.h
#import <UIKit/UIKit.h>
#interface GridCell : UICollectionViewCell
#property (weak, nonatomic) IBOutlet UIImageView *prd_img;
#end
GridCel.m
#import "GridCell.h"
#implementation GridCell
- (instancetype)initWithFrame:(CGRect)frameRect {
self = [super initWithFrame:frameRect];
if (self) {
// Initialization code
}
return self;
}
#end
This is the Error.
*** Assertion failure in -[KidsDetailViewController loadView], /SourceCache/UIKit_Sim/UIKit-3283.1/UICollectionViewController.m:166
2014-07-28 02:25:18.874 Geelbe[7673:231598] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UICollectionViewController loadView] loaded the "jXd-Ir-mr4-view-0IK-5Q-NzC" nib but didn't get a UICollectionView.'
*** First throw call stack:
I've tried everything and still gives error.
Thanks.
I had this issue when adding a UICollectionViewController as an embedded container view controller on a storyboard.
I switched the container view controller's custom class to be a Collection View Controller. But the view property inside that view controller was still the Xcode boilerplate UIView.
Delete the default UIView within your controller on the storyboard and replace it with a UICollectionView. The outlets should be reconnected automatically.
I think the problem may be because you inherit from UICollectionViewController, you do not have to specify anymore , because it already implements it. Try top delete it, see if it would fix your error.
Also in the Identity Inspector make sure you set the class KidsDetailViewController for the corresponding View Controller.
Jeff Kelley's answer here worked for me for same error.
When you’re using a UICollectionViewController, the view outlet needs
to be connected to a UICollectionView in your storyboard; if it’s a
UIView of another class, it’ll crash.
So, I used UIViewController with UICollectionView as its property and hooked up with nib.
How to setup a collection view controller with a nib (.xib) file.
Add a new file by selecting the "Empty" template from the "User Interface" section. Drag a UICollectionView object from the object library over.
1) Associate the nib which collection view controller class.
In the Document Outline (left hand section), under "Placeholders", select "File's Owner". Show the Identity Inspector and set the class dropdown to your subclass of UICollectionViewController.
2) Associate the nib with the UICollectionView.
Again, in the Document Outline (left hand section), under "Placeholders", select "File's Owner". Right click it to see the "Outlets" and "Referencing Outlets" display. Two of the selections under "Outlets" are "view" and "collectionView". Its counter-intuitive, but drag from the "view" selection to the UICollectionView object in the Document Outline.
** If you drag from the "collectionView" selection, you will get the 'loaded the "your_collection_view_controller" nib but didn't get a UICollectionView' error.
When you build and run, the code should now "load" the nib and also "get" the UICollectionView.
I have a UITableView with some names in it. I have built my app from the MasterViewController template that Apple provides. I'm trying to store the name of the selected cell in a NSString and then access it in the other class that handles the new ViewController that appears when the cell is tapped. In there I use that string as the title of the view.
In MasterViewController.h
#property (nonatomic, retain) NSString *theTitle;
In MasterViewController.m
#synthesize theTitle;
- (void)tableView: (UITableView*)tableview didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath animated:YES];
theTitle = cell.textLabel.text;
}
In the new ViewController.m
#import "MasterViewController.m"
- (void)viewDidLoad
{
MasterViewController* MasterViewControllerAccess = [[MasterViewController alloc] init];
self.title = MasterViewControllerAccess.theTitle;
NSLog("%#", [NSString stringWithFormat:#"%#", MasterViewControllerAccess.theTitle]);
}
The new ViewController is linked to the cell in the IB. When I press the cell theTitle returns NULL. But if I log it directly in the didSelectRowAtIndexPath:method it returns the real names. This means that something wrong occurs between the different classes. What's wrong?
You are instantiating a new instance of MasterViewController, instead you need to access the MasterViewController instance that already exists. Consider following Apple's example of setting the detail item (ie from master to detail). I can't see any reason to set it the way you are doing it. In any case, if you are using a navigation controller:
#import "MasterViewController.h" // don't import .m files. Always import .h files
- (void)viewDidLoad
{
MasterViewController* MasterViewControllerAccess = (MasterViewController*)self.navigationController.viewControllers[0]
self.title = MasterViewControllerAccess.theTitle;
NSLog("%#", [NSString stringWithFormat:#"%#", MasterViewControllerAccess.theTitle]);
}
In viewDidLoad of the pushed view controller, you allocate a new instance
of MasterViewController, which is completely different and unrelated to the
existing master view controller (which has been loaded from the storyboard or nib file).
Therefore MasterViewControllerAccess.theTitle is nil.
As said in the above comments, it is usually easier to pass the information the other way
around (from master to detail view controller), e.g. in prepareForSegue as in
the template application.
I'm trying to implement a custom UITableViewCell and I'm hoping to access the parent tableView from with the cell subclass. I was in the process of creating a custom init method that allows me to specify the tableview, but came across an error.
I tried declaring an iVar of __weak UITableView *_tableView; however, I was given an error stating it was a duplicate declaration. I looked into the UITableViewCell header file, and sure enough, there is a declaration of
#private
UITableView *_tableView;
This is great as I assume iOS will be setting this for me, however I want to know if I'm allowed to use this, or if this is one of those things that will get my app rejected. There is no documentation on this and I've not found any mention of if anywhere online.
Any ideas?
You're right not to try to access the private ivar. I'd suggest not bothering to pass in the superview, either, but just use what's available to the table cell to find its enclosing tableView
UIView+mytable.h:
#import <UIKit/UIKit.h>
#interface UIView (mytable)
- (UITableView *)mySuperTableView;
#end
UIView+mytable.m:
#import "UIView+dsltable.h"
#implementation UIView (dsltable)
- (UITableView *)mySuperTableView
{
if ( [self isKindOfClass: [UITableView class]] )
return (UITableView *)self;
return [self.superview mySuperTableView];
}
#end
No, you can't access the undocumented private ivar. You either need to add your ivar with a different name or get the table view by getting the cell's superview.
I've been searching all throughout the internet for assistance, however there has been little to no solutions to my issue at hand. My project that im trying to get a gasp on is somewhat unique (UI is not exactly following the typical norms).
Current Development Enviroment:
xcode 4
storyboards instead of nibs
Below is a diagram of what i am trying to accomplish -- all within a UIView Controller:
UIView is the light grey background
UITableView 1 - this is a static (or it can be dynamic, thats another challenge) UITableview which will hold different numeric
values for calculation
UITableView 2 - this is a UITableview which will hold calculated results every time it is run.
UIImageView 1 - this is a calculated image example (I have that figured out)
Im sure experienced developers are fully aware of my issue, and or what im about to ask. I understand that a static UITableView is required to be in a tableview controller, but I need to display both the UItableView's at the same time which means it has to be within a UIView.
I can make the interface look the way I need it to through the IB however when trying to compile and build I receive the error that requires the UITableView's to be within a UITableViewController and not a UIView Controller. I have seen many examples using a master-detail layout, but the only stipulation is that this UITableview NEEDS to be displayed 100% of the time when in this view.
So basically, I am asking for direction... but a code example never hurt either! Thank you 100x's over!
-Jonathan
UITableViewController is just a specialized UIViewController specially designed to display full screen UITableViews. It is (quite) equivalent to use an UITableViewController subclass or an UIViewController <UITableViewDataSource, UITableViewDelegate> subclass to manage a tableview.
So even if UITableViewController has some more spiecialized behaviors (automatically creates the UITableView if it does not exists, scrolls it automatically to display the keyboard, sets itself as the delegate and dataSource of the unique UITableView it manages, etc), you can use a standard UIViewController to manage a UITableView and be its dataSource to fill it.
That's even a way to manage a tableview that is not taking the full screen (as UITableViewController expects its view property to directly be the UITableView it manages, not a subview of its main view or whatever, and thus expects the UITableView to take the whole screen, contrary to using an UIViewController that has an UITableView as a custom-sized subclass of its view)
So in your case, you can have an UIViewController that has two IBOutlets, one for each tableView, and that unique UIViewController can be the dataSource (and delegate) of both the UITableViews. That's not a problem. Just be careful then in your datasource methods to distinguish if you are returning data for the first or the second UITableView to feed the correct tables each time.
#interface MyViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, retain) IBOutlet UITableView* masterTableView;
#property (nonatomic, retain) IBOutlet UITableView* detailsTableView;
#end
#implementation MyViewController
#synthesize masterTableView = _masterTableView;
#synthesize detailsTableView = _detailsTableView;
// Proper memory mgmt not shown here:
// - don't forget to set self.masterTableView and self.detailsTableView to nil in viewDidUnload
// - and to release _masterTableView and _detailsTableView in your dealloc method
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
UITableViewCell* cell;
if (tableView == self.masterTableView)
{
static NSString* kMasterCellIdentifier = #"MasterCell";
cell = [tableView dequeueReusableCellWithIdentifier:kMasterCellIdentifier];
if (!cell)
{
cell = [[[UITableViewCell alloc] initWithReuseIdentiier:kMasterCellidentifier] autorelease];
// do some configuration common to all your master cells
}
// configure the rest of your cell for each property that is different from one cell to another
}
else if (tableView == self.detailsTableView)
{
// Do exactly the same principle, but for the cells of your "details" TableView
}
return cell;
}