私は少し手の込んだことをやろうとしていますが、それは可能であるべきです。だからここにあなたのすべての専門家のための挑戦があります(このフォーラムはたくさんの皆さんのパックです:)。
NavigationContoller
(私のQuestionManagerViewController
)にロードしたいアンケート「コンポーネント」を作成しています。 "component"は "empty" UIViewController
です。これは、回答が必要な質問に応じて異なるビューをロードできます。
私がやっている方法は次のとおりです。
UIView
サブクラスとして作成し、いくつかのIBOutlets
を定義します。Question1View.xib
(HERE IS WHERE MY PROBLEM PROBABLY IS)を作成します。 UIViewController
とUIView
の両方をQuestion1Viewクラスに設定しました。私はinitWithNib
のQuestionManagerViewController
を次のように上書きします。
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:@"Question1View" bundle:nibBundleOrNil]) {
// Custom initialization
}
return self;
}
コードを実行すると、このエラーが発生します。
2009-05-14 15:05:37.152 iMobiDines [17148:20b] ***キャッチされていない例外 '
NSInternalInconsistencyException
'のためアプリケーションを終了しました、理由: '-[UIViewController _loadViewFromNibNamed:bundle:]
は "Question1View"ペン先をロードしましたがビューアウトレットが設定されませんでした。
ViewControllerクラスを作成しなくても、nibファイルを使用してビューをロードする方法があるはずです。
ペン先を配列として扱うのではなく、ビューにアクセスするより簡単な方法もあります。
1)後でアクセスしたいアウトレットを持つカスタムViewサブクラスを作成します。 - 私の見解
2)あなたがペン先をロードして処理したいUIViewControllerで、ロードされたペン先のビューを保持するIBOutletプロパティを作成します、例えば
myViewController(UIViewControllerサブクラス)内
@property (nonatomic, retain) IBOutlet UIView *myViewFromNib;
(それを合成してあなたの.mファイルに入れるのを忘れないでください)
)あなたのペン先(IBYで 'myViewNib.xib'と呼びます)を開き、ファイルの所有者をに設定しますMyViewController
4)これであなたのファイルの所有者アウトレットmyViewFromNibをペン先のメインビューに接続します。
5) MyViewControllerで、次の行を書きます。
[[NSBundle mainBundle] loadNibNamed:@"myViewNib" owner:self options:nil];
あなたがそうするようになったらすぐに、あなたのプロパティ "self.myViewFromNib"を呼び出すことはあなたのnibからビューへのアクセスをあなたに与えるでしょう!
皆さん、ありがとうございました。やりたいことをやる方法を見つけました。
UIView
を使ってIBOutlet
を作成します。UIViewController
です(カスタムサブクラスはありませんが、実際のもの)。ファイル所有者のビューはメインビューに接続されており、そのクラスは手順1)のクラスとして宣言されています。IBOutlet
sで接続します。DynamicViewController
はそのロジックを実行して、どのview/xibをロードするかを決定できます。決定したら、loadView
メソッドで次のように入力します。
NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"QPickOneView"
owner:self
options:nil];
QPickOneView* myView = [ nibViews objectAtIndex: 1];
myView.question = question;
それでおしまい!
メインバンドルのloadNibNamed
メソッドは、ビューの初期化と接続の作成を行います。
これで、ViewControllerはメモリ内のデータに応じてビューなどを表示できるようになり、「親」画面はこのロジックに煩わされる必要がなくなります。
いくつかの答えが何を言っているのかよくわかりませんが、次回Googleで検索するときには、この答えをここに含める必要があります。キーワード:「ペン先からUIViewを読み込む方法」または「NSBundleからUIViewを読み込む方法」
これは、ApressiPhone 3のはじめの本(247ページ、「新しいTable View Cellの使用」)からほぼ100%引用したコードです。
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:@"Blah"
owner:self options:nil];
Blah *blah;
for (id object in bundle) {
if ([object isKindOfClass:[Blah class]]) {
blah = (Blah *)object;
break;
}
}
assert(blah != nil && "blah can't be nil");
[self.view addSubview: blah];
}
これはUIView
と呼ばれるBlah
サブクラス、クラスがBlah
に設定されたUIView
を含むBlah
と呼ばれるペン先があると仮定します。
#import "NSObject+LoadFromNib.h"
@implementation NSObject (LoadFromNib)
+ (id)loadFromNib:(NSString *)name classToLoad:(Class)classToLoad {
NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:name owner:self options:nil];
for (id object in bundle) {
if ([object isKindOfClass:classToLoad]) {
return object;
}
}
return nil;
}
@end
extension UIView {
class func loadFromNib<T>(withName nibName: String) -> T? {
let nib = UINib.init(nibName: nibName, bundle: nil)
let nibObjects = nib.instantiate(withOwner: nil, options: nil)
for object in nibObjects {
if let result = object as? T {
return result
}
}
return nil
}
}
そして使用中の例:
class SomeView: UIView {
class func loadFromNib() -> SomeView? {
return self.loadFromNib(withName: "SomeView")
}
}
カスタムビューの複数のインスタンス、つまりOutlet Collectionを管理する必要がある人のために、@ Gonso、@ AVeryDev、および@Olieの回答を次のようにマージしてカスタマイズしました。
カスタムのMyView : UIView
を作成し、それを必要なXIBのルートUIView
の "Custom Class"に設定します。
すべてを作成するアウトレットMyView
に必要なもの(ポイント3以降、IBはアウトレットをUIViewController
に接続し、カスタムビューには接続しないように提案します)。
UIViewController
をカスタムビューの "File's Owner"に設定してくださいXIB;
UIViewController
に、必要なUIViews
のインスタンスごとに新しいMyView
を追加し、それらをUIViewController
に接続して、Outlet Collectionを作成します。これらのビューは、カスタムビューインスタンスの "ラッパー"ビューとして機能します。
最後に、viewDidLoad
のUIViewController
に以下の行を追加します。
NSArray *bundleObjects; MyView *currView; NSMutableArray *myViews = [NSMutableArray arrayWithCapacity:myWrapperViews.count]; for (UIView *currWrapperView in myWrapperViews) { bundleObjects = [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil]; for (id object in bundleObjects) { if ([object isKindOfClass:[MyView class]]){ currView = (MyView *)object; break; } } [currView.myLabel setText:@"myText"]; [currView.myButton setTitle:@"myTitle" forState:UIControlStateNormal]; //... [currWrapperView addSubview:currView]; [myViews addObject:currView]; } //self.myViews = myViews; if need to access them later..
私はUINibを使ってカスタムUIViewをインスタンス化して再利用する
UINib *customNib = [UINib nibWithNibName:@"MyCustomView" bundle:nil];
MyCustomViewClass *customView = [[customNib instantiateWithOwner:self options:nil] objectAtIndex:0];
[self.view addSubview:customView];
この場合に必要なファイルは、MyCustomView.xib、MyCustomViewClass.hおよびMyCustomViewClass.mです。[UINib instantiateWithOwner]
は配列を返すので、次のようにしてください。再利用したいUIViewを反映する要素。この場合、それが最初の要素です。
Interface Builderでは、View ControllerのクラスをUIView
のサブクラスに設定しないでください。それは間違いなく少なくともあなたの問題の一部です。それをUIViewController
、そのサブクラス、または他のカスタムクラスのいずれかとして残します。
Xibからのビューのみをロードすることに関しては、私はあなたが持っている何らかのビューコントローラを持っていると仮定していました(たとえUIViewController
を拡張しなくても)。あなたがあなたのインタフェースを定義するためにそれを使用したい場合は、Interface Builderでファイルの所有者として設定します。私もこれを確認するために少し調査しました。これは、そうでなければUIView
内のインターフェース要素にアクセスする方法がなく、またコード内の独自のメソッドをイベントによってトリガーする方法もないためです。
ビューのファイル所有者としてUIViewController
を使用する場合は、initWithNibName:bundle:
を使用してビューをロードし、View Controllerオブジェクトを元に戻すことができます。 IBでは、xibのインターフェースでview
アウトレットをビューに設定してください。 File's Ownerとして他の種類のオブジェクトを使用する場合は、NSBundle
のloadNibNamed:owner:options:
メソッドを使用してnibをロードし、File's Ownerのインスタンスをそのメソッドに渡す必要があります。そのすべてのプロパティは、IBで定義したコンセントに従って正しく設定されます。
LoadNibNamedの代わりにUIViewControllerのinitWithNibNameを使用することもできます。もっと簡単ですね。
UIViewController *aViewController = [[UIViewController alloc] initWithNibName:@"MySubView" bundle:nil];
[self.subview addSubview:aViewController.view];
[aViewController release]; // release the VC
これで、MySubView.xibとMySubView.h/mを作成するだけです。 MySubView.xibで、File's OwnerクラスをUIViewControllerに、ビュークラスをMySubViewに設定します。
subview
の位置とサイズは、親のxibファイルを使用して指定できます。
これはもっと簡単なはずです。私はUIViewController
を拡張してloadNib:inPlaceholder:
セレクタを追加することになりました。今私は言うことができます
self.mySubview = (MyView *)[self loadNib:@"MyView" inPlaceholder:mySubview];
これがカテゴリのコードです(Gonsoが説明したのと同じrigamaroleを行います)。
@interface UIViewController (nibSubviews)
- (UIView *)viewFromNib:(NSString *)nibName;
- (UIView *)loadNib:(NSString *)nibName inPlaceholder:(UIView *)placeholder;
@end
@implementation UIViewController (nibSubviews)
- (UIView *)viewFromNib:(NSString *)nibName
{
NSArray *xib = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil];
for (id view in xib) { // have to iterate; index varies
if ([view isKindOfClass:[UIView class]]) return view;
}
return nil;
}
- (UIView *)loadNib:(NSString *)nibName inPlaceholder:(UIView *)placeholder
{
UIView *nibView = [self viewFromNib:nibName];
[nibView setFrame:placeholder.frame];
[self.view insertSubview:nibView aboveSubview:placeholder];
[placeholder removeFromSuperview];
return nibView;
}
@end
これは素晴らしい質問(+1)で、答えはほぼ参考になりました。)すみませんが、これに目をくぐることができました。うまくいけば、この答えは他の人を助けるでしょう。
MyVC
は、これらすべてを保持するView Controllerです。
MySubview
は、xibからロードしたいビューです。
MySubView
のビューを作成します。MyVC.hでは、
IBOutlet MySubview *mySubView
// ...
@property (nonatomic, retain) MySubview *mySubview;
MyVC.mでは@synthesize mySubView;
とdealloc
でリリースすることを忘れないでください。
UIView *view
のアウトレット/プロパティを持っています(必要ではないかもしれませんが、私のために働きました)。MySubview
に設定し、ビュープロパティを自分のビューにリンクします。IBOutlet
に接続します。MyVC.mに戻って、
NSArray *xibviews = [[NSBundle mainBundle] loadNibNamed: @"MySubview" owner: mySubview options: NULL];
MySubview *msView = [xibviews objectAtIndex: 0];
msView.frame = mySubview.frame;
UIView *oldView = mySubview;
// Too simple: [self.view insertSubview: msView aboveSubview: mySubview];
[[mySubview superview] insertSubview: msView aboveSubview: mySubview]; // allows nesting
self.mySubview = msView;
[oldCBView removeFromSuperview];
他の答えのヒントは私の見解をxibからロードしたが、MyVCの見解を置き換えなかった(当たり前) - 私は自分でそれを交換しなければならなかった。
また、mySubview
のメソッドにアクセスするには、.xibファイルのview
プロパティをMySubview
に設定する必要があります。それ以外の場合は、普通のUIView
として返されます。
それ自身のxibから直接mySubview
をロードする方法があるなら、それはロックです、しかし、これは私がする必要があるところに私を得ました。
私も似たようなことをしたい、これが私が見つけたものです:(SDK 3.1.3)
ボタンを押すとVC BをロードするView Controller A(それ自体はNavコントローラが所有)を持っています。
AViewController.mに
BViewController *bController = [[BViewController alloc] initWithNibName:@"Bnib" bundle:nil];
[self.navigationController pushViewController:bController animated:YES];
[bController release];
VC BはBnibのインターフェースを持っていますが、ボタンが押されたときに別のペン先とは別のUIを持つ「編集モード」に入りたいのですが、新しいものは使いたくありません。 VC編集モードの場合、新しいペン先を既存のB VCに関連付ける必要があります。
だから、BViewController.mで(ボタンを押す方法で)
NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:@"EditMode" owner:self options:nil];
UIView *theEditView = [nibObjects objectAtIndex:0];
self.editView = theEditView;
[self.view addSubview:theEditView];
次に別のボタンを押します(編集モードを終了するため)。
[editView removeFromSuperview];
そして元のBnibに戻ります。
これは問題なく動作しますが、私のEditMode.nibにはトップレベルオブジェクトが1つしかないことに注意してください(UIViewオブジェクト)。このペン先のファイルの所有者がBViewControllerとして設定されているか、デフォルトのNSObjectとして設定されているかは関係ありません。もしそうであれば、exc_bad_accessがクラッシュし、xcodeは6677スタックフレームをロードします。これは、内部UIViewメソッドが繰り返し呼び出されることを示しています...無限ループのように見えます。 (ビューアウトレットISただし、私のオリジナルのBnibに設定)
お役に立てれば。
Swiftでは
実際、この問題に対する私の解決策は、CustonViewControllerのviewDidLoadにビューをロードして、そのようなビューを使用することでした。
myAccessoryView = NSBundle.mainBundle().loadNibNamed("MyAccessoryView", owner: self, options: nil)[0] as! MyAccessoryView
loadView()
メソッドでビューをロードしないでください。 loadViewメソッドは、カスタムViewControllerのビューをロードするのに役立ちます。
私は好きなカテゴリーを作りました:
UIView+NibInitializer.h
#import <UIKit/UIKit.h>
@interface UIView (NibInitializer)
- (instancetype)initWithNibNamed:(NSString *)nibNameOrNil;
@end
UIView+NibInitializer.m
#import "UIView+NibInitializer.h"
@implementation UIView (NibInitializer)
- (instancetype)initWithNibNamed:(NSString *)nibNameOrNil
{
if (!nibNameOrNil) {
nibNameOrNil = NSStringFromClass([self class]);
}
NSArray *viewsInNib = [[NSBundle mainBundle] loadNibNamed:nibNameOrNil
owner:self
options:nil];
for (id view in viewsInNib) {
if ([view isKindOfClass:[self class]]) {
self = view;
break;
}
}
return self;
}
@end
それから、次のように呼び出します。
MyCustomView *myCustomView = [[MyCustomView alloc] initWithNibNamed:nil];
あなたのペン先の名前があなたのクラスの名前以外のものである場合は、ペン先名を使用してください。
追加の動作のためにあなたのサブクラスでそれをオーバーライドするために、それはこのように見えるかもしれません:
- (instancetype)initWithNibNamed:(NSString *)nibNameOrNil
{
self = [super initWithNibNamed:nibNameOrNil];
if (self) {
self.layer.cornerRadius = CGRectGetHeight(self.bounds) / 2.0;
}
return self;
}
設計可能なオプションを持つSwiftユーザーの場合:
UIView
サブクラスとxibファイルを作成します。これは、私たちの場合はMemeViewです。 Meme Viewクラス内では、クラス宣言の前に@IBDesignable
属性で設計可能として定義することを忘れないでください。インデントインスペクタパネルのカスタムUIView
サブクラスを使用して、xibのファイルの所有者を設定することを忘れないでください
初期化されたxibを開くためにカスタムクラスにいくつかのメソッドを実装する必要があります。
class XibbedView: UIView {
weak var nibView: UIView!
override convenience init(frame: CGRect) {
let nibName = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
self.init(nibName: nibName)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let nibName = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
let nib = loadNib(nibName)
nib.frame = bounds
nib.translatesAutoresizingMaskIntoConstraints = false
addSubview(nib)
nibView = nib
setUpConstraints()
}
init(nibName: String) {
super.init(frame: CGRectZero)
let nibName = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
let nib = loadNib(nibName)
nib.frame = bounds
nib.translatesAutoresizingMaskIntoConstraints = false
addSubview(nib)
nibView = nib
setUpConstraints()
}
func setUpConstraints() {
["V","H"].forEach { (quote) -> () in
let format = String(format:"\(quote):|[nibView]|")
addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(format, options: [], metrics: nil, views: ["nibView" : nibView]))
}
}
func loadNib(name: String) -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: name, bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
}
私たちのカスタムクラスでは、インターフェイスビルダーからそれらを完全に制御するためにいくつかの不可解なプロパティを定義することもできます。
@IBDesignable class MemeView: XibbedView {
@IBInspectable var memeImage: UIImage = UIImage() {
didSet {
imageView.image = memeImage
}
}
@IBInspectable var textColor: UIColor = UIColor.whiteColor() {
didSet {
label.textColor = textColor
}
}
@IBInspectable var text: String = "" {
didSet {
label.text = text
}
}
@IBInspectable var roundedCorners: Bool = false {
didSet {
if roundedCorners {
layer.cornerRadius = 20.0
clipsToBounds = true
}
else {
layer.cornerRadius = 0.0
clipsToBounds = false
}
}
}
@IBOutlet weak var label: UILabel!
@IBOutlet weak var imageView: UIImageView!
}
prepareForInterfaceBuilder()
を実装できるようにするために、ストーリーボードまたは別のxib内に表示されている間にビューにさらに情報を追加する必要がある場合、このメソッドはインターフェイスビルダーでファイルを開くときにのみ実行されます。私が書いたことをすべて行っても何も機能しない場合、それはその実装にブレークポイントを追加することによってシグレビューをデバッグする方法です。
これはビューの階層です。
これがサンプル全体をダウンロードできることを願っています ここ
Aaron Hillegass(作家、講師、Cocoa ninja)の このブログ投稿 は非常に啓発的なものです。指定されたイニシャライザを介してNIBファイルをロードするという彼の修正されたアプローチを採用しなくても、少なくとも進行中のプロセスについてよりよく理解するでしょう。私は最近この方法を使って大成功を収めました!
私は同じこと(XIBファイルからプログラム的にビューをロードすること)をする理由がありましたが、私はUIView
のサブクラスのサブクラスのコンテキストから(つまりビューコントローラを一切含まずに)完全にこれを行う必要がありました。これを行うために、私はこのユーティリティメソッドを作成しました:
+ (id) initWithNibName:(NSString *)nibName withSelf:(id)myself {
NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:nibName
owner:myself options:nil];
for (id object in bundle) {
if ([object isKindOfClass:[myself class]]) {
return object;
}
}
return nil;
}
それから、サブクラスのinitWithFrame
メソッドから次のように呼び出します。
- (id)initWithFrame:(CGRect)frame {
self = [Utilities initWithNibName:@"XIB1" withSelf:self];
if (self) {
// Initialization code.
}
return self;
}
一般的な興味のために投稿されました。誰もがこの方法でそれをしないで何か問題を見た場合、私に知らせてください。
これはSwiftで行う方法です(現在XCode 7 Beta 5でSwift 2.0を書いています)。
Interface Builderで "Custom Class"として設定したUIView
サブクラスから、このようなメソッドを作成します(私のサブクラスはRecordingFooterViewと呼ばれます)。
class func loadFromNib() -> RecordingFooterView? {
let nib = UINib(nibName: "RecordingFooterView", bundle: nil)
let nibObjects = nib.instantiateWithOwner(nil, options: nil)
if nibObjects.count > 0 {
let topObject = nibObjects[0]
return topObject as? RecordingFooterView
}
return nil
}
それならあなたはそれをこのように呼ぶことができます:
let recordingFooterView = RecordingFooterView.loadFromNib()
前回の回答では、iPhone SDKの2.0から2.1の間に発生したNIB(XIB)構造の変更は考慮されていません。ユーザーコンテンツは、1ではなくインデックス0から始まります。
あなたはすべてのバージョン2.1以降に有効である2.1マクロを使うことができます(それはIPHONEの前に2つのアンダースコアです:
// Cited from previous example
NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"QPickOneView" owner:self options:nil];
int startIndex;
#ifdef __IPHONE_2_1
startIndex = 0;
#else
startIndex = 1;
#endif
QPickOneView* myView = [ nibViews objectAtIndex: startIndex];
myView.question = question;
私達は私達の適用のほとんどのためにこれと同じような技術を使用する。
バーニー
この質問の根底にあるスタンドアロンのXIBを作成する方法を説明する回答はありません。 "Create New XIB File"へのXcode 4
オプションはありません。
これをする
1) Choose "New File..."
2) Choose the "User Interface" category under the iOS section
3) Choose the "View" item
4) You will then be prompted to choose an iPhone or iPad format
これは単純に思えるかもしれませんが、単語 "XIB"がどこにも現れないので、それを探し回ってあなたに数分を節約することができます。
@AVeryDev
6)ロードしたビューをView Controllerのビューに添付するには、次の手順に従います。
[self.view addSubview:myViewFromNib];
おそらく、メモリリークを防ぐためにビューから削除する必要があります。
明確にするために:View ControllerにはいくつかのIBOutletがあり、そのうちのいくつかは元のnibファイル内の項目に接続されており(一部は)、読み込まれたnib内の項目に接続されています。両方のペン先は同じ所有者クラスを持っています。ロードされたビューは元のビューをオーバーレイします。
ヒント:ロードしたペン先のメインビューの不透明度をゼロに設定すると、元のペン先のアイテムが見えにくくなりません。
最短バージョン:
RSFavoritePlaceholderView *favoritePlaceholderView = [[[NSBundle mainBundle] loadNibNamed:@"RSFavoritePlaceholderView" owner:self options:nil] firstObject];
何時間もかけて、私は次の解決策を考え出しました。カスタムUIView
を作成するには、次の手順に従います。
1)UIViewから継承したクラスmyCustomViewを作成します。
3).xibファイル内のUIViewのクラスを変更し、そこにmyCustomViewクラスを割り当てます。
5)myCustomView * customViewに.xibをロードします。次のサンプルコードを使用してください。
myCustomView * myView = [[[NSBundle mainBundle] loadNibNamed:@"myCustomView" owner:self options:nil] objectAtIndex:0];
[myView.description setText:@"description"];
注:まだ問題に直面する人のためにコメントすることができ、私は彼らにmyCustomViewとサンプルプロジェクトのリンクを提供します
ビューと同じように、ビューを持つxibに名前を付けるという規則があります。 View Controllerの場合と同じです。それから、クラス名をコードで書き出す必要はありません。私は同じ名前のnibファイルからUIViewをロードします。
MyViewというクラスの例。
あなたのコードでは、このような新しいMyViewを作成してください:
MyView * myView = [MyView nib_viewFromNibWithOwner:owner];
これがこのカテゴリです。
@implementation UIView (nib)
+ (id) nib_viewFromNib {
return [self nib_viewFromNibWithOwner:nil];
}
+ (id) nib_viewFromNibWithOwner:(id)owner {
NSString *className = NSStringFromClass([self class]);
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:className owner:owner options:nil];
UIView *view = nil;
for(UIView *v in nib) {
if ([v isKindOfClass:[self class]]) {
view = v;
break;
}
}
assert(view != nil && "View for class not found in nib file");
[view nib_viewDidLoad];
return view;
}
// override this to do custom setup
-(void)nib_viewDidLoad {
}
次に、私が使用しているコントローラからのアクションとボタンを関連付け、カスタムビューサブクラスのアウトレットを使用してラベルに物事を設定します。
Swift 4でプログラム的にnib/xibからビューを読み込むには:
// Load a view from a Nib given a placeholder view subclass
// Placeholder is an instance of the view to load. Placeholder is discarded.
// If no name is provided, the Nib name is the same as the subclass type name
//
public func loadViewFromNib<T>(placeholder placeholderView: T, name givenNibName: String? = nil) -> T {
let nib = loadNib(givenNibName, placeholder: placeholderView)
return instantiateView(fromNib: nib, placeholder: placeholderView)
}
// Step 1: Returns a Nib
//
public func loadNib<T>(_ givenNibName: String? = nil, placeholder placeholderView: T) -> UINib {
//1. Load and unarchive nib file
let nibName = givenNibName ?? String(describing: type(of: placeholderView))
let nib = UINib(nibName: nibName, bundle: Bundle.main)
return nib
}
// Step 2: Instantiate a view given a nib
//
public func instantiateView<T>(fromNib nib: UINib, placeholder placeholderView: T) -> T {
//1. Get top level objects
let topLevelObjects = nib.instantiate(withOwner: placeholderView, options: nil)
//2. Have at least one top level object
guard let firstObject = topLevelObjects.first else {
fatalError("\(#function): no top level objects in nib")
}
//3. Return instantiated view, placeholderView is not used
let instantiatedView = firstObject as! T
return instantiatedView
}