241

我正在尝试做一些复杂的事情,但应该是可能的。所以这里对你们所有的专家来说都是一个挑战(这个论坛有很多人:))。

我正在创建一个问卷“组件”,我想将其加载到NavigationContoller(我的QuestionManagerViewController)上。“组件”是一个“空” UIViewController,可以根据需要回答的问题加载不同的视图。

我这样做的方式是:

  1. 创建 Question1View 对象作为UIView子类,定义一些IBOutlets.
  2. 创建(使用界面生成器)Question1View.xib (这里是我的问题可能在哪里)。我将 theUIViewController和 the都设置UIView为 Question1View 类。
  3. 我将插座与视图的组件链接(使用 IB)。
  4. 我覆盖initWithNibQuestionManagerViewController的看起来像这样:

    - (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”笔尖,但未设置视图出口。

我确信有一种方法可以使用 nib 文件加载视图,而无需创建 viewController 类。

4

24 回答 24

224

还有一种更简单的方法来访问视图,而不是将 nib 作为数组处理。

1 ) 创建一个自定义 View 子类,其中包含您以后想要访问的任何插座。 - 我的观点

2 ) 在你想要加载和处理笔尖的 UIViewController 中,创建一个 IBOutlet 属性来保存加载的笔尖的视图,例如

在 MyViewController (一个 UIViewController 子类)

  @property (nonatomic, retain) IBOutlet UIView *myViewFromNib;

(不要忘记合成它并在你的 .m 文件中发布它)

3)在 IB 中打开您的 nib(我们将其称为“myViewNib.xib”),将文件的所有者设置为MyViewController

4)现在将文件的 Owner outlet myViewFromNib 连接到 nib 中的主视图。

5)现在在 MyViewController 中,编写以下行:

[[NSBundle mainBundle] loadNibNamed:@"myViewNib" owner:self options:nil];

现在,只要你这样做,调用你的属性“self.myViewFromNib”就可以让你从你的笔尖访问视图!

于 2010-10-29T19:45:48.413 回答
120

谢谢你们。我确实找到了一种方法来做我想做的事。

  1. UIView用你需要的s创建你的IBOutlet
  2. 在 IB 中创建 xib,将其设计为您喜欢的并将其链接如下:文件的所有者属于类UIViewController(没有自定义子类,而是“真正的”子类)。文件所有者的视图连接到主视图,并且其类被声明为步骤 1) 中的类。
  3. 用 s 连接您的控件IBOutlet
  4. 可以运行它的DynamicViewController逻辑来决定加载什么视图/xib。一旦做出决定,在loadView方法中输入如下内容:

    NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"QPickOneView"
                                                      owner:self
                                                    options:nil];
    
    QPickOneView* myView = [ nibViews objectAtIndex: 1];
    
    myView.question = question;
    

而已!

主包的loadNibNamed方法将负责初始化视图和创建连接。

现在 ViewController 可以根据内存中的数据显示一个视图或另一个视图,并且“父”屏幕不需要打扰这个逻辑。

于 2009-05-14T22:48:00.360 回答
72

我不确定有些答案在说什么,但我需要把这个答案放在这里,以备下次在谷歌搜索时使用。关键词:“如何从 nib 加载 UIView”或“如何从 NSBundle 加载 UIView”。

这里的代码几乎 100% 直接来自 Apress开始 iPhone 3书(第 247 页,“使用新的表格视图单元格”):

- (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,一个名为 nib 的 nibBlah包含一个UIView将其类设置为 的Blah


类别:NSObject+LoadFromNib

#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")
    }
}
于 2010-07-07T01:54:42.173 回答
22

对于所有需要管理多个自定义视图实例(即Outlet Collection)的用户,我以这种方式合并并自定义了@Gonso、@AVeryDev 和@Olie 答案:

  1. 创建一个自定义MyView : UIView并将其设置为所需XIB中根的“自定义类” ; UIView自定义类

  2. 创建您需要的所有插座MyView(现在就做,因为在第 3 点之后,IB 会建议您将插座连接到UIViewController我们想要的而不是自定义视图); 自定义类插座

  3. 将您设置为自定义视图XIBUIViewController的“文件所有者” ; 在此处输入图像描述

  4. 在为您想要的每个实例UIViewController添加一个新的,并将它们连接到创建一个Outlet Collection:这些视图将充当自定义视图实例的“包装”视图; UIViewsMyViewUIViewController在此处输入图像描述

  5. 最后,在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..
于 2012-09-24T16:07:33.537 回答
19

我会使用 UINib 来实例化一个自定义 UIView 以重用

UINib *customNib = [UINib nibWithNibName:@"MyCustomView" bundle:nil];
MyCustomViewClass *customView = [[customNib instantiateWithOwner:self options:nil] objectAtIndex:0];
[self.view addSubview:customView];

在这种情况下需要的文件是MyCustomView.xibMyCustomViewClass.hMyCustomViewClass.m 注意[UINib instantiateWithOwner]返回一个数组,所以你应该使用反映你想要重用的 UIView 的元素。在这种情况下,它是第一个元素。

于 2014-02-24T15:14:03.880 回答
11

您不应该将视图控制器的类设置为UIViewInterface Builder 中的子类。这绝对是您问题的至少一部分。将其保留为UIViewController它的某个子类或您拥有的其他一些自定义类。

至于仅从 xib 加载视图,我假设您必须将某种视图控制器(即使它不扩展UIViewController,这对于您的需要可能太重)设置为接口中的文件所有者Builder 如果你想用它来定义你的界面。我也做了一些研究来证实这一点。这是因为否则将无法访问 中的任何界面元素UIView,也无法让您自己的代码中的方法由事件触发。

如果您使用 aUIViewController作为视图的文件所有者,则可以使用initWithNibName:bundle:它来加载它并取回视图控制器对象。在 IB 中,确保将view出口设置为带有 xib 界面的视图。如果您使用其他类型的对象作为文件的所有者,则需要使用NSBundle'loadNibNamed:owner:options:方法来加载 nib,将文件所有者的实例传递给该方法。它的所有属性都将根据您在 IB 中定义的网点进行正确设置。

于 2009-05-14T13:42:29.313 回答
9

你也可以使用 UIViewController 的 initWithNibName 代替 loadNibNamed。我发现它更简单。

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 的 Owner 类设置为 UIViewController,并将视图类设置为 MySubView。

subview您可以使用父 xib 文件的位置和大小。

于 2011-10-15T15:39:55.130 回答
8

这是应该更容易的事情。我最终扩展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
于 2011-08-30T00:20:00.557 回答
8

这是一个很好的问题(+1),答案几乎是有帮助的;)对不起,伙计们,但我花了很长时间来解决这个问题,尽管 Gonso 和 AVeryDev 都给出了很好的提示。希望这个答案对其他人有所帮助。

MyVC是持有所有这些东西的视图控制器。

MySubview是我们要从 xib 加载的视图

  • 在 MyVC.xib 中,创建一个MySubView大小和形状正确并放置在您想要的位置的类型视图。
  • 在 MyVC.h 中,有

    IBOutlet MySubview *mySubView
    // ...
    @property (nonatomic, retain) MySubview *mySubview;
    
  • 在 MyVC.m 中,@synthesize mySubView;不要忘记在dealloc.

  • 在 MySubview.h 中,有一个出口/属性UIView *view(可能是不必要的,但对我有用。)在 .m 中合成并发布它
  • 在 MySubview.xib 中
    • 将文件所有者类型设置为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的方法,view必须将 .xib 文件中的属性设置为MySubview。否则,它会以普通旧的UIView.

如果有办法mySubview直接从它自己的 xib 加载,那就太棒了,但这让我到达了我需要的地方。

于 2011-07-08T23:33:09.803 回答
7

迅速

实际上,我对这个问题的解决方案是,在我的 CustonViewController 中的 viewDidLoad 中加载视图,我想在其中使用这样的视图:

myAccessoryView = NSBundle.mainBundle().loadNibNamed("MyAccessoryView", owner: self, options: nil)[0] as! MyAccessoryView

不要在loadView()方法中加载视图!loadView 方法用于为您的自定义 ViewController 加载视图。

于 2016-02-05T09:42:49.463 回答
6

我也想做类似的事情,这就是我发现的:(SDK 3.1.3)

我有一个视图控制器 A(本身由导航控制器拥有),它在按下按钮时加载 VC B:

在 AViewController.m

BViewController *bController = [[BViewController alloc] initWithNibName:@"Bnib" bundle:nil];
[self.navigationController pushViewController:bController animated:YES];
[bController release];

现在 VC B 的界面来自 Bnib,但是当按下按钮时,我想进入“编辑模式”,该模式具有与不同 nib 不同的 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 个顶级 obj,即 UIView obj。这个 nib 中的 File's Owner 设置为 BViewController 还是默认的 NSObject 都没有关系,但请确保 File's Owner 中的 View Outlet 未设置为任何内容。如果是,那么我会遇到 exc_bad_access 崩溃,xcode 继续加载 6677 个堆栈帧,显示重复调用的内部 UIView 方法......所以看起来像一个无限循环。(然而,View Outlet 设置在我原来的 Bnib 中)

希望这可以帮助。

于 2010-04-21T13:14:40.570 回答
6

我做了一个我喜欢的类别:

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];

如果您的 nib 的名称不是您的班级名称,请使用 nib 名称。

要在子类中覆盖它以获得其他行为,它可能如下所示:

- (instancetype)initWithNibNamed:(NSString *)nibNameOrNil
{
    self = [super initWithNibNamed:nibNameOrNil];
    if (self) {
        self.layer.cornerRadius = CGRectGetHeight(self.bounds) / 2.0;
    }
    return self;
}
于 2014-09-24T20:31:44.380 回答
6

对于具有可设计选项的 Swift 用户:

  1. 创建一个自定义UIView子类和一个 xib 文件,我们将以自己的类名命名:在我们的例子中是 MemeView。在 Meme View 类中,请记住@IBDesignable在类声明之前使用属性将其定义为可设计
  2. Rember 使用我们UIView在 Indetity Inspector 面板中的自定义子类在 xib中设置文件的所有者

    在此处输入图像描述

  3. 现在,在 xib 文件中,我们可以构建我们的界面、制作约束、创建出口、操作等。 在此处输入图像描述

  4. 我们需要为我们的自定义类实现一些方法以在初始化后打开 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
    }
    

    }

  5. 在我们的自定义类中,我们还可以定义一些不可检查的属性,以便从界面构建器中完全控制它们

    @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!
    

}

几个例子:
在此处输入图像描述 在此处输入图像描述

如果我们需要在情节提要或另一个 xib 中显示视图时添加更多信息,为此我们可以实现prepareForInterfaceBuilder(),此方法将仅在界面构建器中打开文件时执行。如果你做了我写的所有事情但没有任何工作,这是一种通过在其实现中添加断点来调试单个视图的方法。 这是视图层次结构。 在此处输入图像描述
查看层次结构

希望这可以帮助一个完整的样本可以在这里下载

于 2016-06-18T08:00:50.373 回答
4

我发现Aaron Hillegass(作者、讲师、Cocoa ninja)的这篇博文很有启发性。即使您不采用他修改后的方法通过指定的初始化程序加载 NIB 文件,您也可能至少会更好地了解正在进行的过程。我最近一直在使用这种方法,取得了巨大的成功!

于 2010-03-25T19:33:26.173 回答
3

前面的答案没有考虑到 iPhone SDK 2.0 和 2.1 之间发生的 NIB (XIB) 结构的变化。用户内容现在从索引 0 而不是 1 开始。

您可以使用适用于所有 2.1 及更高版本的 2.1 宏(即 IPHONE 之前的两个下划线:

 // 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;

我们在大多数应用程序中使用与此类似的技术。

巴尼

于 2009-07-01T05:07:14.887 回答
3

我有理由做同样的事情(以编程方式从 XIB 文件加载视图),但我需要完全从 a 的子类的子类的上下文中执行此操作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;
}

出于一般兴趣而发布;如果有人在不这样做的情况下发现任何问题,请告诉我。

于 2011-10-25T19:33:46.953 回答
3

这是在 Swift 中执行此操作的一种方法(目前在 XCode 7 beta 5 中编写 Swift 2.0)。

从您UIView在 Interface Builder 中设置为“自定义类”的子类创建一个这样的方法(我的子类称为 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()

于 2015-08-22T12:37:58.053 回答
2

@AVeryDev

6)将加载的视图附加到视图控制器的视图:

[self.view addSubview:myViewFromNib];

据推测,有必要将其从视图中删除以避免内存泄漏。

澄清一下:视图控制器有几个 IBOutlets,其中一些连接到原始 nib 文件中的项目(像往常一样),一些连接到加载的 nib 中的项目。两个笔尖都具有相同的所有者类别。加载的视图覆盖了原始视图。

提示:将加载的笔尖中主视图的不透明度设置为零,这样就不会遮挡原始笔尖中的项目。

于 2010-11-25T07:13:48.580 回答
2

没有一个答案解释了如何创建作为这个问题根源的独立 XIB。没有Xcode 4“创建新的 XIB 文件”选项。

去做这个

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”这个词不会出现在任何地方。

于 2011-04-26T20:06:56.097 回答
1

花了很多时间后,我伪造了以下解决方案。按照以下步骤创建自定义UIView.

1) 创建从UIView继承的myCustomView类。
在此处输入图像描述

2) 创建名为myCustomView的.xib
在此处输入图像描述

3)更改.xib 文件中的UIView类,在那里分配myCustomView类。
在此处输入图像描述

4) 创建IBOutlets
在此处输入图像描述

5) 在myCustomView * customView 中加载 .xib。使用以下示例代码。

myCustomView * myView = [[[NSBundle mainBundle] loadNibNamed:@"myCustomView" owner:self options:nil] objectAtIndex:0];
[myView.description setText:@"description"];

注意:对于那些仍然遇到问题的人可以发表评论,我将提供示例项目的链接与myCustomView

于 2016-06-18T07:44:31.757 回答
1

最短版本:

RSFavoritePlaceholderView *favoritePlaceholderView = [[[NSBundle mainBundle] loadNibNamed:@"RSFavoritePlaceholderView" owner:self options:nil] firstObject];
于 2017-11-29T11:48:36.673 回答
0

我有一个命名 xibs 的约定,其中的视图与视图相同。就像对视图控制器所做的一样。然后,我不必在代码中写出类名。我从同名的 nib 文件加载 UIView。

名为 MyView 的类的示例。

  • 在 Interface Builder 中创建一个名为 MyView.xib 的 nib 文件
  • 在 Interface Builder 中,添加一个 UIView。将其类设置为 MyView。自定义您的心脏内容,将 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 {

}

然后,我将按钮与我正在使用的控制器的操作连接起来,并使用我的自定义视图子类中的插座在标签上设置内容。

于 2013-12-09T04:27:07.210 回答
0

在 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
}
于 2018-01-05T08:04:49.283 回答
-1

我最终为此向 UIView 添加了一个类别:

 #import "UIViewNibLoading.h"

 @implementation UIView (UIViewNibLoading)

 + (id) loadNibNamed:(NSString *) nibName {
    return [UIView loadNibNamed:nibName fromBundle:[NSBundle mainBundle] retainingObjectWithTag:1];
 }

 + (id) loadNibNamed:(NSString *) nibName fromBundle:(NSBundle *) bundle retainingObjectWithTag:(NSUInteger) tag {
    NSArray * nib = [bundle loadNibNamed:nibName owner:nil options:nil];
    if(!nib) return nil;
    UIView * target = nil;
    for(UIView * view in nib) {
        if(view.tag == tag) {
            target = [view retain];
            break;
        }
    }
    if(target && [target respondsToSelector:@selector(viewDidLoad)]) {
        [target performSelector:@selector(viewDidLoad)];
    }
    return [target autorelease];
 }

 @end

此处解释:viewcontroller is less view loading in ios&mac

于 2013-03-19T06:21:11.657 回答