我试着做一些复杂的事情,但应该是可能的。所以这里有一个对你们所有专家的挑战(这个论坛是由你们很多人组成的:))。
我正在创建一个问卷“组件”,我想加载在一个navigationcontroller(我的QuestionManagerViewController)。“组件”是一个“空的”UIViewController,它可以根据需要回答的问题加载不同的视图。
我的做法是:
Create Question1View object as a UIView subclass, defining some IBOutlets.
Create (using Interface Builder) the Question1View.xib (HERE IS WHERE MY PROBLEM PROBABLY IS). I set both the UIViewController and the UIView to be of class Question1View.
I link the outlets with the view's component (using IB).
I override the initWithNib of my QuestionManagerViewController to look like this:
- (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:] loaded the "Question1View" nib but the view outlet was not set.'
我确信有一种方法可以使用nib文件加载视图,而不需要创建一个viewController类。
在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
}
还有一种更简单的方法来访问视图,而不是将nib作为数组处理。
1)创建一个自定义的View子类,其中包含你以后想要访问的任何出口。——MyView
2)在你想要加载和处理nib的UIViewController中,创建一个IBOutlet属性来保存加载的nib的视图
在MyViewController中(一个UIViewController子类)
@property (nonatomic, retain) IBOutlet UIView *myViewFromNib;
(别忘了合成它并在你的。m文件中发布它)
3)在IB中打开你的nib(我们称之为'myViewNib.xib'),设置你文件的所有者为MyViewController
4)现在连接你的文件的所有者出口myViewFromNib到nib的主视图。
5)现在在MyViewController中,写以下一行:
[[NSBundle mainBundle] loadNibNamed:@"myViewNib" owner:self options:nil];
当你这样做的时候,把你的财产称为“自我”。myViewFromNib”将让你从你的nib访问视图!
花了好几个小时后,我想出了以下解决办法。
按照以下步骤创建自定义UIView。
1)创建类myCustomView继承自UIView。
2)创建名称为myCustomView的.xib。
3)在你的.xib文件中改变UIView的类,在那里分配myCustomView类。
4)创建iboutlet
5)在myCustomView * customView中加载.xib。
使用下面的示例代码。
myCustomView * myView = [[[NSBundle mainBundle] loadNibNamed:@"myCustomView" owner:self options:nil] objectAtIndex:0];
[myView.description setText:@"description"];
注:对于那些仍然面临问题的人可以评论,我将提供他们的链接
示例项目的myCustomView
下面是一种在Swift中实现的方法(目前正在XCode 7 beta 5中编写Swift 2.0)。
从你在接口构建器中设置为“自定义类”的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 ()
我有理由做同样的事情(从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;
}
张贴的一般利益;如果有人发现没有这样做的问题,请告诉我。