I have been following the guide from Apple:
http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/TableView_iPhone/TableViewCells/TableViewCells.html#//apple_ref/doc/uid/TP40007451-CH7
concerning: Technique for Static Row Content.
My problem is the following:
All my cells are nil.
According to Apple, the loading of the view should instantiate all object populating that nib file, bit only the tableview is instantiated. Thus the cell are nil and crashes the program in method cellForRowAtIndexPath: when it is returning a NULL cell.
I have followed the guide to the letter, search all over and have found no solution, except creating a nib for each cell and loading those ones when needed, but that solution is much less elegant than the Apple solution.
Any help would be appreciated.
You have probably not bound your IBOutlets for the cells to the cells themselves. If your cell ivars are nil, then you didn't wire something.
EDIT
If the IBOutlets are connected, but the ivars are nil, then the IBOutlets aren't connected. There other possibilities, but that's the most common. Other possibilities: you're trying to access prior to viewDidLoad. In particular, you can't access your ivars during initWithFrame:. Other possibility is that you're overwriting them at some point. Check their values in viewDidLoad. Other possibility is that you're loading the wrong nib file, or not loading a nib file at all. All possibilities, but I'd first check everything in viewDidLoad and double-check you're connections.
When instantiating your table view controller, in your init method you should call the overridden designated initializer of the superclass ([UIViewController initWithNibName:bundle:]), passing in the nib name:
- (id)init {
return [self initWithNibName:NSStringFromClass([self class]) bundle:[NSBundle mainBundle]];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization here
}
return self;
}
For more details, see this answer: Automatically Loading XIB for UITableViewController
Related
I'm really going crazy on this.
But let me explain to you my little project first:
I have an Custom UITableView TDStartTableView.
Also in there I have some methods implemented for rendering the table. No problem there.
Inside of one TableViewCell there is a button.
When that Button is clicked it triggers this method:
- (void)triggerPush {
[self.delegate pushNextView];
}
self.delegate is specified in the .h file of TDStartTableView like this:
#property (nonatomic, weak) id<TDStartTableViewDelegate> delegate;
Also, the reference is set in my UITableViewController:
self.tableView.delegate = self;
So essentially what I'm trying to do is: Create a custom UITableView with Buttons etc. and then listen on the events from a ViewController that is implementing that UITableView and the protocol
So because the protocol forces me to implement pushNextView this method is in my UIViewController:
- (void)pushNextView {
NSLog(#"This works");
}
To this point everything works just fine, no problem there!
But now comes the tricky part.
I create a segue from my UIViewController to a new ViewController. I connect them via a segue and name the segue appropriately. pushToSecondStep.
Now one would think, that when I change the implementation of pushNextView to this
- (void)pushNextView {
[self performSegueWithIdentifier:#"pushToSecondStep" sender:self];
}
it works. But what I get is:
'Receiver (<TDFirstStepTableViewController: 0x8dc97d0>) has no segue with identifier 'pushToSecondStep''
Please help, I'm going crazy :D
The problem was, that I overwrote a constructor of TDStartTableView.
The proper form is that you implement all constructors, so that Objective-C can instantiate them all by itself:
- (id) initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
return self;
}
Also when you implement a custom UITableView Widget you shouldn't use UITableViewController but UIViewController.
Also you don't initialize your custom UITableView yourself, Storyboard already does that for you, so if you want to set special variables for it like numberOfRows then just declare a property and then set it via a setter-method outside and call [tableView reloadData].
Also, thanks https://stackoverflow.com/users/1095089/shubhank for helping me in the chat :)
-(id) initForNewItem{
self = [super initWithNibName:#"EmployeeDetailViewController" bundle:nil];
if(self){
[nameField setDelegate:self];
[pinField setDelegate:self];
}
return self;
}
In this case, the delegates are not successfully set. However, if I go into the xib file and ctrl-click + drag the UITextFields onto the file owner and set them as delegates through that, it works. Can someone explain why calling setter methods in the init method does not work?
Inside init method, the views haven't been loaded. All the visual setup must be done further on in the viewController's lifecycle, at least into the viewDidLoad method. Or in case that you don't go for a .xib solution, you can do it while loading the view manually, into the loadView method.
So, both labels are nil into the init method, and the delegate can't be set.
I'm trying to save custom cell objects and later on show them. But fail to understand the mechanism totally i have:
- (id)initWithCoder:(NSCoder *)decoder {
if((self = [super init])) {
self.action = [decoder decodeObjectForKey:#"action"];
}
return self;
}
and
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
}
return self;
}
this way I get my variable decoded but the tablecell doesn't show up at all. if I remove init with coder i do get my tablecell interface showed, but can't get variable decoded. What should I do to make this work?
I think i can see your problem.
still, you shouldnt save the cells themselves. just create a UITableViewCell-Subclass that accepts one object from which it will gather all of its content. if you need more than one class for this, thats fine too. You can easily create several subclasses for several usecases.
then just save the data-objects and recreate the cells when you need them again.
the reason for this is that your way creates massive overhead, because you are trying to save all the UIviews, Lables, etc that make up your cell. Also, UITableVIews are highly optimized and try to reuse existing cells which does not play well with your approach.
TL;DR:
You need dataobjects, which you can save in keyedArchivers, and you need tableviewcells that accept these objects and display the necessary data. Seriously, you will save yourself some trouble. Let me know if you need help and have fun
I have designed a nice custom control CustomUIView as a subclass of UIview, with a nice initialiser that takes in 8 parameters. I made it to be the designated initializer to make sure, any user will provide all the 8 parameters correctly.
After few days, I wanted to reuse that control in a different project where nibs are used.
I added a basic UIView into the canvas of one of the NIBs and changed The Custom class option to my CustomUIView class. But I immediately realised my nice initializer is of no use, since it is not called at all.
What would you recommend to do about this? I want to ensure that
all the parameters are taken in but at the same time
I want basic positioning of that custom control in IB.
Why not build on top of the standard UIViewController initializer for NIBs then?
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle parameter1:(id)param1...
NSAssert(param1 != nil && param2 != nil ...);
if (self = [super initWithNibName:nibName bundle:nibBundle]) {
//Custom initializations here.
}
return self;
}
Is there a method that is always called in Cocoa? Many classes have init or initWith, but even worse they can be loaded from a nib or something. I don't want to have to scrape around and find how it does this in this case. I just want to set some initial variables and other things, and I want a method to subclass that I can depend on no matter if it's a UIView, UIViewController or UITableViewCell etc.
No there is not such a method. init comes from NSObject so every object can use it, and as well subclasses define their own initialization methods. UIView, for example, defines initWithFrame: and furthermore there are init methods from protocols, such as NSCoding which defines initWithCoder:. This is the dynamic nature of objective-C, anything can be extended at any time. That being said, there are some patterns. UIViewController almost always takes initWithNibName:bundle: and UIView almost always takes initWithFrame: or initWithCoder:. What I do is make an internal initialize method, and just have the other inits call it.
- (void)initialize
{
//Do stuff
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
[self initialize];
}
}
- (id)initWithCoder:(NSCoder *)aCoder
{
self = [super initWithCoder:aCoder];
if(self)
{
[self initialize];
}
}
Not 100% sure that it is always called, but I am pretty sure that this is a viable option. To be perfectly honest, I can't recall that I have ever seen this method used in practice and I usually shy away from using this method (I have absolutely no idea why, probably because it's just not the cleanest and most comprehensive method to achieve this...):
-didMoveToSuperview()
From documentation:
Tells the view that its superview changed.
The default implementation of this method does nothing. Subclasses can override it to perform additional actions whenever the superview changes.
There's many ways you can write a custom initializer.
- (id)initWithString:(NSString *)string {
if((self == [super init])) {
self.string = string;
}
return self;
}
That's just how I write my initializers in general. For example, the one above takes a string. (you don't have to pass strings if you don't want).
Btw, init is a method. According to the header for NSObject, init has a method implementation.