我试着做一些复杂的事情,但应该是可能的。所以这里有一个对你们所有专家的挑战(这个论坛是由你们很多人组成的:))。
我正在创建一个问卷“组件”,我想加载在一个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类。
我不确定一些答案在谈论什么,但我需要把这个答案放在这里,当我下次在谷歌中搜索时。关键词:“如何从一个nib加载一个UIView”或“如何从一个NSBundle加载一个UIView”
下面的代码几乎100%直接来自Apress Beginning 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叫Blah它包含一个UIView它的类设置为Blah。
类别:+ LoadFromNib NSObject
#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")
}
}
花了好几个小时后,我想出了以下解决办法。
按照以下步骤创建自定义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
对于那些需要管理多个自定义视图实例的人,也就是Outlet Collection,我合并并定制了@Gonso, @AVeryDev和@Olie的答案:
Create a custom MyView : UIView and set it as "Custom Class" of the root UIView in the desired XIB;
Create all outlets you need in MyView (do it now because after point 3 the IB will propose you to connect outlets to the UIViewController and not to the custom view as we want);
Set your UIViewController as "File's Owner" of the custom view XIB;
In the UIViewController add a new UIViews for each instance of MyView you want, and connect them to UIViewController creating an Outlet Collection: these views will act as "wrapper" views for the custom view instances;
Finally, in the viewDidLoad of your UIViewController add the following lines:
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..