我试着做一些复杂的事情,但应该是可能的。所以这里有一个对你们所有专家的挑战(这个论坛是由你们很多人组成的:))。
我正在创建一个问卷“组件”,我想加载在一个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
}
我有一种命名xib的约定,其中的视图与视图相同。和视图控制器一样。这样,我就不必在代码中写出类名了。我从同名的nib文件中加载一个UIView。
一个名为MyView的类的例子。
创建一个名为MyView的nib文件。接口生成器中的xib
在Interface Builder中添加一个UIView。将其类设置为MyView。自定义到你的内心的内容,连接MyView的实例变量到子视图,你可能想以后访问。
在你的代码中,像这样创建一个新的MyView:
MyView * MyView = [MyView nib_viewfromnibwiowner: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 {
}
然后,我将连接按钮与我正在使用的控制器的动作,并使用自定义视图子类中的outlet在标签上设置内容。
我也想做一些类似的事情,这是我发现的:
(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,但当一个按钮被按下,我想去一个“编辑模式”有一个独立的UI从不同的nib,但我不想要一个新的VC的编辑模式,我想新的nib与我现有的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中只有一个顶级obj,一个UIView obj。
不管这个nib中的文件所有者是设置为BViewController还是默认的NSObject,但要确保文件所有者中的视图出口没有设置为任何东西。
如果是,那么我得到一个exc_bad_access崩溃,xcode继续加载6677个堆栈帧
显示一个内部UIView方法被反复调用…看起来像一个无限循环。
(视图出口是设置在我原来的Bnib然而)
希望这能有所帮助。