Question about nibs

I've been trying to build a tableview, and some articles are concerned with methods that instantiate nibs and others say that storyboards supercede nibs.


I'm using storyboards to make a layout with a tableview in it but currently it doesn't display the contents. I've confirmed that it's actually running the code, it is being instantiated, but the table view still remains empty with my custom cell type.


My search has lead me to the forums in search for answers. I was able to found the following articles.


https://forums.developer.apple.com/message/136225#136225

https://stackoverflow.com/questions/22882544/empty-prototype-cell-for-a-uitableview


Here's the layout in the interface builder.

http://imgur.com/a/QSVdf


Obviously the second article is interesting. it says that the storyboard way of doing it is by NIB. but I was under the impression NIBs were old fashioned.


I have no nib for the custom cell... it is part of my storyboard layout.


I'm new to xcode and swift. All the guides i've followed don't seem to have these problems with them (you just put the custom cell inside the storyboard, and then make the data source and delegate classes. these are all, from the interface builder part of the ReceiverScreen view controller in the picture.


This is a follow up to my previous problem with nil values on my custom cell. that was fixed but you can goto that article to see what i'm talking about in context.


https://forums.developer.apple.com/thread/85393


The question is what information do i need to know in relation to getting this to work? I'm trying to find resources about nibs with storyboards. Because i'm just starting developing on ios, i get a bit muddled with how to do things.


I need to know how this all fits together.


Thanks for any help in advance it's appreciated.

Storybopard is a way to assemble various Nib inside a common view and describe transitions between the views.

But nib do not disappear ; in particular, you can have a nib to define custom cell (that's what I do)


- you define the class for the cell MyCustomCell, subclass of UITableViewCell, with all the outlets for the content of the cell

if for instance you have a label, that you declare as num corresponding to an IBOutlet that you name numLabel:

class MyCustomCell: UITableViewCell {
    var num: String = "" {
        didSet {
            if num != oldValue {
                numLabel.text = num
            }
        }
    }
    @IBOutlet weak var numLabel: UILabel!

Note how you can update automatically the label when the co,ntent of the var num chan,ges, with a didSet


- you create a nib file (use the same name, so the link between the 2) : MyCustomCell.nib

- open the nib file, draw the custom cell with all its views inside ; connect each object to an IBOutlet in MyCustomCell class


- You give an Identifier to the custom tableviewcell: MyCellIdentifier

- in the class of customcell, you awake fromNib:

    override func awakeFromNib() {
        super.awakeFromNib()
    }


- In the tableView controller, you register the custom cell

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(MyCustomCell.self, forCellReuseIdentifier: "MyCellIdentifier")


- In IB, in the tableViewController, you have the tableView and its prototype cell : give the Identifier MyCellIdentifier to the cell (which is custom type).

- check that delegate and datasource are set to TableViewController (that has been done automatically when you defined the tableview)


from there everything should work.

If the table view "still remains empty", the first presumption would be that the number of rows is 0, and the second would be that "tableView(_:cellForRowAt:)" is failing in some way, typically due to a mismatched identifier. NIB problems are further down the list of likely issues. Still …


>> Storyboard is a way to assemble various Nib inside a common [design-]view


Indeed, but I think it's useful to clarify the terminology:


– In the old, old days, there were NIB files that you edited directly in Xcode (or, in those days, in Interface Builder, which was still a separate app). NIB files are binary files. In fact, they're contain archive data created by NSKeyedArchiver.


— Sometime around macOS 10.4 IIRC, NIB files were replaced by XIB files, which are text files that represent the design shown on the IB canvas. They're compiled into NIB files when you build your app. The value of XIB files is that they're suitable for SCM, since they have lines of text that can be compared, and they can contain additional design information that doesn't need to be part of the final built app.


— More recently, storyboards were introduced and are gradually taking over from XIB files (faster on iOS than macOS). Storyboards are also SCM-friendly, and are compiled into a different format, but this compiled format is (or at least is partially) a package of regular ol' NIB files. That is, the underlying run-time technology is much the same as it ever was.


I say all this because…


>> I was under the impression NIBs were old fashioned


Not at all, they're just kinda an implementation detail that developers normally don't have to think about any more. If anything, it's XIBs that are old fashioned.


And I say all this because…


The stuff out there about NIBs has produced unnecessary anxiety in the OP. I bet the problem is something straightforward, such as one of the things I mentioned first.

You said nib, but when i go add file->user interface-> empty it creates a xib file.


For the sake of time, how do you simply make a NIB file? again. this is like a wild goose chase.


Thanks you've been really helpful.

Hi,


followed instructions to a 'T'


i've modified the datasource method to dequeue cell, and then instantiate from the nib.


Here's the code:


let identifier = "PanicAlertTableViewCell"
        print("using identifier: " + identifier)
      
        if let dequeuedcell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath) as? PanicAlertTableViewCell {
            print("isadequeuedcell")
            print("identifier :" + dequeuedcell.reuseIdentifier!)
          
      
        }


let cell = PanicAlertTableViewCell.instantiateFromNib(viewType: PanicAlertTableViewCell.self)


This is a helper method which makes it easier to get the required type from the nib. It requires that the class have the same identifier as the other, the code looks like this:


public extension UIView {

    public class func instantiateFromNib<T: UIView>(viewType: T.Type) -> T {
        return Bundle.main.loadNibNamed(String(describing: viewType), owner: nil, options: nil)?.first as! T
    }


}



So if i use the line in the top example, it would return a PanicAlertTableViewCell object with the nib named PanicAlertTableViewCell


I have registered the custom cell with the table.

tblAlerts.register(PanicAlertTableViewCell.self, forCellReuseIdentifier: "PanicAlertTableViewCell")



This method is run when the view appears.


The Table View in the storyboard uses dynamic prototypes.


it is empty. however it runs that register command. I imagine that if i did not register it, the datasource function would break.


this is the code for the setting:


public var num : String = "" {
        didSet{
            if num != oldValue {
            
                lblNumber.text = num
                print("num: " + lblNumber.text!)
            }
        }
    }

    public var alert : String = "" {
        didSet {
            if alert != oldValue {
            
                lblAlert.text = alert
                print("description: " + lblAlert.text!)
            }
        }
    }



Here is the debug log:


2017-08-28 12:44:03.868 vgsecurity[8394:178074] [Crashlytics] Version 3.8.5 (123)
Counting rows
0
Counting rows
0
Counting rows
0
ERROR /BuildRoot/Library/Caches/com.apple.xbs/Sources/VectorKit_Sim/VectorKit-1230.34.9.30.27/GeoGL/GeoGL/GLCoreContext.cpp 1763: InfoLog SolidRibbonShader:
ERROR /BuildRoot/Library/Caches/com.apple.xbs/Sources/VectorKit_Sim/VectorKit-1230.34.9.30.27/GeoGL/GeoGL/GLCoreContext.cpp 1764: WARNING: Output of vertex shader 'v_gradient' not read by fragment shader




[vgsecurity.PanicSender]
Counting rows
1
using identifier: PanicAlertTableViewCell
isadequeuedcell
identifier :PanicAlertTableViewCell
number of Sections: 1
number of Rows: 1
vgsecurity.PanicSender
num: 1)
description: Nathan Sinclair



The line 20 is the identifier that can be received from the cell.


Still no displaying.

Quincey explained the difference between xib and nib.


But, in usual language, we very often use nib when we should say xib.


So you are right, you create a xib file (that will later be compiled into nib, but you don't see it).

Note that func are called awakeFromNib for instance.


So, if everything OK, don't forget to close the thread.

Wish you good development.

It seems to me this discussion is lost in the weeds. Apart from anything else, it's impossible for anyone to help you when that involves an entire history of attempts to add code to solve a problem. It's necessary to narrow down the focus to one thing, for the primary reason of determining if that one thing is the problem. If it's not, the debugging effort is wasted. (And for the secondary reason of preventing information overload.)


Your original problem (IIUC) is that your table view doesn't display any data. To solve that, you need to go back to first steps:


1. Create a table with a standard UITableViewCell cell. For now, give it a new reuse identifier that you haven't previously used, so it's clear which identifier belongs to which iteration of this process. I'll pretend the identifier is "RU1", though you of course will want to use something more meaningful. In your "tableView(_:cellForRowAt:)" method, use identifier "RU1", set the standard label text field to something or other just to show that it works.


Does that setup show the correct number of rows, with the correct label text in each row? If not, then there's no purpose in proceeding until you've solved that.


2. Create a subclass of UITableViewCell. For now, you don't have to add any behavior to it. You just need a different class name. In your storyboard, change the class of the table's prototype cell to your subclass name. In your "tableView(_:cellForRowAt:)" method, check that a cell of the correct subclass was returned using an "as?" or "as!" check on the dequeued object. ("as!" seems preferable, since this should never fail to be of the correct class, so you have no valid recovery strategy if it does fail.)


Does your table view still work?


3. Create a separate XIB file which contains a single top level object that is the UITableViewCell subclass type. For now, you don't have to add anything to it or rearrange it, just make sure it has a label field. Give this cell a different reuse identifier, say "RU2". Note that you cannot use "RU1" here, unless you delete the original prototype in the table, because that would make the identifier ambiguous. In your view controller, add one line of code to register this NIB in (say) viewDidLoad. In your "tableView(_:cellForRowAt:)" method, use the "RU2" identifier, and check that you get an object of the correct class.


Does that work?


If you get this far, then you can start customizing your UITableViewCell subclass. At that point, you can delete the prototype cell ("RU1") from the table view, or leave it there and ignore it.


My guess is that you've somehow provided two different prototype cells under the same reuse identifier, one in the table view and one in a separate NIB. You will see inexplicable behavior if you do that. However, even if that is not the cause, you need to proceed stepwise until you find out where things go wrong.

Question about nibs
 
 
Q