4

I have an app which utilises a set of custom "controls" which are loaded on demand from Xib files using methods similar to the below:

NSArray * topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"AudioPlayer" owner:self options:nil];
InteractiveMovieView *newAudio = [topLevelObjects objectAtIndex:0];

This approach works great except where there are multiple controls loaded at once (in effect on one "page" of the app).

Loading from the bundle each time is clearly inefficient but I can't find another way of approaching this. I've tried loading the nib into a copy property once and returning it on demand for re-use, but that doesn't work as the copy returned is never a "clean" copy of the blank nib.

I hope that makes sense, and all help is appreciated.

AustinRathe
  • 671
  • 1
  • 10
  • 21

2 Answers2

5

It sounds like you're looking for the UINib class. From the documentation:

Your application should use UINib objects whenever it needs to repeatedly instantiate the same nib data. For example, if your table view uses a nib file to instantiate table view cells, caching the nib in a UINib object can provide a significant performance improvement.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • Can you explain why [UINib nibWithNibName:bundle:] can improve performance? I think it just creates an UINib object that points to the Nib file. The heavy job is in [nib instantidateWithOwner:options:] which does unarchive the nib (in my opinion, this operation is much heavier) – onmyway133 Nov 15 '13 at 02:37
  • @entropy your statement contradicts the documentation. – nielsbot Nov 15 '13 at 08:09
  • @nielsbot yes, it certainly contradicts, but don't you think as I do ? People say this is expensive, that is expensive, ... without a reason :( – onmyway133 Nov 15 '13 at 08:20
  • 2
    I assume Apple knows how their code works and they didn't just write that in the document for no reason. If you are in doubt, you should profile it. – nielsbot Nov 15 '13 at 09:14
  • I can't say exactly how `UINib` improves performance, because I don't have its source code. But presumably it caches at least some of the work of parsing a nib file, like (for example) looking up classes and selectors. – rob mayoff Nov 15 '13 at 15:52
  • 1
    `UINib` caches the XML from the nib so it doesn't have to load it into memory every time. All the unarchiving happens during `instantiateWithowner:options` though, so you aren't going to see huge performance benefits using `UINib` unless the nib is so large that loading the xml takes a significant amount of time. – memmons Feb 25 '14 at 19:54
  • @memmons That is so true. Caching `UINib` instance is easy, but **insignificant** due to decoding. – eonil Apr 24 '15 at 12:51
  • Does anyone understand how UITableView does to reuse cells? How do they create a copy the cells along with all the outlets? – Fábio Oliveira Feb 25 '16 at 14:10
4

Following Rob's suggestion, you could do the following:

@implmentation InteractiveMovieView (NibFactory)

+(id)movieView
{
    static UINib * __nib ;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        __nib = [ UINib nibWithNibName:@"AudioPlayer" bundle:nil ] ;
    });

    InteractiveMovieView * view = [ __nib instantiateWithOwner:nil options:nil ][0] ;
    return view ;
}

@end
nielsbot
  • 15,922
  • 4
  • 48
  • 73
  • 3
    Nearly all the heavy lifting happens in the unarchiving of the view via `instantiateWithOwner:options`. Creating a static nib will not result in any performance gains. – memmons Feb 24 '14 at 18:50
  • If I understand the documentation @Rob quoted, one should cache the `UINib` object, no? – nielsbot Feb 25 '14 at 06:52
  • The docs are slightly confusing in their wording. It indicates that the `UINib` object is responsible for caching, not that you should cache the `UINib`. – memmons Feb 25 '14 at 19:40
  • Take a look at the docs for `instantiateWithOwner:options` in regards to where the heavy lifting happens: *Unarchives and instantiates the in-memory contents of the receiver’s nib file, creating a distinct object tree and set of top level objects.* As far as I can tell testing via instruments, using `UINib` vs `loadNibNamed` makes very little difference performance-wise. – memmons Feb 25 '14 at 19:42
  • From what I can tell it _does_ cache the data of the nib -- the XML itself. But unarchiving and instantiating in-memory contents is orders of magnitudes more expensive than loading the nib's xml. So, yes, it's certainly better to use `UINib`, but pratically it makes little difference unless perhaps you have a huge nib with multiple root objects which is larger than typical. – memmons Feb 25 '14 at 19:49